【问题标题】:Partial bean serialization and deserialization+merging部分bean序列化和反序列化+合并
【发布时间】:2009-04-08 21:43:36
【问题描述】:

我正在开发一个 RESTful Web 服务。

我有一堆实体类(主要是 JPA 实体,还有其他 bean)。

有大量的对象映射、序列化、绑定和诸如此类的库。我正在寻找一种能够让我:

  • 将实体序列化为 XML 和 JSON

    序列化必须支持使用 getters,而不仅仅是对象字段。

    它必须支持视图。视图是指一种指定要序列化的实体属性子集的方法。例如,请参阅 Yahoo! 中的 Retrieving Partial Resources。社交平台 API。我也不希望它无限深地递归:

    视图应该定义 a) 要在实体中公开的属性和 b) 每个属性的视图(如果它们本身就是实体)。

    例如,实体Person 可能具有视图fullsimple。当请求Personsimple 视图时,只会序列化属性idfirstNamelastName。当请求full 视图时,属性motherfather(它们本身就是Persons)也将被序列化,但仅限于simple 视图(因此它不会递归到祖父母)。

    JSON 序列化必须是“自然”,即在 Javascript 中有意义的内容。这意味着我想要正确的整数、布尔值和空值,并且我不想要额外的对象包装器或试图捕获整个 XML 信息集的东西。

    对于 XML,必须可以将序列化配置为使用 空元素 序列化空值,而不是 XML Schema 的 xsi:nil="true" 属性。

    此外,数组必须使用嵌套元素进行序列化,以便区分空数组和给定视图中不存在的属性:

    • 未定义的friends 属性(视图中不存在):

      <person>
      </person>
      
    • 空数组,人没有朋友:

      <person>
          <friends></friends>
      </person>
      
  • 反序列化 XML 和 JSON 并将数据合并到现有实体中

    现在这是困难的部分。接下来的两个是连接的:

    部分对象的反序列化必须是可能的(类似于视图,但没有预先定义哪些属性存在)。

    合并到现有属性,而不是创建新属性。

    这有点难以解释。大多数库都反序列化为 Java 对象,但在那个时候,未定义属性和空/空属性之间的区别(因为它存在于 Javascript/JSON、如上所述的 XML、PHP 等)之间的区别就消失了。

    当得到这个 XML 时:

    <person>
        <lastName>Bon Jovi</lastName>
        <friends></friends>
    </person>
    

    并且被传递一个Person 对象,库应该:

    person.setLastName("Bon Jovi");
    person.setFriends(new ArrayList());
    

    它不应触及实体 firstName 和/或清除它是 father,例如。

    当然,对于列表,这应该更复杂。我希望配置一个 id 属性,通过它来决定是更新嵌套实体还是创建一个新实体。

    这些更新/补丁是库不能只返回 DTO 的一个原因:因为那时 null 可能意味着“未设置”或“什么都不做”。

嗯,就是这样。我一直在说“必须”很多,我现在意识到 :) 库实际上不需要提供它,但必须有一种方法以一种干净的方式添加功能(= 不是以一种会重写所有内容的方式更容易)。

【问题讨论】:

    标签: java xml json serialization


    【解决方案1】:

    我不知道现有的库可以满足你的所有需求,但是,假设你需要实现一些东西:

    • 基于 bean 属性编写 XML 或 JSON 非常简单:

      • 看看使用 Apache Commons BeanUtils 能够获取所有属性值 (http://commons.apache.org/beanutils/)。特别是 PropertyUtils 类。
      • 使用 BeanUtils 递归地遍历整个对象图 - 小心循环 - 你需要一个 Set 或其他东西来跟踪你已经看到的内容
      • XML:看看 XMLEncoder - 它使用 JavaBean 属性来创建 XML
    • 对于阅读:一种方法可能是使用现有库(用于 JSON 或 XML)来创建对象,然后处理合并对象之间的属性。 XMLDecoder 类可以读取 bean XML(假设您使用 XMLEncoder 创建它)。这种方法的棘手部分是要知道一个值何时被“设置”为 null 而不是在 XML 中设置。这种方法还具有创建一堆新对象的额外开销。

    • 否则,读取 JSON 或 XML 会有点棘手,但还不错

      • 我假设您已经有一些方法可以索引要合并到的对象(例如某种地图)
      • 我假设您已经有一些方法可以知道哪个属性是唯一标识对象的键(我假设姓氏只是为了说明问题,因为它会成为一个错误的键)
      • XML:对于这种类型的使用,我推荐一个用于 xml 的 SAX 阅读器 - 您需要一个堆栈来跟踪您正在向哪些对象添加数据。 SAX 阅读器会告诉您看到了哪些标签,然后给出这些标签的值。您也可以在此处使用 XML 拉取,这往往会更快一些
      • JSON:查看一些开源 JSON 库并进行一些调整。 JSON 解析起来非常简单,而且这些工具往往很小,所以这应该没什么大不了的。或者,您可以编写一个 ANTLR(或其他生成器)解析器来读取 JSON 并根据需要进行处理。

    【讨论】:

      【解决方案2】:

      对于它的价值,Jackson 具有开箱即用的部分更新:

      ObjectMapper mapper = new ObjectMapper();
      Bean existing = ...;
      mapper.updatingReader(existing).readValue(jsonSource);
      

      它还可以转换兼容的类型(类似于序列化为JSON,读回不同的类型)。

      对于XML部分你可以使用JAXB,虽然据我所知它只能完成绑定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-30
        • 1970-01-01
        • 2020-02-24
        • 2012-03-17
        相关资源
        最近更新 更多