Più GSON @SerializedName per campo?


104

Esiste un modo in Gson per mappare più campi JSON su una singola variabile membro dell'oggetto Java?

Diciamo che ho una classe Java ...

public class MyClass {
    String id;
    String name;
}

Voglio usare questa singola classe con due diversi servizi. Tuttavia, questi due servizi differiscono nel modo in cui restituiscono i dati ...

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

... e ...

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

... rispettivamente.

Esiste un modo per mappare entrambi i campi "person"e "user"nella stringa JSON al namecampo nell'oggetto Java?

(Nota: devo solo convertire da una stringa JSON a un oggetto Java, mai il contrario.)


1
Ecco una spiegazione semplice e perfetta futurestud.io/tutorials/…
Atul Bhardwaj

Risposte:


239

Nel mese di ottobre 2015, la versione 2.4 GSON ( changelog ) Aggiunta la possibilità di uso alternato / più nomi per @SerializedNamequando deserializzazione. Non sono più necessari TypeAdapter personalizzati!

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


1
Ecco una spiegazione semplice e perfetta futurestud.io/tutorials/…
Atul Bhardwaj

Sorprendente! Grazie per questa risposta!
sunlover3

ottima risposta, grazie!
Dor Rud il

27

Non è supportato definire più @SerializedNameannotazioni in un campo in Gson.

Motivo: per impostazione predefinita, la deserializzazione viene gestita con una LinkedHashMap e le chiavi sono definite dai nomi dei campi json in entrata (non i nomi dei campi della classe personalizzata o serializedNames) e c'è una mappatura uno a uno. Si può vedere l'implementazione (come funziona deserializzazione) alla ReflectiveTypeAdapterFactoryclasse interna della classe Adapter<T>'s read(JsonReader in)metodo.

Soluzione: È possibile scrivere un costume TypeAdapter che le maniglie name, persone usertag JSON e li mappe di campo del nome della classe personalizzata 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();
    }
}

Scenario di test:

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

Esempi di TypeAdapters.

Modifica 2016.04.06: come ha scritto @Mathieu Castets alla sua risposta, ora è supportato. (Questa è la risposta corretta a questa domanda.)

public abstract String [] alternate
Returns: i nomi alternativi del campo quando è deserializzato
Default: {}


Ecco una spiegazione semplice e perfetta futurestud.io/tutorials/…
Atul Bhardwaj

20

per i fan di Kotlin

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

8

Per KOTLIN ho usato di seguito ma non funziona

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

quindi l'ho modificato e qui funziona bene !!

@SerializedName(value="name", alternate= arrayOf("person", "user"))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.