当前位置: 首页 > 知识库问答 >
问题:

使用Gson引发异常反序列化多态JSON

田博易
2023-03-14

我正在开发一个应用程序,它使用Gson作为JSON反序列化器,需要从REST API反序列化多态JSON。在解释mi问题之前,请注意,我已经用Gson研究了多态反序列化,并在几个案例中成功地实现了它。这是我面临的一个具体问题。在问这个问题之前,我也读过这篇很棒的帖子和关于堆栈溢出的讨论。顺便说一下,我正在使用RuntimeTypeAdapterFactory来反序列化多态对象。

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

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,那么一切都可以正常工作。我不明白为什么GsonRuntimeTypeAdapterFactory有这个限制。事实上,在这篇博客文章中,这显然不是一个问题。

谁能解释一下这里发生了什么,为什么定义类型的属性的名称不能在POJO层次结构中定义?

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

共有3个答案

崔宜修
2023-03-14

您可以始终使用默认Gson实例进行序列化(new Gson()),然后使用RuntimeTypeAdapterFactory实例进行反序列化。

如果你想改变一切,建议不要使用@Expose。它只会用冗余注释破坏模型类。

储志业
2023-03-14

我认为使用您自己的userType而不使用@Exact注释会达到目的

雷格斯

伯俊弼
2023-03-14

嗯,经过一段时间的挖掘,我发现问题实际上不是反序列化,问题出现在序列化和注册RuntimeTypeFactory时,如问题所述。如果您注册一个runtimeTypeAdapterFactory,并使用相同的字段名来定义工厂和pojo中的类类型,那么使用GSON将pojo序列化为json,例如使用RuntimeTypeAdapterFactory for a SpecialUser所产生的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

因为de field userType由于GSON序列化器而在json中重复,这将自动添加一个在为类BaseUser注册的RuntimeTypeAdapterFactory中声明的字段。

 类似资料:
  • 我有一个接口,其中和实现。服务器会返回这样的响应- 相应的类来建模它是 中的声明它是哪种车辆。我需要反序列化的成一个对象取决于。如果是,我需要在反序列化和期间使用反序列化。 如何使用gson实现这一点? 编辑-这篇文章的不同之处在于类类型()包含在需要反序列化的中。这里不是。如果在内,我可以为编写自定义反序列化程序,检查,并进行相应的反序列化。但是我想我需要为编写一个自定义反序列化程序,在这里我创

  • 问题内容: 使用Gson 2.2.2,我正在尝试序列化POJO(行为)的数组列表。 我有一个适配器,几乎是我在网上看到的一个副本: 我这样注册: 然后,当我尝试序列化我的ArrayList时: 我出现堆栈溢出。 似乎在线上: 它开始递归循环,一次又一次地通过我的序列化器。那么,我该如何注册它以免发生这种情况?我需要序列化列表并保持多态性。 问题答案: 看起来您发现了JsonSerializer文档

  • 我从超文本传输协议Web服务收到以下JSON响应 现在我希望能够反序列化这个。我偶然发现了来自谷歌的Gson,它最初在一些小测试用例中运行良好,但我在反序列化上面的字符串时遇到了一些困难。 我正在阅读Gson用户指南,理想情况下,我希望有一个对象,它有两个属性:和,但是字段必须是对象的,这可能会让Gson感到困难。 然后我看了这个例子,它更接近我的问题,但我仍然不太明白。在这个例子中,整个响应是一

  • 问题内容: 我使用了很多不可变的集合,并且很好奇如何使用Gson反序列化它们。由于没有人回答,而且我自己找到了解决方案,因此我正在简化问题并提出自己的答案。 我有两个问题: 如何为所有人编写一个作品? 如何全部注册? 问题答案: 更新:有https://github.com/acebaggins/gson- serializers ,其中涵盖了许多番石榴集合: 如何编写适用于所有Immutable

  • 简单地说,我能够让Jackson2.1.2将类层次结构序列化为带有类型信息的JSON字符串。但是,我无法让Jackson2.1.2将JSON字符串反序列化回到我类层次结构中。下面是一个暴露这个问题的单元测试。 类层次结构足够简单;只有两个直接子类的基类。此外,JSON输出似乎尊重我的Jackson@JsonTypeInfo,并从Mapper.WriteValueString生成一个可信的字符串 但

  • 问题内容: 我如何反序列化此json: 使用Google GSON? 问题答案: 要反序列化JSON,您需要为递归接口使用自定义反序列化器。在这种类中,您需要检查JSON并确定要实例化为JSON本身的type字段的类。在这里,您有一个我为您编写的示例基本解串器。 当然,管理边界事件可以得到改善(例如,如果没有类型字段,会发生什么情况?)。 这是我的代码的结果: