Ответ 1
При регистрации обычного адаптера типа (GsonBuilder.registerTypeAdapter
) он генерирует только адаптер типа для определенного класса THAT. Например:
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));
Если вы это сделали, то Gson
будет не использовать ваш myTypeAdapterObject
, он будет использовать адаптер типа по умолчанию для Object
.
Итак, как вы можете создать объект адаптера типа, который может преобразовать ЛЮБОЙ подкласс Animal
в Json? Создайте TypeAdapterFactory
! factory может совпадать с общим типом и классом TypeToken
. Вы должны вернуть значение null, если ваш TypeAdapterFactory
не знает, как обращаться с объектом такого типа.
Другая вещь TypeAdapterFactory
может быть использована для того, чтобы вы не могли адаптировать CHAIN адаптеры любым другим способом. По умолчанию Gson не передает ваш экземпляр Gson
в методы read
или write
TypeAdapter
. Поэтому, если у вас есть такой объект, как:
public class MyOuterClass {
private MyInnerClass inner;
}
Невозможно написать свой TypeAdapter<MyOuterClass>
, который знает, как использовать TypeAdapter<MyInnerClass>
, не используя TypeAdapterFactory
. Метод TypeAdapterFactory.create
ПРОЧИТАЕТ экземпляр Gson
, который позволяет вам научить ваш TypeAdapter<MyOuterClass>
как сериализовать поле MyInnerClass
.
В общем, вот хороший стандартный способ начать писать реализацию TypeAdapterFactory
:
public enum FooAdapterFactory implements TypeAdapterFactory {
INSTANCE; // Josh Bloch 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
}
}
}