Monday, May 23, 2011

Detaching Hibernate Objects to pass to GWT

One thing we encountered pretty quickly when we started our GWT work was the fact that you can't serialize objects over the wire from server to GWT client if those objects were obtained via a Hibernate/JPA entity manager.

If you've ever worked with Hibernate/JPA, you'll know that when you get back entity POJOs whose fields are not loaded (i.e. marked for lazy loading and you didn't ask for the data to be loaded), your entity POJO instance will have Hibernate proxies where you would expect a "null" object to be (this is to allow you to load the data later, if your object is still attached to the entity manager session).

Having these proxies even after leaving a JPA entity manager session is a problem in the GWT world because the GWT client sitting in your browser doesn't have Hibernate classes available to it! Trying to send these entity POJO instances that have references to Hibernate proxies causes serialization errors and your GWT client will fail to operate properly.

This is a known issue and is discussed here.

We pretty quickly decided against using DTOs. As that page above mentioned, "if you have many Hibernate objects that need to be translated, the DTO / copy method creation process can be quite a hassle". We have a lot of domain objects that are used server side in RHQ. There was no reason why we shouldn't be able to reuse our domain objects both server side and client side - introducing DTOs just so we could workaround this serialization issue seemed ill-advised. It would have just added bloat and unnecessary complexity.

I can't remember how mature the Gilead project was at the time we started our GWT work, or maybe we just didn't realize it existed. Gilead does require you to have your domain objects and server side impl classes extend certain Java classes (LightEntity for example), so it has a slight downside that it requires you to modify all your domain objects. In any event, we do not use Gilead to do this detaching of hibernate proxies.

RHQ's solution was to write our own "Hibernate Detach Utility". This is a single static utility that you use to process your objects just prior to sending them over the wire to your GWT client. Essentially it scrubs your object of all Hibernate proxies, cleaning it such that it can be serialized over the wire successfully.

We also used this when we originally developed a web services interface to the RHQ remote API.

Here is the HibernateDetachUtility source code in case you are interested in seeing how we do it - maybe you could use this in your own GWT/Hibernate application. I think it is reuseable - not much custom RHQ stuff is going on in here.

2 comments:

  1. Can You please write a simple How To.. so we can use the functionality?

    ReplyDelete
  2. Sure teneke. Just to summarize - the purpose here is to support the use-case where you have server-side code that is about to send an object (or collection of objects) to a remote client that doesn't have Hibernate in its classpath (such as a GWT client running in a browser). In such a case, you wouldn't even be able to deserialize the objects on the remote client, because it couldn't load any Hibernate proxy classes that are in the objects.

    To solve this, your server-side code can call this to "scrub" your object(s) of all Hibernate proxy objects and effectively null out all fields that weren't loaded by Hibernate:

    HibernateDetachUtility.nullOutUninitializedFields(object, HibernateDetachUtility.SerializationType.SERIALIZATION);

    At this point, "object" has been scrubbed and you can send it on its way to the client - any fields not loaded by Hibernate will appear null (you won't get LazyInitializeExceptions because the Hibernate proxy is gone). It's really that simple.

    ReplyDelete