5

我一直面临这个问题,序列化的休眠对象会产生意外的 xml,其中包含来自 Hibernate 的所有检测代码。

在序列化对象之前,我们对对象进行了一些清理。

但是,是否有可用于直接序列化对象的标准选项?

4

6 回答 6

3

我以前没有使用过 XStream,但是我已经序列化了 Hibernate 管理的实体。这不好玩。

有两个大问题:

  • 延迟加载;
  • 一对多关系。

前者很明显 - 您需要实际数据进行序列化。后者不那么重要 - 您针对集合接口(例如:)声明的任何一对多关系都Set<T>将被 Hibernate 自己的(不可序列化!)集合实现插入。这很可能是 Hibernate 的类渗入您的对象的地方。

我最终编写了执行此操作的反射代码(实际上是内省的):

  1. 在会话打开的情况下,触摸整个对象图以强制加载任何未加载的实体;
  2. 关闭 Hibernate 会话(包括任何涉及其连接的事务);
  3. 遍历对象图,用 ArrayList、HashSet 或 HashMap(已知可序列化集合)的实例替换任何列表、集合或映射。

请注意,第 2 步很重要 - 如果您在关闭会话之前替换集合,Hibernate 只会在关闭时将其自己的集合放回...

编辑: @cliff.meyers 发现了一个我忘记提及的实现细节:如果你这样做,你需要将对象图限制在你自己的实体上,并注意循环引用路径(例如:通过缓存对你的对象的引用'已经走了)。

于 2008-11-30T19:27:23.863 回答
3

我想出了一些足够的解决方案。在我的应用程序中,只有 PersistentSets 会弄乱 XStream 生成的 XML。所以我向 XStream 添加了另一个转换器(它与打开的 Hibernate Session 和活动对象一起运行):

XStream xs = new XStream();
xs.registerConverter(new CollectionConverter(xs.getMapper()) {
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        org.hibernate.collection.PersistentSet ps = (PersistentSet) source;
        super.marshal(new HashSet(ps), writer, context);
    }

    @Override
    public boolean canConvert(Class type) {
        return type.isAssignableFrom(org.hibernate.collection.PersistentSet.class);
    }
}, XStream.PRIORITY_VERY_HIGH);
String s = xs.toXML(processInstance);

序列化的 XML 如下所示:

  <processLogs class="org.hibernate.collection.PersistentSet">
    <pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
      <id>813017</id>
      <entryDate>
        <time>1310832421216</time>
        <timezone>GMT</timezone>
      </entryDate>
      <eventI18NKey>process.log.action-performed</eventI18NKey>
      <additionalInfo>Wydrukuj wniosek</additionalInfo>
      <logValue>GENERATE_APPLICATION</logValue>
      <logType>PERFORM_ACTION</logType>
      <state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[8]"/>
      <processInstance reference="../../.."/>
      <user reference="../../../creator"/>
    </pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
    <pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>
      <id>808211</id>
      <entryDate>
        <time>1310828206169</time>
        <timezone>GMT</timezone>
      </entryDate>
      <eventI18NKey>process.log.action-performed</eventI18NKey>
      <additionalInfo>Zaakceptuj</additionalInfo>
      <logValue>ACCEPT</logValue>
      <logType>PERFORM_ACTION</logType>
      <state reference="../../../definition/states/pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration[4]"/>
      <processInstance reference="../../.."/>
      <user reference="../../../creator"/>
    </pl.net.bluesoft.rnd.processtool.model.ProcessInstanceLog>

在我的例子中,class 属性并不重要,所以我忽略了它的值。你当然可以修补它。

于 2011-07-16T18:25:26.457 回答
3

XStream 现在提供了一个单独的模块/jar 来处理 Hibernate 集合。有关示例,请参阅XStream 的常见问题解答。

于 2012-08-29T19:57:44.367 回答
1

尽管我没有使用休眠,但我遇到了类似的问题。我查看了实体修剪器,但它并不是我想要的,因为我正在寻找更简单的解决方案。

我想出了一个非常简单的解决方案,它使用反射来代理 CGLIB 增强对象,就像一个魅力。

请访问http://www.anzaan.com/2010/06/serializing-cglib-enhanced-proxy-into-json-using-xstream/示例和代码。

于 2010-06-26T02:10:05.127 回答
1

Codehaus JIRA 上有一些关于此(和示例代码)的信息:

http://jira.codehaus.org/browse/XSTR-226

我们为许多其他远程实现(Axis 1、Blaze DS 等)编写了一些工具来解决此类问题。我们所做的与 Dan 的解决方案非常相似,尽管我们添加了声明哪些对象路径要走以及哪些要“剪断”的功能,因为在许多情况下我们对所有数据都不感兴趣;它还会导致“n+1 选择”问题发生数千次的严重问题!:) 我认为实现 XStream 转换器将是最佳方法,因为您只需遍历对象图一次。如果您在 Session 上设置 FlushMode.MANUAL ,您还应该能够随时修改对象图,而 Hibernate 不会做任何讨厌的事情。谨慎使用它,因为它是一种先进的技术。

于 2008-11-30T19:50:06.877 回答
1

没有使用它,但xstream-for-beans似乎适合(引用):

该项目提供了在以下方面增强 XStream 的映射器和转换器的实现:

  1. 序列化对象,因为它们被 getter 和 setter 公开。可用于字段的 XStream 功能应适用于为 getter/setter 属性定义的属性。
  2. 清理托管对象的序列化:自动省略不相关的字段和类信息。
  3. 处理“离线”字段和代理对象。

Converter不幸的是,作为闭源项目的一部分,我编写了一次自定义 XStream来处理这个问题。xstream-for-beans 处理相同的问题,非常值得一试。

我过去成功地使用了 Terracotta 的Pojoizer实用程序,但我认为它不再被维护了。

于 2012-05-22T07:50:39.000 回答