Thursday, July 11, 2013

Using GWT and Hibernate (JPA)

This article discusses an option to use Hibernate and JPA entities directly in a GWT application. It uses a small project JpaCloner which can be found on the github https://github.com/nociar/jpa-cloner. The Google Web Toolkit  framework itself declares support for JPA entities. It means that the GWT is able to:
  • Translate JPA entities to Javascript.
  • Serialize JPA entities in GWT-RPC calls.
So there should be no problem to use your JPA domain model direcly in the client code (as JPA entities are translatable). But just try to return a JPA entity from your GWT-RPC calls. The call will end with a SerializationException. There are two problems related to the serialization of Hibernate entities by GWT. Both problems are discussed in following paragraphs.

Javassist proxies

The first probem of the serialization is caused by the type of Hibernate entities. Hibernate uses javassist proxy classes which are not known to the GWT during the compilation time. GWT is also not able to serialize lazy collections implemented by Hibernate. So the declared support of JPA by GWT seems to be useless when using Hibernate. But the situation is not as bad as it seems. :-) The thing to be done is very simple - just replace the hibernate proxies by raw JPA classes and lazy collection by standard java.util collections. The good news is that you are not forced to do it manually. You can use a small project JpaCloner for all of this, the usage is extremely simple, for example:

/** Return an instance of Company by ID. */
public void Company getCompany(long id) {
    Company entity = entityDAO.getEntity(id);
    return JpaCloner.clone(entity);
}

Please note that the JpaCloner creates a cloned entity of the raw JPA class - this means that you can easily get rid of Hibernate proxy classes.

Serialization depth

The second problem of the serialization is related to ORM technologies in general. There must be somehow defined an object graph which should be serialized. GWT-RPC serializes all properties of a returned object . In case of bidirectional JPA mappings it would easily serialize the whole DB which is of course not acceptable. Only a subset of neighboring entities should be serialized (entity subgraph). This can be again accomplished by the JpaCloner's clone() methods. Additional parameters can specify property paths and the depth of cloning. The following example shows how to serialize a company with a hierarchical department structure:

/** 
 * Return an instance of Company by ID. The instance 
 * will contain also all departments and employees.
 */
public void Company getCompanyWithDepartments(long id) {
    Company entity = entityDAO.getEntity(id);
    return JpaCloner.clone(entity, "department+.employees");
}

Please note that the cloning should be done in a transaction scope to prevent lazy initialization exception thrown by Hibernate. 

Conclusion

So what to say at the end? Just that the usage of JPA entities in your GWT projects can be easy and straightforward. There is no need to use sophisticated frameworks, nor to use redundant DTOs and Dozer which mostly mirror related JPA entities. The JpaCloner does not have any dependencies and is completely non-invasive. This is not true for projects like hibernate4gwt (now Gilead) which forces you to extend your domain model entities from the LightEntity class.

Happy coding :-)