Gsonで逆シリアル化しようとしているJSON形式のツリーオブジェクトがあります。各ノードには、オブジェクトタイプNodeのフィールドとして子ノードが含まれます。 Nodeは、いくつかの具象クラス実装を持つインターフェースです。逆シリアル化プロセス中に、ノードを逆シリアル化するときに実装する具体的なクラスをGsonにどのように通信できますか?ノードが属しているタイプ?各Nodeには、タイプを指定するメンバーフィールドがあります。オブジェクトがシリアル化された形式のときにフィールドにアクセスし、何らかの方法でタイプをGsonに通知する方法はありますか?
ありがとう!
Node
sにカスタム JsonDeserializer を追加することをお勧めします。
Gson gson = new GsonBuilder()
.registerTypeAdapter(Node.class, new NodeDeserializer())
.create();
デシリアライザのメソッドでノードを表すJsonElement
にアクセスし、それをJsonObject
に変換して、タイプを指定するフィールドを取得できます。その後、それに基づいて正しいタイプのNode
のインスタンスを作成できます。
JSONSerializerとJSONDeserializerの両方を登録する必要があります。また、次の方法ですべてのインターフェースに汎用アダプターを実装できます。
これは私が自分で使用した実装で、正常に動作します。
public class PropertyBasedInterfaceMarshal implements
JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_META_KEY = "CLASS_META_KEY";
@Override
public Object deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
object.getClass().getCanonicalName());
return jsonEle;
}
}
次に、このアダプタをすべてのインターフェースに次のように登録できます
Gson gson = new GsonBuilder()
.registerTypeAdapter(IInterfaceOne.class,
new PropertyBasedInterfaceMarshal())
.registerTypeAdapter(IInterfaceTwo.class,
new PropertyBasedInterfaceMarshal()).create();
私の知る限り、これは非コレクション型では機能しません。具体的には、具象型がシリアル化に使用され、インターフェイス型が非シリアル化に使用される状況です。つまり、インターフェイスを実装する単純なクラスがあり、具象クラスをシリアル化してから、インターフェイスを逆シリアル化するように指定すると、回復不可能な状況になります。
上記の例では、タイプアダプターがインターフェイスに対して登録されていますが、具象クラスを使用してシリアル化する場合は使用されません。つまり、CLASS_META_KEYデータは設定されません。
アダプターを階層アダプターとして指定すると(それにより、gsonに階層内のすべてのタイプに使用するように指示します)、シリアライザーはそれ自体を呼び出し続けるため、無限ループになります。
インターフェースの具体的な実装からシリアル化し、インターフェースとInstanceCreatorのみを使用して逆シリアル化する方法を知っている人はいますか?
デフォルトでは、gsonは具象インスタンスを作成するようですが、フィールドを設定しません。
問題はここに記録されます:
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
Google GsonのTypeToken
クラスを使用する必要があります。もちろん、それを機能させるには、ジェネリッククラスTが必要です。
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo、fooType);
gson.fromJson(json, fooType);