I've been facing this issue where, the hibernate objects on serialization produces unexpect xmls containing all the instrumented code from Hibernate.
We did some cleaning of the object before serializing the object.
But, is there a standard option available to serialize the object directly?
I've not used XStream before, but I have serialized Hibernate-managed entities. It isn't fun.
There are two big issues:
The former is obvious - you need the actual data to serialize. The latter is less so - any one-to-many relationships you declare against collection interfaces (eg: Set<T>
) will get plugged by Hibernate's own (unserializable!) collection implementations. This may well be where Hibernate's classes are bleeding into your objects.
I ended up writing reflective code (actually introspective) that did this:
Note that step 2 is important - if you replace the collections prior to closing the session, Hibernate will just put its own collections right back upon close...
Edit: @cliff.meyers spotted a detail of the implementation I forgot to mention: if you do this, you need to limit object graph walking only to your own entities, and watch for circular reference paths (eg: by caching references to objects you've already walked).
I've came up with somewhat sufficient solution. In my application, only PersistentSets were messing up XML generated by XStream. So I have added another Converter to XStream (which runs with open Hibernate Session and live objects):
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);
The serialized XML looks like below:
<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>
In my case, the class attribute was not important, so I have ignored its value. You can of course tinker with it.
XStream now provides a separate module/jar to handle Hibernate collections. Please see XStream's FAQ for an example.
There is some info on this (and sample code) over at the Codehaus JIRA:
http://jira.codehaus.org/browse/XSTR-226
We wrote some tools to work around this sort of issue for a bunch of other remoting implementations (Axis 1, Blaze DS, etc). What we did is very similar to Dan's solution, although we added the ability to declare which object paths to walk and which to "snip" because in many situations we were not interested in all the data; it also would have led to serious issues with the "n+1 selects" problem happening thousands of times! :) I think implementing an XStream converter would be the optimal approach since you'd only have to walk the object graph once. If you set FlushMode.MANUAL on your Session you should also be able to modify the object graph as you go without Hibernate doing anything nasty. Use this with caution though as it's a somewhat advanced technique.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With