Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate4 configuration without xml files - sessionFactory is null

Tags:

java

hibernate

I have a web project working with Spring3 and Hibernate4 and now I want to test the DAOs without using the xml files. To do so I have created a class that creates a LocalSessionFactoryBean with the data contained in the application's xml file and a simple test class.

However, the sessionFactory returned by localSessionFactoryBean.getObject() is null. I have been looking at some examples like this and they have the same problem when I modify them to run without Spring. Do you have any idea?

This is the code that prepares the sessionFactory:

@Configuration
@Transactional
@EnableTransactionManagement
@ComponentScan({ "com.company" })
public class HibernateInitializator {

    public SessionFactory getSessionFactory() {

        Properties hibernateProperties = getHibernateProperties();
        DataSource dataSource = getDatasourceConfiguration();
        LocalSessionFactoryBean localSessionFactoryBean = generateSessionFactoryBean(new String[] { "com.company" },
            dataSource, hibernateProperties);
        SessionFactory sessionFactory = localSessionFactoryBean.getObject();

        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return sessionFactory;
    }

    private DataSource getDatasourceConfiguration() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/dbName");
        dataSource.setUsername("username");
        dataSource.setPassword("password");

        return dataSource;
    }

    private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
        Properties hibernateProperties) {

        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource);
        localSessionFactoryBean.setPackagesToScan(basePackage);
        localSessionFactoryBean.setHibernateProperties(hibernateProperties);

        return localSessionFactoryBean;
    }

    private static Properties getHibernateProperties() {

        Properties hibernateProperties = new Properties();
        hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
        hibernateProperties.put("hibernate.show_sql", false);
        hibernateProperties.put("hibernate.generate_statistics", false);
        hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
        hibernateProperties.put("hibernate.use_sql_comments", false);

        return hibernateProperties;
    }
}

And this is a simple test class that uses it:

public class GenericDAOHibernateTest {

    private GenericDAOHibernate dao;

    @BeforeTest
    private void testInitialization() {

        dao = new GenericDAO();
        HibernateInitializator initializator = new HibernateInitializator();
        SessionFactory sessionFactory = initializator.getSessionFactory();
        dao.setSessionFactory(sessionFactory);
    }

    @Test(description = "Checks that returns the user list ")
    public void shouldReturnsUserList() throws SQLException, Exception {

        List<Object[]> openResultSetList = dao.doSomeOperation();
        ...
    }
}
like image 294
rafaborrego Avatar asked May 27 '14 09:05

rafaborrego


2 Answers

Try adding this line

localSessionFactoryBean.afterPropertiesSet();

in the method after the properties of LocalSessionFactoryInstance has been set. Your method will be as

private static LocalSessionFactoryBean generateSessionFactoryBean(String[] basePackage, DataSource dataSource,
        Properties hibernateProperties) {
        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource);
        localSessionFactoryBean.setPackagesToScan(basePackage);
        localSessionFactoryBean.setHibernateProperties(hibernateProperties);
        // Added the below line
        localSessionFactoryBean.afterPropertiesSet();
        return localSessionFactoryBean;
    }

This link may add more insight to the problem.

As per Documentation,

public void afterPropertiesSet() throws IOException

Invoked by a BeanFactory after it has set all bean properties supplied (and satisfied BeanFactoryAware and ApplicationContextAware). This method allows the bean instance to perform initialization only possible when all bean properties have been set and to throw an exception in the event of misconfiguration.

In your case, I think you need to call it in your code manually.

like image 51
Keerthivasan Avatar answered Oct 01 '22 17:10

Keerthivasan


I asked how to do it without an xml file and the solution proposed by @Octopus fixed the problem I had. However, after fixing that arised other errors with transactions... so I decided to do it in a different way that doesn't interfere with the application.

To do so I created a simplified version of the xml file in /src/test/resources removing many configurations like c3p0's one and hardcoding the values so that the tests won't fail if the application's properties files are changed.

This is the content of the xml file:

<?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" ...>

    <!-- Spring DataSource -->
    <bean id="testDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/testDatabase" />
        <property name="username" value="testUsername" />
        <property name="password" value="testPassword" />
    </bean>

    <!-- Hibernate 4 SessionFactory -->
    <bean id="testSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="testDataSource">
        <property name="packagesToScan" value="com.company" />
        <property name="hibernateProperties">
            <props>
                <!-- Hibernate basic configuration -->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.generate_statistics">false</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.use_sql_comments">false</prop>
            </props>
        </property>
    </bean>

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

    <context:annotation-config />
    <tx:annotation-driven />

    <!-- Initialization of DAOs -->
    <bean id="userDao" name="userDao" class="com.company.dao.UserDAOHibernate" autowire="byName"/>
    ... 
</beans>

In the test class I have used JUnit because I haven't managed to do it with TestNG although I tried extending AbstractTestNGSpringContextTests. I would recommend using JUnit 4.4 version instead of newer versions because it has classes like AssumptionViolatedException that are used by spring-test 2.5.

This is the code:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/application-config-tests.xml" })
public class SimpleUserDAOTest {

    @Autowired
    private UserDAO dao;

    @Autowired
    private SessionFactory sessionFactory;

    @Before
    public void setUp() throws Exception {
        TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(sessionFactory.openSession()));
    }

    @After
    public void tearDown() throws Exception {
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
        SessionFactoryUtils.closeSession(sessionHolder.getSession());
    }

    @Test
    public void shouldReturnActiveUsers() {
        List<User> userList = dao.getActiveUsers();
        ...
    }
}

I hope this helps you in your future developments

like image 23
rafaborrego Avatar answered Oct 01 '22 17:10

rafaborrego