GSONの抽象クラスの脱毛
-
26-09-2019 - |
質問
私はjson形式のツリーオブジェクトを持っています。GSONで脱色しようとしています。各ノードには、オブジェクトタイプノードのフィールドとして子ノードが含まれています。ノードはインターフェイスであり、いくつかの具体的なクラスの実装があります。脱派化プロセス中に、ノードを脱出するときにどのコンクリートクラスを実装するかをGSONに通信するにはどうすればよいですか。各ノードには、タイプを指定するメンバーフィールドがあります。オブジェクトがシリアル化された形式であるときにフィールドにアクセスし、何らかの形でタイプをGSONに通信する方法はありますか?
ありがとう!
解決
カスタムを追加することをお勧めします jsondeserializer 為に Node
S:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Node.class, new NodeDeserializer())
.create();
アクセスできます JsonElement
Deserializerの方法のノードを表す、それをに変換します JsonObject
, 、タイプを指定するフィールドを取得します。その後、正しいタイプのインスタンスを作成できます Node
それに基づいて。
他のヒント
JsonserializerとJsondeserializerの両方を登録する必要があります。また、次の方法で、すべてのインターフェイスに一般的なアダプターを実装できます。
- シリアル化中:実際のインプルクラスタイプのメタINFOを追加します。
- 攻撃中:そのメタ情報を取得し、そのクラスのJSondeserailizeに電話してください
これが私が自分自身に使用し、うまく機能した実装です。
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();
私が知る限り、これは非収集タイプ、またはより具体的には、具体的なタイプをシリアル化するために使用し、インターフェイスタイプを使用して脱色に使用される状況では機能しません。つまり、インターフェイスを実装する単純なクラスがあり、コンクリートクラスをシリアル化してから、インターフェイスを指定してDeserializeを指定すると、回収できない状況になります。
上記の例では、タイプアダプターはインターフェイスに対して登録されていますが、コンクリートクラスを使用してシリアル化すると使用されません。つまり、class_meta_keyデータは決して設定されません。
アダプターを階層アダプターとして指定すると(GSONに階層内のすべてのタイプに使用するように指示する)、シリアイザーが自分自身を呼び出し続けるので、無限のループになります。
インターフェイスの具体的な実装からシリアル化する方法を知っている人は、インターフェイスとInstanceCreatorのみを使用してDaserializeを化する方法を知っていますか?
デフォルトでは、GSONはコンクリートインスタンスを作成するように思われますが、フィールドを設定しません。
問題はここに記録されています:
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
使用する必要があります TypeToken
Google GSONのクラス。もちろん、それを機能させるために一般的なクラスTが必要です
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.tojson(foo、footype);
gson.fromJson(json, fooType);