Mehrere GSON @SerializedName pro Feld?

104

Gibt es in Gson eine Möglichkeit, mehrere JSON-Felder einer einzelnen Java-Objektmitgliedsvariablen zuzuordnen?

Angenommen, ich habe eine Java-Klasse ...

public class MyClass {
    String id;
    String name;
}

Ich möchte diese einzelne Klasse mit zwei verschiedenen Diensten verwenden. Diese beiden Dienste unterscheiden sich jedoch darin, wie sie ihre Daten zurückgeben ...

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

... und ...

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

... beziehungsweise.

Gibt es eine Möglichkeit, die Felder "person"und "user"in der JSON-Zeichenfolge dem nameFeld im Java-Objekt zuzuordnen ?

(Hinweis: Ich muss immer nur von einer JSON-Zeichenfolge in ein Java-Objekt konvertieren - niemals umgekehrt.)

Gus
quelle
1
Hier ist eine einfache und perfekte Erklärung futurestud.io/tutorials/…
Atul Bhardwaj

Antworten:

235

Im Oktober 2015 hat Gson Version 2.4 ( Changelog ) die Möglichkeit hinzugefügt, @SerializedNamebeim Deserialisieren alternative / mehrere Namen zu verwenden . Kein benutzerdefinierter TypeAdapter mehr erforderlich!

Verwendung:

@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
quelle
1
Hier ist eine einfache und perfekte Erklärung futurestud.io/tutorials/…
Atul Bhardwaj
Tolle! Vielen Dank für diese Antwort!
sunlover3
tolle Antwort, danke!
Dor Rud
27

Es wird nicht unterstützt, mehrere @SerializedNameAnmerkungen zu einem Feld bei Gson zu definieren .

Grund: Standardmäßig wird die Deserialisierung mit einer LinkedHashMap verwaltet und die Schlüssel werden durch eingehende Feldnamen von json definiert (nicht durch die Feldnamen der benutzerdefinierten Klasse oder die serialisierten Namen), und es gibt eine Eins-zu-Eins-Zuordnung. Sie können die Implementierung (wie Deserialisierung Werke) bei siehe ReflectiveTypeAdapterFactoryKlasse innere Klasse Adapter<T>‚s - read(JsonReader in)Methode.

Lösung: Sie können eine benutzerdefinierte schreiben TypeAdapter welche Griffe name, personund userjson - Tags und ordnet sie der benutzerdefinierten Klasse Namensfeld 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();
    }
}

Testfall:

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

Beispiele zu TypeAdapters.

Edit 2016.04.06: Wie @Mathieu Castets bei seiner Antwort geschrieben hat, wird es jetzt unterstützt. (Das ist die richtige Antwort auf diese Frage.)

public abstract String [] alternative
Rückgabe: Die alternativen Namen des Felds, wenn es deserialisiert wird.
Standard: {}

Devrim
quelle
Hier ist eine einfache und perfekte Erklärung futurestud.io/tutorials/…
Atul Bhardwaj
19

für Kotlin Fans

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

Für KOTLIN habe ich unten verwendet, aber es funktioniert nicht

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

Also habe ich es bearbeitet und hier funktioniert es gut !!

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