我正在开发一个应用程序,它使用Gson作为JSON反序列化器,需要从REST API反序列化多态JSON。在解释我的问题之前,请注意,我已经在Gson中研究了多态反序列化,并在几个案例中成功实现了它。所以这是我遇到的一个特定问题。在问这个问题之前,我也阅读了this great post和this 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问题不在于反序列化,而在于使用上面描述的代码进行序列化。在答案中可以找到进一步的解释。
4条答案
按热度按时间xiozqbni1#
经过一段时间的挖掘,我发现问题并不在于反序列化,而是在于序列化和注册RuntimeTypeFactory时,如问题中所述。如果您注册了一个runtimeTypeAdapterFactory,并使用相同的字段名在工厂和pojo中定义类类型,例如,对于SpecialUser,通过使用GSON和RuntimeTypeAdapterFactory将pojo序列化为json而得到的json将为:
这将导致所描述的异常:
因为由于GSON序列化器,字段userType在json中重复,这将自动添加一个字段,该字段在为类BaseUser注册的RuntimeTypeAdapterFactory中声明。
t9eec4r02#
我认为使用您自己的userType而不使用@Expose注解就可以了
雷加兹
mklgxw1f3#
您始终可以使用默认的Gson示例来 * 序列化 *(new Gson()),然后使用RuntimeTypeAdapterFactory示例来 * 反序列化 *。
如果你想转换所有的东西,建议不要使用@Expose,因为它只会用多余的注解破坏你的模型类。
0h4hbjxa4#
我在android/Kotlin上也遇到了同样的问题,JorgeMuci's answer对我不起作用,但使用同样的方法,我使用了@Transient标签,效果很好