lysergicjava

oh, technology

Menu Close

Knocking back Hibernate (cleanse your objects!)

Sometimes, you realize you’ve stumbled into a hard problem, and you start to feel bad.  Then you search around for a while and see that other people, some of them quite smart, have the same problem.  Then you feel better.

This happened to me lately: I encountered the dreaded Hibernate cruft.

As others have discovered, Hibernate’s slick trickery at runtime can cause headaches.  Specifically, when Hibernate wraps a CGLib proxy around your POJO and you send said proxy off to XStream for serialization to XML, you end up serializing stuff you didn’t intend.

See, XStream, slick as it is, depends heavily on reflection.  Commonly, you annotate your POJOs so XStream knows exactly how to serialize them.  But if Hibernate has substituted a proxy with additional fields, or swapped out a java.util.list for a org.hibernate.PersistentBag, XStream just shrugs and tries its best… without your carefully thought-through annotations.

So, what you really need is to cleanse an object fetched from a Hibernate session of all Hibernate artifacts.  There’s been much gnashing of teeth over lazy fetching and incomplete object graphs, but all it boils down to is that you’ve got to make sure your objects are in a good-enough state to serialize before you try.  Either make the calls to fetch the desired linked objects, or live with the consequences.

Anyway, cleansing the object: turns out it’s more work than I thought originally.  Well, there’s really two approaches.  The first approach is to just create a new POJO and traverse the proxy, explicitly setting the POJO values you want.  A factory method could do this.  And for a small number of POJOs, with just a small handful of fields and/or very shallow graphs, this would be fine.  But…

I’ve got a gangload of POJOs, with complex and deep graphs.  I want more of a once-and-for-all solution.  I opted for reflection after reading this post about the performance of reflection in deep cloning.

Here’s what I’m doing: I’ve taken Matt Hick’s approach of deep cloning using reflection, and added methods that filter out Hibernate specific stuff and swap back in what you started with.  A key part:

private static Map<Class, Class> hibernateCollectionsMap = new HashMap<Class, Class>();
static
{
   hibernateCollectionsMap.put(PersistentBag.class, ArrayList.class);
   hibernateCollectionsMap.put(PersistentList.class, ArrayList.class);
   hibernateCollectionsMap.put(PersistentMap.class, HashMap.class);
   hibernateCollectionsMap.put(PersistentSet.class, HashSet.class);
   hibernateCollectionsMap.put(PersistentSortedMap.class, SortedMap.class);
   hibernateCollectionsMap.put(PersistentSortedSet.class, SortedSet.class);
}

…which is used to map Hibernate proxy collections back to the java collections they once were.  I also turn java.sql.Timestamps back into java.util.Dates.  You can just kill that if you wanted sql Timestamps in the first place.

This whole exercise got me thinking.  With more work I could craft an entire toolchain, complete with XML config files and the like, that would allow anyone, anywhere to sanitize a Hibernate-fetch object graph.  But this would be total overkill, and anyway, at some point Hibernate will probably do this for you.

I decided to keep it simple, and handle the vast majority of the cases I’m going to encounter, and let the rest of the world take care of itself.  Feel free to take the code and tweak it to your heart’s content.  Special thanks to Matt Hicks for his deep-clone approach and his ClassUtilities which I made use of.

Download my code here.