使用 Gson 抛出异常反序列化多态 JSON

2022-09-04 03:47:32

我正在开发一个使用Gson作为JSON反序列化器的应用程序,并且需要从REST API反序列化多态JSON。在解释mi问题之前,请注意,我已经使用Gson进行了多态反序列化,并已成功在几个案例中实现了它。所以这是我遇到的一个具体问题。在问这个问题之前,我也读过这篇很棒的文章这个Stack Overflow讨论。顺便说一句,我用来反序列化多态对象。RuntimeTypeAdapterFactory

问题我遇到的是,显然GSON不允许声明指定层次结构中对象类型的字段。我将用一些代码进一步解释。我有以下pojos结构(为了简单起见,pojos已经减少):RuntimeTypeAdapterFactory

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

现在,这是我为用户层次结构定义的代码。RuntimeTypeAdapterFactory

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();
}

现在,当我尝试反序列化 JSON 文本时:

{  
   "user":{  
      "userType":"USER",
      "email":"albert@gmail.com",
      "name":"Albert"
   }
}

我得到这个例外:

com.google.gson.JsonParseException: cannot serialize com.mobile.model.entities.v2.common.User because it already defines a field named userType

但是,如果我将类中的属性“userType”的名称更改为“type”,并且我反序列化相同的JSON,则一切都可以正常工作。我不明白为什么Gson有这个限制。事实上,在这篇博客文章中,显然这不是一个问题。BaseUserRuntimeTypeAdapterFactory

任何人都可以解释这里发生了什么,为什么定义类型的属性的名称不能在pojos层次结构中定义?

EDIT 问题不在于反序列化时,而在于使用上述代码进行序列化时。在答案中找到进一步的解释。


答案 1

好吧,经过一段时间的挖掘,我发现问题实际上并不是反序列化,而是在序列化并按照问题中描述的方式注册运行时类型工厂时出现问题。如果您注册了一个 runtimeTypeAdapterFactory,并使用相同的字段名称在工厂和 pojo 中定义类类型,则例如,使用 GSON 将 pojo 序列化为 json 以及 SpecialUser 的 RuntimeTypeAdapterFactory 生成的 json 将是:

{  
  "user":{  
      "userType":"SPECIAL",
      "email":"albert@gmail.com",
      "name":"Albert"
      "userType":"SPECIAL"
  }
}

这将导致描述的异常:

com.google.gson.JsonParseException: cannot serialize com.mobile.model.entities.v2.common.User because it already defines a field named userType

因为由于GSON序列化程序,de field userType在json中重复,它将自动添加一个在为类BaseUser注册的运行时TypeAdapterFactory中声明的字段。


答案 2

我认为使用自己的userType而不@Expose注释将解决问题

雷加兹