43

Gson で逆シリアル化しようとしている JSON 形式のツリー オブジェクトがあります。各ノードには、その子ノードがオブジェクト タイプ Node のフィールドとして含まれます。Node はインターフェースであり、いくつかの具象クラスの実装があります。逆シリアル化プロセス中に、ノードがどのタイプに属するか事前にわからない場合、ノードを逆シリアル化するときに実装する具象クラスを Gson にどのように伝えることができますか? 各ノードには、タイプを指定するメンバー フィールドがあります。オブジェクトがシリアル化された形式のときにフィールドにアクセスし、何らかの形で型を Gson に伝える方法はありますか?

ありがとう!

4

4 に答える 4

51

s用のカスタムJsonDeserializerを追加することをお勧めします。Node

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Node.class, new NodeDeserializer())
    .create();

JsonElementデシリアライザーのメソッドでノードを表すにアクセスし、それを に変換してJsonObject、型を指定するフィールドを取得できます。Nodeその後、それに基づいて正しいタイプのインスタンスを作成できます。

于 2010-09-02T17:52:43.887 に答える
35

JSONSerializer と JSONDeserializer の両方を登録する必要があります。また、次の方法で、すべてのインターフェイスに汎用アダプターを実装できます。

  • シリアル化中 : 実際の impl クラス タイプの META-info を追加します。
  • DeSerialization 中: そのメタ情報を取得し、そのクラスの 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();
于 2012-02-02T02:29:05.107 に答える
1

私が知る限り、これは非コレクション型では機能しません。より具体的には、具象型を使用してシリアル化し、インターフェイス型を使用して逆シリアル化する状況です。つまり、インターフェイスを実装する単純なクラスがあり、具体的なクラスをシリアル化してから、逆シリアル化するインターフェイスを指定すると、回復不能な状況に陥ります。

上記の例では、型アダプターはインターフェイスに対して登録されていますが、具体的なクラスを使用してシリアル化する場合は使用されません。つまり、CLASS_META_KEY データが設定されることはありません。

アダプターを階層アダプターとして指定すると (それにより、gson に階層内のすべての型にそれを使用するように指示します)、シリアライザーが自分自身を呼び出し続けるため、無限ループに陥ります。

インターフェイスの具体的な実装からシリアル化してから、インターフェイスと InstanceCreator のみを使用して逆シリアル化する方法を知っている人はいますか?

デフォルトでは、gson は具体的なインスタンスを作成するように見えますが、そのフィールドは設定しません。

問題はここに記録されます:

http://code.google.com/p/google-gson/issues/detail?id=411&q=インターフェース

于 2012-02-21T02:49:51.097 に答える
0

TypeTokenGoogle Gson のクラスを使用する必要があります。もちろん、それを機能させるにはジェネリッククラス T が必要です

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();

gson.toJson(foo, fooType);

gson.fromJson(json, fooType);
于 2013-02-22T09:16:59.660 に答える