Announcement Announcement Module
Collapse
No announcement yet.
NullPointerException in HibernateTemplate with proxy factory Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • NullPointerException in HibernateTemplate with proxy factory

    Hi,

    I'm getting NullPointerException from HibernateTemplate when using TransactionProxyFactoryBean. If I access my bean directly, bypassing the proxy, everything works fine. Basically I'm doing the following from a servlet (simplified a lot):

    1: // Start a JTA transaction (we need XA)
    2: userTransaction.begin();
    3: myDao.getHibernateTemplate().load(class1, id);
    4: // Start a new transaction (PROPAGATION_REQUIRES_NEW)
    5: myProxiedDao.getHibernateTemplate().save(foo);
    6: userTransaction.commit(); // or rollback

    Both Daos are using the same LocalSessionFactoryBean. It does not make any difference if I specify PROPAGATION_REQUIRED instead of PROPAGATION_REQUIRES_NEW.

    If I change the order of lines 3 and 5, everything works!? Unfortunately the business logic does not allow changing the order.

    I have spent a couple of days debugging Spring's internals and it seems that when line 5 is executed, a SessionHolder is found in the current thread and its isSynchronizedWithTransaction() is true but SessionHolder.sessionMap does not contain a default session. As a result, the following condition in SessionFactoryUtils.getSession evaluates to false and a null Session is returned, which later causes a NullPointerException in HibernateTemplate:

    if (allowSynchronization && !sessionHolder.isSynchronizedWithTransaction()) {
    ...
    }
    return sessionHolder.getSession();

    We are using Spring 1.1.3, Hibernate 2.1.7 and WebLogic 8.1 SP4. Unfortunately our schedule does not allow upgrading any of these since then full regression testing would be needed, for which we don't have time.

    Am I trying something that is not supported? Or has been fixed in a later Spring release? What should I try next? Excerpts from my configuration below.

    I'd really appreciate if someone could shed some light on this. Thanks!

    Br,
    Timo

    Code:
    <bean id="localSessionFactory" parent="abstractLocalSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
       <property name="hibernateProperties">
           <props>
               <prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
               <prop key="hibernate.show_sql">false</prop>
               <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
               <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.Provider</prop>
               <prop key="hibernate.cache.region_prefix">epm</prop>
               <prop key="hibernate.query.substitutions">true 1, false 0</prop>
               <prop key="hibernate.transaction.factory_class">
                 net.sf.hibernate.transaction.JTATransactionFactory
               </prop>
               <prop key="hibernate.transaction.manager_lookup_class">
                 net.sf.hibernate.transaction.WeblogicTransactionManagerLookup
               </prop>
           </props>
       </property>
       <property name="dataSource">
           <ref bean="localDataSource"/>
       </property>
    </bean>
    
    <bean id="importLoggingServiceTarget" class="com.mycompany.epm.service.ImportLoggingServiceImpl">
        <property name="sessionFactory">
            <ref bean="localSessionFactory"/>
        </property>
    </bean>
    
    <bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>
    
    <bean id="importLoggingService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="txManager"/>
        </property>
        <property name="target">
            <ref bean="importLoggingServiceTarget"/>
        </property>
        <property name="proxyInterfaces">
            <value>com.mycompany.epm.service.ImportLoggingService</value>
        </property>
        <property name="transactionAttributes">
            <props>
    <!-- The following rule applies on line 5 above -->
              <prop key="isolated*">PROPAGATION_REQUIRES_NEW</prop>
              <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
              <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
    And here's the exception stack trace that Andreas asked for:

    Code:
    java.lang.NullPointerException
    	at org.springframework.orm.hibernate.HibernateTemplate.checkWriteOperationAllowed&#40;HibernateTemplate.java&#58;870&#41;
    	at org.springframework.orm.hibernate.HibernateTemplate$12.doInHibernate&#40;HibernateTemplate.java&#58;385&#41;
    	at org.springframework.orm.hibernate.HibernateTemplate.execute&#40;HibernateTemplate.java&#58;243&#41;
    	at org.springframework.orm.hibernate.HibernateTemplate.save&#40;HibernateTemplate.java&#58;383&#41;
    	at com.mycompany.epm.service.ImportLoggingServiceImpl.doSave&#40;ImportLoggingServiceImpl.java&#58;55&#41;
    	at com.mycompany.epm.service.ImportLoggingServiceImpl.save&#40;ImportLoggingServiceImpl.java&#58;34&#41;
    	at sun.reflect.NativeMethodAccessorImpl.invoke0&#40;Native Method&#41;
    	at sun.reflect.NativeMethodAccessorImpl.invoke&#40;NativeMethodAccessorImpl.java&#58;39&#41;
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke&#40;DelegatingMethodAccessorImpl.java&#58;25&#41;
    	at java.lang.reflect.Method.invoke&#40;Method.java&#58;324&#41;
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection&#40;AopUtils.java&#58;296&#41;
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint&#40;ReflectiveMethodInvocation.java&#58;155&#41;
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed&#40;ReflectiveMethodInvocation.java&#58;122&#41;
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke&#40;TransactionInterceptor.java&#58;56&#41;
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed&#40;ReflectiveMethodInvocation.java&#58;144&#41;
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke&#40;JdkDynamicAopProxy.java&#58;174&#41;
    	at $Proxy8.save&#40;Unknown Source&#41;
    	at com.mycompany.epm.application.importing.sap.receival.MessageReceiver.logMessageToDB&#40;MessageReceiver.java&#58;222&#41;
    	at com.mycompany.epm.application.importing.sap.receival.MessageReceiver.handleMessage&#40;MessageReceiver.java&#58;137&#41;
    	at com.mycompany.epm.application.actions.saprtitesting.PostSapRtiMessageAction.execute&#40;PostSapRtiMessageAction.java&#58;73&#41;
    	at org.apache.struts.action.RequestProcessor.processActionPerform&#40;RequestProcessor.java&#58;484&#41;
    	at org.apache.struts.action.RequestProcessor.process&#40;RequestProcessor.java&#58;274&#41;
    	at org.apache.struts.action.ActionServlet.process&#40;ActionServlet.java&#58;1482&#41;
    	at org.apache.struts.action.ActionServlet.doPost&#40;ActionServlet.java&#58;525&#41;
    	at javax.servlet.http.HttpServlet.service&#40;HttpServlet.java&#58;760&#41;
    	at javax.servlet.http.HttpServlet.service&#40;HttpServlet.java&#58;853&#41;
    	at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run&#40;ServletStubImpl.java&#58;996&#41;
    	at weblogic.servlet.internal.ServletStubImpl.invokeServlet&#40;ServletStubImpl.java&#58;419&#41;
    	at weblogic.servlet.internal.TailFilter.doFilter&#40;TailFilter.java&#58;28&#41;
    	at weblogic.servlet.internal.FilterChainImpl.doFilter&#40;FilterChainImpl.java&#58;27&#41;
    	at com.mycompany.epm.infra.filter.OpenSessionsInViewFilter.doFilterInternal&#40;OpenSessionsInViewFilter.java&#58;53&#41;
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter&#40;OncePerRequestFilter.java&#58;76&#41;
    	at weblogic.servlet.internal.FilterChainImpl.doFilter&#40;FilterChainImpl.java&#58;27&#41;
    	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run&#40;WebAppServletContext.java&#58;6458&#41;
    	at weblogic.security.acl.internal.AuthenticatedSubject.doAs&#40;AuthenticatedSubject.java&#58;321&#41;
    	at weblogic.security.service.SecurityManager.runAs&#40;SecurityManager.java&#58;118&#41;
    	at weblogic.servlet.internal.WebAppServletContext.invokeServlet&#40;WebAppServletContext.java&#58;3661&#41;
    	at weblogic.servlet.internal.ServletRequestImpl.execute&#40;ServletRequestImpl.java&#58;2630&#41;
    	at weblogic.kernel.ExecuteThread.execute&#40;ExecuteThread.java&#58;219&#41;
    	at weblogic.kernel.ExecuteThread.run&#40;ExecuteThread.java&#58;178&#41;
    The $Proxy8.save line is the line 5 of my simplified code shown above.

  • #2
    A stacktrace could be helpful for figuring out the problem.

    Regards,
    Andreas

    Comment


    • #3
      Stack trace added

      Hi Andreas,

      I added the stack trace at the end of my original message. As you may notice, the stack trace contains OpenSessionsInViewFilter which is a modified version of Spring's OpenSessionInViewFilter. The difference is that it opens sessions to four data sources rather than to one. I don't know whether it has anything to do with the problem. Although not visible in the stack trace, I actually close the sessions opened by the filter before starting my UserTransaction. If I don't close them, everything seems to work but the save operation done on line 5 does not have any effect on the database if the UserTransaction is rolled back. Any clue why? Shouldn't the new transaction started with PROPAGATION_REQUIRES_NEW be isolated from the UserTransaction which is rolled back? Maybe the load operation on line 3 binds the pre-opened sessions to the UserTransaction and the save operation on line 5 then uses the same sessions, thus actually doing its work under the UserTransaction rather than in the newly started transaction???

      I would love to get rid of the whole filter since it is not needed in this case but unfortunately it is part of the framework I have to live with.

      Br,
      Timo

      Comment


      • #4
        Re: Stack trace added

        I would say, that the session is coupled to the UserTransaction. Therefore nulling it out will cause problems (as you have seen). So if you rollback the UserTransaction, you will also rollback the session, since these are coupled. As of REQUIRES_NEW: Normally an existing transaction should be suspended (if supported!) while a new one will be executed. However I do not know how your explicit session handling (nulling out) might interfere here.

        Maybe some more insight might be found
        here

        Regards,
        Andreas

        Comment


        • #5
          Nulling out the session

          If nulling the session is the problem, I don't understand why I don't get a NullPointerException when omitting the TransactionProxyFactoryBean. Nor do I understand why the load operation on line 3 always works, despite nulling the session.

          Do you know what Spring/HibernateTemplate should actually do with the Hibernate sessions if I start a new transaction using TransactionProxyFactoryBean and PROPAGATION_REQUIRES_NEW? Should Spring bind the current thread's Hibernate session to the new transaction for the duration of the transaction or should it start a new Hibernate session and bind it to the newly created transaction??? I thought it should do the latter but obviously it doesn't. Does it mean that I have to start a new session manually? I though that HibernateTemplate takes care of opening and closing sessions. I have been reading Spring's documentation but haven't really found clear answers to these.

          I remember reading somewhere in Spring's documentation that WebLogic 8.1 supports suspending a transaction, especially if you use WebLogic specific JTA transaction manager, as I do.

          Br,
          Timo

          Comment


          • #6
            Re: Nulling out the session

            Originally posted by tsillan
            If nulling the session is the problem, I don't understand why I don't get a NullPointerException when omitting the TransactionProxyFactoryBean.
            Afaik, HibernateTemplate creates a new session if none exists (this behavior can be configured by a property).

            As of problems concerning REQUIRES_NEW I cannot tell, because I usually use REQUIRED and had no problems there. Maybe someone else can provide more insight here.

            Originally posted by tsillan
            Does it mean that I have to start a new session manually? I though that HibernateTemplate takes care of opening and closing sessions. I have been reading Spring's documentation but haven't really found clear answers to these.
            You should not meddle with session management, as Spring does indeed handle these issues.

            Regards,
            Andreas

            Comment


            • #7
              As of problems concerning REQUIRES_NEW I cannot tell, because I usually use REQUIRED and had no problems there. Maybe someone else can provide more insight here.
              It does not really matter whether I use REQUIRED or REQUIRES_NEW. I get NullpointerException if line 5 (save) is executed after line 3 (load) _and_ TransactionProxyFactoryBean is used on line 5. I don't get any problems, even if the session is nulled out, when I either (a) switch lines 3 and 5 or (b) don't use TransactionProxyFactoryBean. Does not make any sense to me.

              Maybe I should try with the latest Spring, even if we cannot upgrade Spring in the forthcoming release of our application.

              Thanks for trying to help!

              Timo

              Comment


              • #8
                Problem solved by switching to SPring 1.2.3

                This problem was solved by switching to Spring 1.2.3. Obviously this was a defect in Spring 1.1.3.

                Comment

                Working...
                X