How do I implement type TypeAdapterFactory in Gson?
The main method of create is generic. Why?
The registration method registerTypeAdapterFactory() does not receive type a type argument. So, how does Gson
know which classes are processed by the factory?
Should I implement one factory for multiple classes, or can I implement one for many classes?
If I implement one factory for multiple classes, then what should I return in case of out-of-domain type argument?
To use a custom type adapter with Gson, you must register it with a GsonBuilder : GsonBuilder builder = new GsonBuilder(); builder. registerTypeAdapter(Point. class, new PointAdapter()); // if PointAdapter didn't check for nulls in its read/write methods, you should instead use // builder.
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object.
Gson can work with arbitrary Java objects including objects for which you do not have the source. For this purpose, Gson provides several built in serializers and deserializers. A serializer allows to convert a Json string to corresponding Java type. A deserializers allows to convert from Java to a JSON representation.
When you register a regular type adapter (GsonBuilder.registerTypeAdapter
), it only generates a type adapter for THAT specific class. For example:
public abstract class Animal { abstract void speak(); } public class Dog extends Animal { private final String speech = "woof"; public void speak() { System.out.println(speech); } } // in some gson related method gsonBuilder.registerTypeAdapter(Animal.class, myTypeAdapterObject); Gson g = gsonBuilder.create(); Dog dog = new Dog(); System.out.println(g.toJson(dog));
If you did this, then Gson
will not use your myTypeAdapterObject
, it will use the default type adapter for Object
.
So, how can you make a type adapter object that can convert ANY Animal
subclass to Json? Create a TypeAdapterFactory
! The factory can match using the generic type and the TypeToken
class. You should return null if your TypeAdapterFactory
doesn't know how to handle an object of that type.
The other thing TypeAdapterFactory
can be used for is that you can't CHAIN adapters any other way. By default, Gson doesn't pass your Gson
instance into the read
or write
methods of TypeAdapter
. So if you have an object like:
public class MyOuterClass { private MyInnerClass inner; }
There is no way to write your TypeAdapter<MyOuterClass>
that knows how to use your TypeAdapter<MyInnerClass>
without using the TypeAdapterFactory
. The TypeAdapterFactory.create
method DOES pass the Gson
instance, which allows you to teach your TypeAdapter<MyOuterClass>
how to serialize the MyInnerClass
field.
Generally, here is a good standard way to begin to write an implementation of a TypeAdapterFactory
:
public enum FooAdapterFactory implements TypeAdapterFactory { INSTANCE; // Josh Bloch's Enum singleton pattern @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { if (!Foo.class.isAssignableFrom(type.getRawType())) return null; // Note: You have access to the `gson` object here; you can access other deserializers using gson.getAdapter and pass them into your constructor return (TypeAdapter<T>) new FooAdapter(); } private static class FooAdapter extends TypeAdapter<Foo> { @Override public void write(JsonWriter out, Foo value) { // your code } @Override public Foo read(JsonReader in) throws IOException { // your code } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With