每个字段有多个GSON @SerializedName?


104

Gson中有什么方法可以将多个JSON字段映射到单个Java对象成员变量?

假设我有一个Java类...

public class MyClass {
    String id;
    String name;
}

我想将此单一类与两个不同的服务一起使用。但是,这两种服务在返回数据的方式上有所不同...

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

...和...

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

... 分别。

有什么方法可以将JSON字符串中的"person""user"字段都映射到nameJava对象中的字段?

(注意:我只需要从JSON字符串转换为Java对象-无需其他方法。)


1
这是简单而完美的解释 futurestud.io/tutorials/...
阿图尔巴德瓦杰

Answers:


238

2015年10月,Gson 2.4版changelog)添加了@SerializedName在反序列化时使用备用/多个名称的功能。不再需要自定义TypeAdapter!

用法:

@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
这是简单而完美的解释 futurestud.io/tutorials/...
阿图尔巴德瓦杰

惊人!感谢您的回答!
sunlover3

好答案,谢谢!
Dor Rud)

27

不支持为@SerializedNameGson的一个字段定义多个注释。

原因: 默认情况下,反序列化由LinkedHashMap管理,并且密钥由传入的json的字段名(而不是自定义类的字段名或serializedNames)定义,并且存在一对一的映射。您可以在ReflectiveTypeAdapterFactory类的内部类Adapter<T>read(JsonReader in)方法中查看实现(反序列化的工作方式)。

解决办法: 你可以写一个自定义的TypeAdapter负责处理namepersonuserJSON标签,并将它们映射到您的自定义类的名称字段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();
    }
}

测试用例:

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

有关TypeAdapter的示例。

编辑2016.04.06:正如@Mathieu Castets在他的回答中所写,现在受支持。(这是此问题的正确答案。)

public abstract String [] Alternative
返回:字段反序列化时的备用名称
默认值: {}


这是简单而完美的解释 futurestud.io/tutorials/...
阿图尔巴德瓦杰


8

对于KOTLIN,我在下面使用了它,但不起作用

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

所以我编辑了它,在这里效果很好!

@SerializedName(value="name", alternate= arrayOf("person", "user"))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.