Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to autowire a Hibernate Session in a Spring Transaction JUnit test

This question is similar to a previous one. I am trying to @Autowire a Hibernate Session in one of my Spring-JUnit-Transactional tests but I am getting this exception:

java.lang.IllegalStateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional ...

Here is my JUnit class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager")
@Transactional
public class MyTest {
    @Qualifier("session")
    @Autowired
    private Session session;

    @Test
    public void testSomething() {
        session.get(User.class, "[email protected]");
    }
}

Every works fine if I @Autowire a SessionFactory and get my Session programmatically (instead of defining it in the Spring XML) like so:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager")
@Transactional
public class MyTest{    
    @Qualifier("sessionFactory")
    @Autowired
    private SessionFactory sessionFactory;

    @Test
    public void testSomething() {
    Session session = SessionFactoryUtils.getSession(sessionFactory, false);
        session.get(User.class, "[email protected]");
    }
}

I can, however, get my original example to work if I define my Session in my Spring XML with <aop:scoped-proxy /> like so:

<?xml version="1.0" encoding="UTF-8"?>

<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        ">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        ...
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation"><value>classpath:/hibernate.cfg.xml</value></property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="session" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession" scope="prototype">
        <constructor-arg ref="sessionFactory" />
        <constructor-arg value="false" />
        <!-- This is seems to be needed to get rid of the 'No Hibernate Session' error' -->
        <aop:scoped-proxy />
    </bean>
</beans>

My question is: Why is <aop:scoped-proxy /> needed given that there should only one thread-bounded transaction context in my unit test? What is the proper way to define my Hibernate Session bean?

like image 638
0sumgain Avatar asked Sep 30 '09 21:09

0sumgain


1 Answers

SessionFactoryUtils.getSession() is as good as any other way of getting the Session. It does the same thing HibernateDaoSupport.getSession() would do.

The reason you need scoped-proxy is because of timing. Without the scoped-proxy it seems that it is injecting the Session before the test begins and thus before the transaction begins and so you get the errors.

By adding the scoped-proxy it proxies the Session and injects that so it does not inject the actual session upfront (before the transaction starts) but only fetches it and makes calls on it once the test is running, when it actually needs to make a call against it.

like image 144
Michael Wiles Avatar answered Sep 25 '22 12:09

Michael Wiles