¿Múltiples GSON @SerializedName por campo?

104

¿Hay alguna forma en Gson de mapear múltiples campos JSON a una sola variable miembro de objeto Java?

Digamos que tengo una clase de Java ...

public class MyClass {
    String id;
    String name;
}

Quiero usar esta clase única con dos servicios diferentes. Sin embargo, estos dos servicios difieren en cómo devuelven sus datos ...

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

... y ...

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

... respectivamente.

¿Hay alguna forma de asignar los campos "person"y "user"en la cadena JSON al namecampo en el objeto Java?

(Nota: solo necesito convertir de una cadena JSON a un objeto Java, nunca al revés).

Gus
fuente
1
Aquí hay una explicación simple y perfecta futurestud.io/tutorials/…
Atul Bhardwaj

Respuestas:

239

En octubre de 2015, la versión 2.4 de Gson ( registro de cambios ) agregó la capacidad de usar nombres alternativos / múltiples para la @SerializedNamedeserialización. ¡No se necesitan más adaptadores de tipos personalizados!

Uso:

@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

Mathieu Castets
fuente
1
Aquí hay una explicación simple y perfecta futurestud.io/tutorials/…
Atul Bhardwaj
¡Asombroso! ¡Gracias por esta respuesta!
sunlover3
gran respuesta, gracias!
Dor Rud
27

No se admite definir múltiples @SerializedNameanotaciones en un campo en Gson.

Motivo: De forma predeterminada, la deserialización se administra con un LinkedHashMap y las claves se definen por los nombres de campo de json entrantes (no los nombres de campo de la clase personalizada o los serializedNames) y hay una asignación uno a uno. Se puede ver la aplicación (cómo funciona la deserialización) en la ReflectiveTypeAdapterFactoryclase interna de la clase Adapter<T>'s read(JsonReader in)método.

Solución: Se puede escribir una costumbre TypeAdapter que maneja name, persony useretiquetas JSON y los asigna a campo del nombre de la clase personalizada 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();
    }
}

Caso de prueba:

    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"}

Ejemplos sobre TypeAdapters.

Editar 2016.04.06: Como ha escrito @Mathieu Castets en su respuesta, ahora es compatible. (Esa es la respuesta correcta para esta pregunta).

public abstract String [] alternativo
Devuelve: los nombres alternativos del campo cuando se deserializa
Predeterminado: {}

Devrim
fuente
Aquí hay una explicación simple y perfecta futurestud.io/tutorials/…
Atul Bhardwaj
20

para los fans de Kotlin

@SerializedName(value="name", alternate= ["person", "user"])
Mostafa Anter
fuente
8

Para KOTLIN utilicé a continuación pero no funciona

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

¡¡Así que lo edité y aquí funciona bien !!

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