Deserializing polymorphic JSON with Gson throwing exception

JorgeMuci :

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.

JorgeMuci :

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.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=451931&siteId=1