Beberapa GSON @SerializedName per kolom?

104

Apakah ada cara di Gson untuk memetakan beberapa bidang JSON ke variabel anggota objek Java tunggal?

Katakanlah saya memiliki kelas Java ...

public class MyClass {
    String id;
    String name;
}

Saya ingin menggunakan kelas tunggal ini dengan dua layanan berbeda. Namun, kedua layanan ini berbeda dalam cara mengembalikan datanya ...

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

... dan ...

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

... masing-masing.

Apakah ada cara untuk memetakan bidang "person"dan "user"dalam string JSON ke namebidang di objek Java?

(Catatan: Saya hanya perlu mengonversi dari string JSON ke objek Java - tidak pernah sebaliknya.)

Gus
sumber
1
Berikut adalah penjelasan sederhana dan Sempurna futurestud.io/tutorials/…
Atul Bhardwaj

Jawaban:

239

Pada bulan Oktober 2015, Gson versi 2.4 ( changelog ) menambahkan kemampuan untuk menggunakan nama alternatif / banyak untuk @SerializedNamesaat deserialisasi. Tidak perlu lagi TypeAdapter khusus!

Pemakaian:

@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
sumber
1
Berikut adalah penjelasan sederhana dan Sempurna futurestud.io/tutorials/…
Atul Bhardwaj
Luar biasa! Terima kasih atas jawaban ini!
sunlover3
jawaban yang bagus, terima kasih!
Dor Rud
27

Tidak didukung untuk menentukan beberapa @SerializedNameanotasi ke bidang di Gson.

Alasan: Secara default Deserialization dikelola dengan LinkedHashMap dan kuncinya ditentukan oleh nama field json yang masuk (bukan nama field kelas kustom atau serializedNames) dan ada pemetaan satu lawan satu. Anda dapat melihat pelaksanaan (bagaimana deserialization bekerja) di ReflectiveTypeAdapterFactorykelas batin kelas ini Adapter<T>'s read(JsonReader in)metode.

Solusi: Anda dapat menulis TypeAdapter khusus yang menangani name, persondan usertag json dan memetakannya ke bidang nama kelas khusus Anda 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();
    }
}

Kasus cobaan:

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

Contoh tentang TypeAdapters.

Sunting 2016.04.06: Seperti yang ditulis oleh @Mathieu Castets pada jawabannya, sekarang ini didukung. (Itu adalah jawaban yang benar untuk pertanyaan ini.)

public abstract String [] alternate
Returns: nama alternatif dari bidang ketika deserialisasi
Default: {}

Devrim
sumber
Berikut adalah penjelasan sederhana dan Sempurna futurestud.io/tutorials/…
Atul Bhardwaj
20

untuk penggemar Kotlin

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

Untuk KOTLIN saya gunakan di bawah ini tetapi tidak berfungsi

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

jadi saya mengeditnya dan ini berfungsi dengan baik !!

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