I'm working on an app that is using Gson as JSON deserializer and needs to deserialize polymorphic JSON from REST API. Before explaining mi issue note that I've already been looking around polymorphic deserialization with Gson and have implemented it on several cases successfully. So this is a specific issue I'm having. Also I've read this great post and this Stack Overflow discussion before asking this. I'm using RuntimeTypeAdapterFactory
to deserialize polymorphic objects by the way.
The problem I'm having is that apparently GSON's RuntimeTypeAdapterFactory
does't allow to declare the field which specifies the type of the object inside the hierarchy structure. I'll explain further with some code. I have the following pojos structure (pojos had been reduced for the sake of simplicity):
public abstract class BaseUser {
@Expose
protected EnumMobileUserType userType;
}
public class User extends BaseUser {
@Expose
private String name;
@Expose
private String email;
}
public class RegularUser extends User {
@Expose
private String address;
}
public class SpecialUser extends User {
@Expose
private String promoCode;
}
Now this is the code where I defined the RuntimeTypeAdapterFactory
for User hierarchy.
public static RuntimeTypeAdapterFactory<BaseUser> getUserTypeAdapter() {
return RuntimeTypeAdapterFactory
.of(BaseUser.class, "userType")
.registerSubtype(User.class, EnumMobileUserType.USER.toString())
.registerSubtype(RegularUser.class, EnumMobileUserType.REGULAR.toString())
.registerSubtype(SpecialUser.class, EnumMobileUserType.SPECIAL.toString());
}
public static Gson getGsonWithTypeAdapters() {
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapterFactory(getUserTypeAdapter());
return builder.create();
}
Now when I try to deserialize a JSON text:
{
"user":{
"userType":"USER",
"email":"[email protected]",
"name":"Albert"
}
}
I get this exception:
com.google.gson.JsonParseException: cannot serialize com.mobile.model.entities.v2.common.User because it already defines a field named userType
But if I change the name of the property "userType" in my BaseUser
class to "type" for example and I deserialize the same JSON everything works properly. I don't get why Gson RuntimeTypeAdapterFactory
has this restriction. In fact in this blog post apparently this is not an issue.
Can anyone explain what's going on here, why the name of the property that defines the type cannot be defined inside the pojos hierarchy?
EDIT the issue is not when deserializing but when serializing using the code described above. Find further explanation in the answer.
Well, after some time digging I found out that the problem is not actually deserializing, the problem comes when serializing and having a RuntimeTypeFactory registered as described in the question. If you register a runtimeTypeAdapterFactory and use the same field name to define the class type in the factory and in your pojo, json resulting from serializing pojo to json using GSON with the RuntimeTypeAdapterFactory for a SpecialUser for example will be:
{
"user":{
"userType":"SPECIAL",
"email":"[email protected]",
"name":"Albert"
"userType":"SPECIAL"
}
}
This will result in the exception described:
com.google.gson.JsonParseException: cannot serialize com.mobile.model.entities.v2.common.User because it already defines a field named userType
because de field userType is repeated in the json due to GSON serializer, which will automatically add a field as declared in the RuntimeTypeAdapterFactory registered for the class BaseUser.
I think that using your own userType without @Expose annotation will do the trick
Regads
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With