Как реализовать TypeAdapterFactory в Gson?

Как реализовать тип TypeAdapterFactory в Gson?

Основной метод создания - общий. Почему?

Метод регистрации registerTypeAdapterFactory() не получает тип аргумента типа. Итак, как Gson знает, какие классы обрабатываются factory?

Должен ли я реализовать один factory для нескольких классов или я могу реализовать его для многих классов?

Если я реализую один factory для нескольких классов, то что мне следует возвращать в случае аргумента типа вне домена?

Ответы

Ответ 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
        }
    }
}