Plusieurs GSON @SerializedName par champ?

104

Existe-t-il un moyen dans Gson de mapper plusieurs champs JSON à une seule variable membre d'objet Java?

Disons que j'ai une classe Java ...

public class MyClass {
    String id;
    String name;
}

Je souhaite utiliser cette classe unique avec deux services différents. Cependant, ces deux services diffèrent dans la manière dont ils retournent leurs données ...

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

... et ...

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

... respectivement.

Existe-t-il un moyen de mapper à la fois les champs "person"et "user"de la chaîne JSON avec le namechamp de l'objet Java?

(Remarque: je n'ai besoin que de convertir une chaîne JSON en objet Java - jamais l'inverse.)

Gus
la source
1
Voici l'explication simple et parfaite futurestud.io/tutorials
Atul Bhardwaj

Réponses:

239

En octobre 2015, Gson version 2.4 ( changelog ) a ajouté la possibilité d'utiliser des noms alternatifs / multiples @SerializedNamelors de la désérialisation. Plus besoin d'adapter TypeAdapter personnalisé!

Usage:

@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
la source
1
Voici l'explication simple et parfaite futurestud.io/tutorials
Atul Bhardwaj
Incroyable! Merci pour cette réponse!
sunlover3
excellente réponse, merci!
Dor Rud
27

Il n'est pas pris en charge de définir plusieurs @SerializedNameannotations à un champ chez Gson.

Raison: Par défaut, la désérialisation est gérée avec un LinkedHashMap et les clés sont définies par les noms de champ de json entrants (pas les noms de champ de la classe personnalisée ou les serializedNames) et il existe un mappage un à un. Vous pouvez voir la mise en œuvre (comment les travaux de désérialisation) à la ReflectiveTypeAdapterFactoryclasse interne de la classe Adapter<T>de read(JsonReader in)la méthode.

Solution: Vous pouvez écrire une coutume TypeAdapter qui poignées name, personet les userbalises JSON et les cartes à champ nom de votre classe personnalisée 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();
    }
}

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

Exemples sur TypeAdapters.

Edit 2016.04.06: Comme @Mathieu Castets l'a écrit à sa réponse, elle est supportée maintenant. (C'est la bonne réponse à cette question.)

public abstract String [] Alternate
Renvoie: les noms alternatifs du champ lorsqu'il est désérialisé
Par défaut: {}

Devrim
la source
Voici l'explication simple et parfaite futurestud.io/tutorials
Atul Bhardwaj
20

pour les fans de Kotlin

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

Pour KOTLIN, j'ai utilisé ci-dessous mais ne fonctionne pas

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

donc je l'ai édité et ici ça marche bien !!

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