Несколько GSON @SerializedName для каждого поля?
Есть ли какой-либо способ в Gson сопоставить несколько полей JSON с одной переменной-членом объекта Java?
Скажем, у меня есть класс Java...
public class MyClass {
String id;
String name;
}
Я хочу использовать этот единственный класс с двумя разными службами. Однако эти две службы отличаются тем, как они возвращают свои данные...
{ "id": 2341, "person": "Bob" }
... и...
{ "id": 5382, "user": "Mary" }
... соответственно.
Есть ли способ сопоставить поля "person"
и "user"
в строке JSON в поле name
объекта Java?
(Примечание: мне нужно только преобразовать из строки JSON в объект Java - никогда наоборот.)
Ответы
Ответ 1
В октябре 2015 года версия Gson 2.4 (changelog) добавлена возможность использовать альтернативные/множественные имена для @SerializedName
, когда десериализации. Больше не нужно настраивать TypeAdapter!
Применение:
@SerializedName(value="name", alternate={"person", "user"})
https://google.github.io/gson/apidocs/com/google/gson/annotations/SerializedName.html
Ответ 2
Невозможно определить несколько аннотаций @SerializedName
для поля в Gson.
Причина:. По умолчанию десериализация управляется с помощью LinkedHashMap, а ключи определяются входящими именами json-полей (а не именами полей пользовательского класса или serializedNames), и есть одно к одному сопоставление. Вы можете увидеть реализацию (как работает десериализация) в классе ReflectiveTypeAdapterFactory
class class class Adapter<T>
read(JsonReader in)
.
Решение:
Вы можете написать TypeAdapter, который обрабатывает теги name
, person
и user
json и отображает их в поле имени вашего пользовательский класс 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 в ответ, он поддерживается сейчас. (Это правильный ответ на этот вопрос.)
публичный аннотация String [] alternate
Возвраты: альтернативные имена поле, когда оно десериализовано
По умолчанию: {}