dpHibernate and Spring transactions

I’ve recently been getting my feet wet in Java, and starting integrating with dpHibernate to facilitate lazy loading across to Flex.

Here’s what my stack looks like:

  • Spring 2.5.6
  • Hibernate 3.3 (including annotations, and transaction management)

Trying to get dpHibernate wired in, I was getting lots of errors along the lines of the following:

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

 

The problem here is that using transaction management, things get a lot tighter on how and when you can get access to a hibernate session.  dpHibernate tries to get it’s session by essentially calling sessionManager.getCurrentSession();

However, as far as Spring’s transaction manager (which is wired into the SessionManager) is concerned, the thread which is executing has no session, and has no business trying to create one — specifically, outside of a transaction.

After spending several hours trying to work out how to sidestep Springs transaction management, I realized the trick was simply to wire dpHibernate closer to spring.  This is tricky, because dpHibernate is using an extension of the flex’s JavaAdapter, and exists completely outside of the Spring infrastructure.

HibernateSerializer makes a call to a dpHibernate object called SessionManager, which returns the current session outside of a valid Spring transaction.

So, I ditched the SessionManager completely, and replaced it with a good old fashionsed SessionFactory object, as follows:

    @Resource
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

The @Resource tag there tells Spring to give me a wired up sessionFactory instance.

I also decorated the HibernateSerializer with a @Transactional tag, so that Spring knows the context in which this will operate:

@Transactional(readOnly=true)
public class HibernateSerializer implements ISerializer
{

Now, if I add the HibernateSerializer as a bean, Spring knows to give it access to a sessionManager, and to do so in the context of an active transaction.

Add the bean declaration as follows:

<bean id="hibernateSerializerBean" class="net.digitalprimates.persistence.translators.hibernate.HibernateSerializer" />

Nearly there. Finally, I just need to tell dpHibernate to go and fetch this wired up Serializer from Spring, rather than instantiate it’s own. Inside SerializationFactory, I modified the getSerializer() call to read as follows:

    public static ISerializer getSerializer(String type)
    {
        if( HIBERNATESERIALIZER.equals(type) )
        {
            ServletContext ctx = FlexContext.getServletContext();
            WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(ctx);
            ISerializer serializer = (ISerializer) springContext.getBean("hibernateSerializerBean");
            if (serializer == null)
            {
                throw new RuntimeException("bean named hibernateSerializerBean not found");
            }
            return serializer;
        }

        throw new RuntimeException("unsupport serialization type: " +type);
    }

Note that I’ve hard coded the name of the bean here for simplicity sakes. Chances are you’ll want to paramaterize that.

That’s it! Now, calls that pass through dpHibernate happen with a Spring managed transactional session. Great!

 

Edit: Espen came up with a simpler alternative over on his blog — check it out : http://espenskogen.wordpress.com/2009/06/04/more-dphibernate/

Tagged , , ,

4 thoughts on “dpHibernate and Spring transactions

  1. Espen Skogen says:

    Hi Marty,

    I’ve written a blog post on this exact issue, which resolves the problem without having to ditch session manager.

    Have a look when you have a moment:

    http://espenskogen.wordpress.com

  2. Ryan says:

    Thanks for the post!

    Can you tell me what exactly I need to replace in HibernateSerializer?

    Do I change:

    this.sessionManager = new SessionManager(sessionFactoryClazz, getSessionMethod);

    • Marty Pitt says:

      Hi Ryan

      It’s been a little while since I edited the serializer, and there’s a few other experimental changes in there, so I may miss something (unfortunately, I didn’t commit the version that didn’t work .. so my svn history doesn’t help)– but give this a try.

      I added the @Transactional annotation to the class:
      @Transactional(readOnly=true)
      public class HibernateSerializer implements ISerializer

      Made the sessionFactory a resource, and gave it getters and setters:
      @Resource
      private SessionFactory sessionFactory;

      public void setSessionFactory(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
      }

      public SessionFactory getSessionFactory() {
      return sessionFactory;
      }

      Then in getCollectionProxies() modified the beginning of the method to read:

      EventSource session = (EventSource) getSessionFactory().getCurrentSession();

      The actual sessionManager variable got trashed – it’s no longer needed.

      Hope that helps

      Marty

Leave a comment