フィールドごとに複数のGSON @SerializedName?


104

Gsonで複数のJSONフィールドを単一のJavaオブジェクトメンバー変数にマッピングする方法はありますか?

Javaクラスがあるとしましょう...

public class MyClass {
    String id;
    String name;
}

この1つのクラスを2つの異なるサービスで使用したいと思います。ただし、これらの2つのサービスは、データを返す方法が異なります...

{ "id": 2341, "person": "Bob" }

...と...

{ "id": 5382, "user": "Mary" }

...それぞれ。

JSON文字列の"person""user"フィールドの両方をnameJavaオブジェクトのフィールドにマップする方法はありますか?

(注:JSON文字列からJavaオブジェクトに変換する必要があるだけです-その逆はありません。)


1
ここではシンプルかつ完璧な説明です futurestud.io/tutorials/...は
アトゥールBhardwaj

回答:


238

2015年10月、Gsonバージョン2.4changelog)は@SerializedName、逆シリアル化時に代替/複数の名前を使用する機能を追加しました。カスタムTypeAdapterはもう必要ありません。

使用法:

@SerializedName(value="name", alternate={"person", "user"})

https://www.javadoc.io/doc/com.google.code.gson/gson/2.6.2/com/google/gson/annotations/SerializedName.html


1
ここではシンプルかつ完璧な説明です futurestud.io/tutorials/...は
アトゥールBhardwaj

すごい!この回答ありがとうございます!
sunlover3

すばらしい回答、ありがとう!
Dor Rud

27

@SerializedNameGsonでフィールドに複数の注釈を定義することはサポートされていません。

理由: デフォルトでは、逆シリアル化はLinkedHashMapで管理され、キーは受信したjsonのフィールド名(カスタムクラスのフィールド名やserializedNamesではない)によって定義され、1対1のマッピングがあります。ReflectiveTypeAdapterFactoryクラスの内部クラスAdapter<T>read(JsonReader in)メソッドで実装(逆シリアル化のしくみ)を確認できます。

解決策:、およびjsonタグを処理し、それらをカスタムクラスの名前フィールドにマップする カスタムTypeAdapterを記述できます。namepersonuserMyClass

class MyClassTypeAdapter extends TypeAdapter<MyClass> {

    @Override
    public MyClass read(final JsonReader in) throws IOException {
        final MyClass myClassInstance = new MyClass();

        in.beginObject();
        while (in.hasNext()) {
            String jsonTag = in.nextName();
            if ("id".equals(jsonTag)) {
                myClassInstance.id = in.nextInt();
            } else if ("name".equals(jsonTag) 
                    || "person".equals(jsonTag)
                    || "user".equals(jsonTag)) {
                myClassInstance.name = in.nextString();
            }
        }
        in.endObject();

        return myClassInstance;
    }

    @Override
    public void write(final JsonWriter out, final MyClass myClassInstance)
            throws IOException {
        out.beginObject();
        out.name("id").value(myClassInstance.id);
        out.name("name").value(myClassInstance.name);
        out.endObject();
    }
}

テストケース:

    String jsonVal0 = "{\"id\": 5382, \"user\": \"Mary\" }";
    String jsonVal1 = "{\"id\": 2341, \"person\": \"Bob\"}";

    final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(MyClass.class, new MyClassTypeAdapter());
    final Gson gson = gsonBuilder.create();

    MyClass myClassInstance0 = gson.fromJson(jsonVal0, MyClass.class);
    MyClass myClassInstance1 = gson.fromJson(jsonVal1, MyClass.class);

    System.out.println("jsonVal0 :" + gson.toJson(myClassInstance0));
    // output: jsonVal0 :{"id":5382,"name":"Mary"}

    System.out.println("jsonVal1 :" + gson.toJson(myClassInstance1));
    // output: jsonVal1 :{"id":2341,"name":"Bob"}

TypeAdaptersの例。

編集2016.04.06: @Mathieu Castetsが彼の回答で書いたように、現在サポートされています。(これがこの質問の正しい答えです。)

public abstract String [] alternate
戻り値:逆シリアル化されたときのフィールドの代替名
デフォルト: {}


ここではシンプルかつ完璧な説明です futurestud.io/tutorials/...は
アトゥールBhardwaj


8

KOTLIN iの場合、以下で使用しますが機能しません

@SerializedName(value="name", alternate= ["person", "user"])

だから私はそれを編集し、ここでそれはうまくいきます!!

@SerializedName(value="name", alternate= arrayOf("person", "user"))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.