Gsonでtype TypeAdapterFactory を実装するにはどうすればよいですか?
作成の主な方法は汎用です。どうして?
登録メソッド registerTypeAdapterFactory() はタイプ引数を受け取りません。では、Gson
はどのクラスがファクトリによって処理されているかをどのようにして知るのでしょうか。
複数のクラスに1つのファクトリを実装する必要がありますか、それとも多くのクラスに1つ実装できますか?
複数のクラスに1つのファクトリを実装する場合、ドメイン外の型の引数の場合、何を返す必要がありますか?
通常の型アダプター(GsonBuilder.registerTypeAdapter
)を登録すると、その特定のクラスの型アダプターのみが生成されます。例えば:
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
はnotmyTypeAdapterObject
を使用し、Object
のデフォルトのタイプアダプターを使用します。
それでは、ANY Animal
サブクラスをJsonに変換できるタイプアダプターオブジェクトを作成するにはどうすればよいでしょうか。 TypeAdapterFactory
!ファクトリは、ジェネリック型とTypeToken
クラスを使用して一致させることができます。 TypeAdapterFactory
がそのタイプのオブジェクトの処理方法を知らない場合は、nullを返す必要があります。
TypeAdapterFactory
を使用できるもう1つのことは、アダプターを他の方法でチェーン接続できないことです。デフォルトでは、GsonはGson
インスタンスをread
のwrite
またはTypeAdapter
メソッドに渡しません。したがって、次のようなオブジェクトがある場合:
public class MyOuterClass {
private MyInnerClass inner;
}
TypeAdapterFactory
を使わずにTypeAdapter<MyOuterClass>
の使い方を知っているTypeAdapter<MyInnerClass>
を書く方法はありません。 TypeAdapterFactory.create
メソッドはGson
インスタンスを渡します。これにより、TypeAdapter<MyOuterClass>
にMyInnerClass
フィールドをシリアル化する方法を教えることができます。
一般的に、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
}
}
}