Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Adapter Layering Feature #1471

Closed
wants to merge 12 commits into from
Closed

Conversation

paulkass
Copy link
Contributor

@paulkass paulkass commented Feb 19, 2019

Why this is useful: Suppose you have a class with a lot of fields. Most of them can be easily interpreted by the Gson reader, possibly with a field naming strategy. But some have such weird names that the field naming strategy might not necessarily properly match them to the target properties. Especially if the JSON comes from a third party (like an API), the best course of action as of today is to create your own TypeAdapter and manually map all of the fields, including the ones that GSON could map on it's own. This is why I added the "Fill-In" feature. The registerTypeAdapterWithFillIn method allows you to manually define only the fields that Gson can not map properly, while not having to map trivial mappings.

Implementation Details: The way to register a custom adapter with Fill-in is through the GsonBuilder#registerTypeAdapterWithFillIn method. This method wraps the adapter into a constructor object that is then passed to an instance of the ReflectiveTypeAdapterFactory.Adapter class. In other words, when the read method is called on a ReflectiveTypeAdapterFactory.Adapter instance, the ObjectContstructor object calls the custom adapter and generates an instance of the target class whose fields are written to or overwritten (see the Conditions section).

When calling the create method on the ReflectiveTypeAdapterFactory responsible for producing a fill-in adapter, it will only return the adapter when the target type is or is a subclass of the desired target class. This is unlike the usual ReflectiveTypeAdapterFactory instances which serve to create a catch-all type adapter for non-standard classes.

In order to support the construction of instances while reading from the input JsonReader, the InstanceCreator and ObjectConstructor have methods that accept a JsonReader object. If not overridden by the implementation, they default to the normal construct method (for backwards compatibility).

I wrote some tests in the test/.../gson/internal/bind/LayeredAdapterTest.java class to demonstrate and test some common use cases that I thought of for this feature.

Notes:

  • The outside adapter field will overwrite any field values previously written to in the instance returned by the user-defined Adapter. To avoid this, add the @Expose annotation to the fields that you want to be protected from overwriting.
  • Due to the use of default methods in interfaces, this only supports java versions of 8+, and will fail the travis-ci check. I would really appreciate if someone pointed out a way to achieve the same thing in a backwards-compatible way without relying on Java 8 features. Also, if there is going to be a multi-release jar as suggested in java.lang.NumberFormatException: For input string: "11-ea" #1469, this can go in the java 8+ jar.

@paulkass
Copy link
Contributor Author

Java 6 compatibility fixed in #1473

@paulkass paulkass closed this Feb 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants