People have been asking in the comments to my post on XStream about how to properly integrate Hibernate with XStream, as there are few pieces of puzzle that don't necessarily fit together perfectly. I answered in the comments, but Blogger annoyingly doesn't allow a lot of formatting in comments, so I decided to write a separate follow-up post; here it goes.
- First of all, I use Hibernate 2. I know, it's old, but it does the work and I won't fix it unless it is broken. I expect most of the advice will also apply to Hibernate 3.
- I'm aliasing all classes using
XStream.alias()
. Reason being that on the server side, some data model classes are actually subclassed for additional (although non-Hibernate) related functionality. You might or might not need this. - This is however essential: We need to ensure that XStream will treat Hibernate lists, sets, and maps as Java lists, sets, and maps. I believe this is what helps avoid the infamous "com.thoughtworks.xstream.converters.ConversionException: Cannot handle CGLIB enhanced proxies with multiple callbacks..." problem. There are three things that need to be done:
- use
Xstream.addDefaultImplementation()
to tell XStream to treat all Hibernate-enhanced collection classes as plain Java collections:xstream.addDefaultImplementation(
net.sf.hibernate.collection.List.class, java.util.List.class);
xstream.addDefaultImplementation(
net.sf.hibernate.collection.Map.class, java.util.Map.class);
xstream.addDefaultImplementation(
net.sf.hibernate.collection.Set.class, java.util.Set.class); - Finally, in order for XStream to actually handle these collections I needed to define and register some custom converters that are able to handle Hibernate collections as Java collections:
Mapper mapper = xstream.getMapper();
These custom converter classes are rather trivial, here are their definitions. All they really do is extend the XStream built-in collection and map converters, and declare their ability to handle Hibernate lists, sets, and maps:
xstream.registerConverter(new HibernateCollectionConverter(mapper));
xstream.registerConverter(new HibernateMapConverter(mapper));import net.sf.hibernate.collection.List;
and
import net.sf.hibernate.collection.Set;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.mapper.Mapper;
class HibernateCollectionConverter extends CollectionConverter {
HibernateCollectionConverter(Mapper mapper) {
super(mapper);
}
public boolean canConvert(Class type) {
return super.canConvert(type) || type == List.class || type == Set.class;
}
}import net.sf.hibernate.collection.Map;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.mapper.Mapper;
class HibernateMapConverter extends MapConverter {
HibernateMapConverter(Mapper mapper) {
super(mapper);
}
public boolean canConvert(Class type) {
return super.canConvert(type) || type == Map.class;
}
}
- use
That's all I did and it eliminated all of my Hibernate+XStream problems - hope it will also help you.