Using JPAContainer with Hibernate

Hibernate needs special handling in some cases.

Lazy loading

In order for lazy loading to work automatically, an entity must be attached to an entity manager. Unfortunately, Hibernate can not keep entity managers for long without problems. To work around the problem, you need to use a special lazy loading delegate for Hibernate.

JPAContainer entity providers handle lazy loading in delegates defined by the LazyLoadingDelegate interface. The default implementation for Hibernate is defined in HibernateLazyLoadingDelegate. You can instantiate one and use it in an entity provider with setLazyLoadingDelegate().

The default implementation works so that whenever a lazy property is accessed through the Vaadin Property interface, the value is retrieved with a separate (JPA Criteria API) query using the currently active entity manager. The value is then manually attached to the entity instance, which is detached from the entity manager. If this default implementation is not good enough, you may need to make your own implementation.

The EntityManager-Per-Request pattern

One issue with Hibernate is that it is designed for short-lived sessions, but the lifetime of an entity manager is normally roughly that of a user session. The problem is that if an error occurs in a session or an entity manager, the manager becomes unuseable. This causes big problems with long-lived sessions that would work fine with EclipseLink.

The recommended solution is to use the EntityManager-per-Request pattern. It is highly recommended always when using Hibernate.

An entity manager can only be open during the request-response cycle of the Vaadin servlet, so that one is created at the beginning of the request and closed at the end.

Storing an Entity Manager

You first need to implement an EntityManagerProvider that returns a stored EntityManager with getEntityManager(). The entity manager must be stored in a ThreadLocal variable.

  1. public class LazyHibernateEntityManagerProvider
  2. implements EntityManagerProvider {
  3. private static ThreadLocal<EntityManager>
  4. entityManagerThreadLocal =
  5. new ThreadLocal<EntityManager>();
  6. @Override
  7. public EntityManager getEntityManager() {
  8. return entityManagerThreadLocal.get();
  9. }
  10. public static void setCurrentEntityManager(
  11. EntityManager em) {
  12. entityManagerThreadLocal.set(em);
  13. }
  14. }

You need to create and store the per-request instance at the beginning of each request with setCurrentEntityManager() and clear it at the end by setting it as null.

Creating Entity Managers in a Servlet Filter

You can create the entity managers for each request either by extending VaadinServlet and overriding the service() method or by implementing a servlet filter. In the following, we describe how to implement a servlet filter to do the task, but overriding the servlet could be even easier.

  1. public class LazyHibernateServletFilter
  2. implements Filter {
  3. private EntityManagerFactory entityManagerFactory;
  4. @Override
  5. public void init(FilterConfig filterConfig)
  6. throws ServletException {
  7. entityManagerFactory = Persistence
  8. .createEntityManagerFactory("lazyhibernate");
  9. }
  10. @Override
  11. public void doFilter(ServletRequest servletRequest,
  12. ServletResponse servletResponse,
  13. FilterChain filterChain)
  14. throws IOException, ServletException {
  15. try {
  16. // Create and set the entity manager
  17. LazyHibernateEntityManagerProvider
  18. .setCurrentEntityManager(
  19. entityManagerFactory
  20. .createEntityManager());
  21. // Handle the request
  22. filterChain.doFilter(servletRequest,
  23. servletResponse);
  24. } finally {
  25. // Reset the entity manager
  26. LazyHibernateEntityManagerProvider
  27. .setCurrentEntityManager(null);
  28. }
  29. }
  30. @Override
  31. public void destroy() {
  32. entityManagerFactory = null;
  33. }
  34. }

You need to define the servlet filter in the web.xml deployment descriptor as follows:

  1. <filter>
  2. <filter-name>LazyHibernateServletFilter</filter-name>
  3. <filter-class>com.example.LazyHibernateServletFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>LazyHibernateServletFilter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>

The url-pattern must match the pattern for your Vaadin servlet.

Joins in Hibernate vs EclipseLink

EclipseLink supports implicit joins, while Hibernate requires explicit joins. In SQL terms, an explicit join is a “ FROM a INNER JOIN b ON a.bid = b.id” expression, while an implicit join is done in a WHERE clause, such as: “ FROM a,b WHERE a.bid = b.id”.

In a JPAContainer filter with EclipseLink, an implicit join would have form:

  1. new Equal("skills.skill", s)

In Hibernate you would need to use JoinFilter for the explicit join:

  1. new JoinFilter("skills", new Equal("skill", s))