Несколько GSON @SerializedName на поле?

105

Есть ли способ в 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
Вот простое и идеальное объяснение futurestud.io/tutorials/…
Атул Бхардвадж

Ответы:

242

В октябре 2015 года в Gson версии 2.4 ( журнал изменений ) добавлена ​​возможность использования альтернативных / нескольких имен @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/…
Атул Бхардвадж
Удивительный! Спасибо за такой ответ!
sunlover3
27

Не поддерживается определение нескольких @SerializedNameаннотаций к полю в Gson.

Причина: по умолчанию десериализация управляется с помощью LinkedHashMap, а ключи определяются именами входящих полей json (а не именами полей настраиваемого класса или сериализованными именами), и существует сопоставление один к одному. Вы можете увидеть реализацию (каким образом десериализации работы) на ReflectiveTypeAdapterFactoryвнутренний класс класса Adapter<T>«s read(JsonReader in)метод.

Решение: Вы можете написать собственный TypeAdapter , который обрабатывает name, personи userJSon теги и отображает их на поле имени пользовательского класса 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
Возвращает: альтернативные имена поля при десериализации.
По умолчанию: {}

Деврим
источник
Вот простое и идеальное объяснение futurestud.io/tutorials/…
Атул Бхардвадж
20

для фанатов Котлина

@SerializedName(value="name", alternate= ["person", "user"])
Мостафа Антер
источник
8

Для КОТЛИНА я использовал ниже, но не работает

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

поэтому я отредактировал его, и здесь он отлично работает !!

@SerializedName(value="name", alternate= arrayOf("person", "user"))
андроид
источник