web-dev-qa-db-fra.com

Plusieurs GSON @SerializedName par champ?

Existe-t-il un moyen dans Gson de mapper plusieurs champs JSON en une seule variable Java membre?

Disons que j'ai une classe Java ...

public class MyClass {
    String id;
    String name;
}

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

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

... et ...

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

... respectivement.

Est-il possible de mapper à la fois le "person" et "user" champs de la chaîne JSON au champ name de l'objet Java??

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

83
Gus

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

Utilisation:

@SerializedName(value="name", alternate={"person", "user"})

https://google.github.io/gson/apidocs/com/google/gson/annotations/SerializedName.html

200
Mathieu Castets

La définition de plusieurs annotations @SerializedName dans un champ de Gson n'est pas prise en charge.

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 champs du json entrant (et non par les noms de champs de la classe personnalisée ni par les noms serialized). il existe un mappage un à un. Vous pouvez voir l'implémentation (comment fonctionne la désérialisation) à la méthode read(JsonReader in) de la classe interne de la classe ReflectiveTypeAdapterFactory de la classe Adapter<T>.

Solution: Vous pouvez écrire un personnalisé TypeAdapter qui gère name, person et user balises json et les mappe sur le champ de 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 a écrit sa réponse, elle est prise en charge maintenant. (C'est la bonne réponse pour cette question.)

public abstract String [] substitut
Retourne: les noms alternatifs du champ quand il est désérialisé
Défaut: {}

26
Devrim

pour Kotlin fans

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

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

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

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

@SerializedName(value="name", alternate= arrayOf("person", "user"))
6
android