users@jersey.java.net

Re: Integrating Jersey & Hibernate

From: Martin Probst <mail_at_martin-probst.com>
Date: Mon, 21 Apr 2008 18:34:29 +0200

Hi,

I found a solution for my problem and thought I should share:

I've extended ServletContainer and overridden the configure & initiate
method:

     @Override
     protected void initiate(ResourceConfig rc, WebApplication wa) {
       super.initiate(rc, wa);
       persistence = new Persistence(wa.getComponentProvider());
       provider = wa.getComponentProvider();
     }

     @Override
     protected void configure(ServletConfig sc, ResourceConfig rc,
final WebApplication wa) {
       super.configure(sc, rc, wa);

       wa.addInjectable(Session.class, new Injectable<Context,
Session>() {
         @Override
         public Class<Context> getAnnotationClass() {
           return Context.class;
         }

         @Override
         public Session getInjectableValue(Context a) {
           return persistence.getSession();
         }
       });

       wa.addInjectable(ComponentProvider.class, new
Injectable<Context, ComponentProvider>() {
         @Override
         public Class<Context> getAnnotationClass() {
           return Context.class;
         }

         @Override
         public ComponentProvider getInjectableValue(Context a) {
           return provider;
         }
       });
     }

Configure is called first and sets up the injectors, after which
initiate is called that constructs the persistence handler and safes
the provider for later injection (getComponentProvider returns null
until after initiate()).

Persistence is my own transaction manager. It extends Hibernate's
EmptyInterceptor, which provides hooks into the life cycle of
persistent objects. It only overrides the onLoad method, using the
ComponentProvider from the WebApplication to wire up fields:

   @Override
   public boolean onLoad(Object entity, Serializable id, Object[]
state, String[] propertyNames,
       Type[] types) {
     provider.inject(entity);
     return super.onLoad(entity, id, state, propertyNames, types);
   }

Apart from that it also opens sessions and provides them for injection
via the getSession() method used above. Resource classes can simply
declare a @Context Session session; field to get access to the
persistence layer and @Context ComponentProvider provider; to get to
the ComponentProvider, which they use to create new instances of
resources.

One slightly ugly thing: I had to both subclass and wrap Jersey's
ServletContainer. I need to wrap it because service() is marked as
final and I have to implement my own service() to open and close a
transaction with my persistence class:

   @Override
   public void service(HttpServletRequest req, HttpServletResponse
resp) throws ServletException,
       IOException {
     String method = req.getMethod();
     boolean readonly = "GET".equals(method) || "HEAD".equals(method);
     try {
       persistence.open(readonly);
       container.service(req, resp);
       if (readonly) {
         persistence.rollback();
       } else {
         persistence.commit();
       }
     } catch (RuntimeException e) {
       persistence.rollback();
       throw e;
     }
   }

@Paul: is there a reason why service() is final? If not, I could
simply extend ServletContainer, no wrapping necessary.

The endeffect is that I now have a set of resource classes that are
directly persisted, i.e., no additional layer necessary. The entry
points into the resource hierarchy are non-persistent classes that
represent collections of sub-resources. Resource creation (after POST
or PUT) happens through Jersey's IoC component.

Hope this helps someone,
Martin