Multiple GSON @SerializedName per field?

JavaJsonGson

Java Problem Overview


Is there any way in Gson to map multiple JSON fields to a single Java object member variable?

Let's say I have a Java class...

public class MyClass {
    String id;
    String name;
}

I want to use this single class with two different services. However, these two services differ in how they return their data...

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

... and ...

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

... respectively.

Is there any way to map both the "person" and "user" fields in the JSON string to the name field in the Java object?

(Note: I only ever need to convert from JSON string to Java object - never the other way around.)

Java Solutions


Solution 1 - Java

In October 2015, Gson version 2.4 (changelog) added the ability to use alternate/multiple names for @SerializedName when deserializing. No more custom TypeAdapter needed!

Usage:

java

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

kotlin

@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

Solution 2 - Java

for Kotlin fans

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

Solution 3 - Java

It is not supported to define multiple @SerializedName annotations to a field at Gson.

Reason: By default Deserialization is managed with a LinkedHashMap and the keys are defined by incoming json's field names (not the custom class's field names or the serializedNames) and there is a one to one mapping. You can see the implementation(how deserialization works) at ReflectiveTypeAdapterFactory class's inner class Adapter<T>'s read(JsonReader in) method.

Solution: You can write a custom TypeAdapter which handles name, person and user json tags and maps them to name field of your custom class 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();
	}
}

Test case:

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

Examples about TypeAdapters.

Edit 2016.04.06 : As @Mathieu Castets has written at his answer, it is supported now. (That is the correct answer for this question.)

> public abstract String[] alternate
> Returns: the alternative names of > the field when it is deserialized
Default: {}

Solution 4 - Java

For KOTLIN i used below but doesn't work

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

so i edited it and here it works fine!!

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGusView Question on Stackoverflow
Solution 1 - JavaMathieu CastetsView Answer on Stackoverflow
Solution 2 - JavaMostafa AnterView Answer on Stackoverflow
Solution 3 - JavaDevrimView Answer on Stackoverflow
Solution 4 - JavaandroidView Answer on Stackoverflow