java.lang.IllegalStateException: No value for key [org.hibernate.impl.SessionFactoryImpl] with AOP

10,644

As @kriegaex said, the problem comes from the fact I'm using the same session to do the find and update operations.

Given that information, I use this following workaround (which works): I use two separate sessions, one for find and the other for update.

@Repository
public class FooDAOImpl implements FooDAO {
    private FooHibernateDaoSupport hibernateDaoSupport;

    public FooDAOImpl() {
        // Init DaoSupport
    }

    @Override
    public Foo findById(final Serializable fooId) {
        StatelessSession session = hibernateDaoSupport.getSessionFactory().openStatelessSession();
        Foo foo = (Foo) session.get(Foo.class, fooId);
        session.close;
        return foo;
    }

    @Override
    public Foo update(Foo foo) {
        getHibernateTemplate().update(entity);
        return entity;
    }
}

With this solution, there is no need to close the session in my advice code anymore.

NB: I'm opening a stateless session because in my project FooService.update also calls FooService.find in order to set some attributes, so I do not want to have the modifications in my advice code.

Share:
10,644
l-lin
Author by

l-lin

Passionate Senior Web Developer specializing in back end development, especially in Java and Spring Framework. Strong background and experience in all stages of the development cycle, from code, to build, to deploy in production. Coding best practice evangelist and passionate developer who loves all things in software and the web in general with particular interest in: Java, Go, Docker.

Updated on June 05, 2022

Comments

  • l-lin
    l-lin almost 2 years

    I'm having an error each time I update an entity using Hibernate. Here's my story:

    I have a service with an annotation @Transactional and is calling a DAO.update method.

    @Service
    @Transactional
    public class FooServiceImpl implements FooService {
        @Inject
        private FooDAO fooDAO;
    
        @Override
        public Foo update(Foo foo) {
           return fooDAO.update(foo);
        }
    
        @Override
        public Foo find(int fooId) {
           return fooDAO.findById(fooId);
        }
    }
    

    I have an AOP which catch the DAO.update in order to make some operations.

    @Aspect
    @Order(2)
    @Component
    public class FooTackerAspect {
       @Inject
       private FooService fooService;
    
       @Inject
       private SessionFactoryManager sessionFactoryManager;
    
       @Pointcut("execution(* com.foo.bar.FooService.update(..))")
       public void methodToTrack() {}
    
       @Around("methodToTrack")
       public Object track(final ProceedingJoinPoint joinPoint) throws Throwable {
          int fooId = fetchIdFromJoinPoint(joinPoint);
          Foo foo = fooService.find(fooId);
    
          // Do some operations
    
          // I close the session in order to avoid the exception
          // org.hibernate.NonUniqueObjectException: a different object with
          // the same identifier value was already associated with the session
          sessionFactoryManager.getSessionFactory(DataSource.FOO)
              .getCurrentSession().close();
    
          Object retVal = joinPoint.proceed();
          return retVal;
       }
    }
    

    However, after updating the entity (fooDAO.update(foo)), I get the following error:

    2056953 [http-bio-8080-exec-4] ERROR o.s.t.s.TransactionSynchronizationUtils - TransactionSynchronization.beforeCompletion threw exception 
    java.lang.IllegalStateException: No value for key [org.hibernate.impl.SessionFactoryImpl@762d6271] bound to thread [http-bio-8080-exec-4]
        at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:209) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.orm.hibernate3.SpringSessionSynchronization.beforeCompletion(SpringSessionSynchronization.java:193) ~[spring-orm-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCompletion(TransactionSynchronizationUtils.java:106) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCompletion(AbstractPlatformTransactionManager.java:938) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:739) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) [spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) [spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) [spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
        at com.sun.proxy.$Proxy112.update(Unknown Source) [$Proxy112.class:na]
    

    This error is not blocking (the update still goes through). But I want to correct this error. Do you have any idea how I can do that?

    I think the error comes from the fact I closed the session. But I have to close it in order to update the entity.