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

olqngx59  于 2023-03-08  发布在  其他
关注(0)|答案(4)|浏览(220)

我正在开发一个应用程序,它使用Gson作为JSON反序列化器,需要从REST API反序列化多态JSON。在解释我的问题之前,请注意,我已经在Gson中研究了多态反序列化,并在几个案例中成功实现了它。所以这是我遇到的一个特定问题。在问这个问题之前,我也阅读了this great postthis Stack Overflow discussion。我“顺便说一下,我使用RuntimeTypeAdapterFactory来反序列化多态对象。

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

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

这是我为User层次结构定义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

但是如果我把BaseUser类中的属性名“userType”改为“type”,并且反序列化相同的JSON,那么一切都能正常工作。我不明白为什么Gson RuntimeTypeAdapterFactory有这个限制。事实上,在this blog post中,这显然不是一个问题。
有人能解释一下这里发生了什么吗?为什么定义类型的属性的名称不能在pojos层次结构中定义?

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

xiozqbni

xiozqbni1#

经过一段时间的挖掘,我发现问题并不在于反序列化,而是在于序列化和注册RuntimeTypeFactory时,如问题中所述。如果您注册了一个runtimeTypeAdapterFactory,并使用相同的字段名在工厂和pojo中定义类类型,例如,对于SpecialUser,通过使用GSON和RuntimeTypeAdapterFactory将pojo序列化为json而得到的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序列化器,字段userType在json中重复,这将自动添加一个字段,该字段在为类BaseUser注册的RuntimeTypeAdapterFactory中声明。

t9eec4r0

t9eec4r02#

我认为使用您自己的userType而不使用@Expose注解就可以了
雷加兹

mklgxw1f

mklgxw1f3#

您始终可以使用默认的Gson示例来 * 序列化 *(new Gson()),然后使用RuntimeTypeAdapterFactory示例来 * 反序列化 *。
如果你想转换所有的东西,建议不要使用@Expose,因为它只会用多余的注解破坏你的模型类。

0h4hbjxa

0h4hbjxa4#

我在android/Kotlin上也遇到了同样的问题,JorgeMuci's answer对我不起作用,但使用同样的方法,我使用了@Transient标签,效果很好

相关问题