users@jersey.java.net

Re: Integrating Jersey & Hibernate

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 22 Apr 2008 11:22:04 +0200

On Apr 21, 2008, at 6:34 PM, Martin Probst wrote:

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

Thanks for sharing, this is very interesting stuff. Let us know if
you blog about it.


> 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()).
>

Correct. You could do this in the anonymous injectable class:

   return wa.getComponentProvider();


> 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.
>

Changed in the trunk. I have a habit of making things final unless
otherwise required!


> 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.
>


You said in another email:

> The problem is that I want "BookResource" to directly map to a
> persistent class, so I can't have it being created by Jersey - it
> needs to be loaded by Hibernate. Maybe I can hook into the creation
> of the resource (by having my own ComponentProvider) and access the
> path parameter to load the instance from persistence?
>

I presume you manage to solve that with what you did above?

Paul.