[java] 필드 당 여러 GSON @SerializedName?

Gson에서 여러 JSON 필드를 단일 Java 개체 멤버 변수에 매핑하는 방법이 있습니까?

Java 클래스가 있다고 가정 해 보겠습니다.

public class MyClass {
    String id;
    String name;
}

이 단일 클래스를 두 개의 다른 서비스와 함께 사용하고 싶습니다. 그러나이 두 서비스는 데이터를 반환하는 방식이 다릅니다.

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

… 그리고 …

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

… 각각.

JSON 문자열 의 "person""user"필드를 nameJava 개체 의 필드에 매핑하는 방법이 있습니까?

(참고 : JSON 문자열에서 Java 객체로만 변환하면됩니다. 그 반대는 아닙니다.)



답변

2015 년 10 월, Gson 버전 2.4 ( changelog )는 @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


답변

@SerializedNameGson의 필드에 여러 주석을 정의하는 것은 지원되지 않습니다 .

이유 : 기본적으로 Deserialization은 LinkedHashMap으로 관리되며 키는 들어오는 json의 필드 이름 (사용자 정의 클래스의 필드 이름 또는 serializedNames가 아님)으로 정의되며 일대일 매핑이 있습니다. 당신은 구현 (방법 직렬화 작품) 볼 수있는 ReflectiveTypeAdapterFactory클래스의 내부 클래스 Adapter<T>read(JsonReader in)방법을.

해결 방법 :
사용자 지정 쓸 수 TypeAdapter 있는 핸들 name, personuserJSON 태그 및 사용자 정의 클래스의 이름 필드에 매핑 MyClass:

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
반환
값 : 역 직렬화 될 때 필드의 대체 이름 기본값 : {}


답변

Kotlin 팬을 위한

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


답변

KOTLIN의 경우 아래에서 사용했지만 작동하지 않습니다.

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

그래서 나는 그것을 편집하고 여기에서 잘 작동합니다!

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


답변