Question

By mean of Spring libraries I have to develope a DAL (Data Access Layer) in the form of a jar library which will be imported into the main application. I want to use Hibernate to access a MySQL DB and DBCP for the management of the connections pool.

I have written the config file DALConfig.java which contains the configuration of the DAL beans:

package my.dal.config;

import java.util.Properties;
import javax.annotation.Resource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate4.HibernateTransactionManager;

// Needed by Spring to add this class to the ApplicationContext's configuration
@Configuration
@ComponentScan(basePackages = { "my.dal.config" })
// Property file in which are written the MySQL connection properties
@PropertySource("classpath:dbconnection.properties")

public class DALConfig {

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";  
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";  
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";  
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";  
    private static final String PROPERTY_NAME_POOL_INITIAL_SIZE = "pool.initialsize";
    private static final String PROPERTY_NAME_POOL_MAX_IDLE = "pool.maxidle";

    // Needed to access property file
    @Resource
    private Environment environment;

    // The bean which defines the BasicDataSource (DBCP)
    @Bean
    public BasicDataSource dataSource() throws Exception
    {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty(PROPERTY_NAME_DATABASE_DRIVER));
        props.put("url", environment.getProperty(PROPERTY_NAME_DATABASE_URL));
        props.put("username", environment.getProperty(PROPERTY_NAME_DATABASE_USERNAME));
        props.put("password", environment.getProperty(PROPERTY_NAME_DATABASE_PASSWORD));
        props.put("initialSize", environment.getProperty(PROPERTY_NAME_POOL_INITIAL_SIZE));
        props.put("maxIdle", environment.getProperty(PROPERTY_NAME_POOL_MAX_IDLE));

        BasicDataSource bds = BasicDataSourceFactory.createDataSource(props);

        return bds;

    }

    // Bean used to translate Hibernate's exceptions into Spring's ones
    @Bean
    public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
    {
        PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
        return b;
    }
}

Then I wrote the HibernateConfig.java config file which contains the Hibernate configuration stuff

package my.dal.hibernateconfig;

import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;


@Configuration
@ComponentScan(basePackages = { "my.dal.hibernatesessionfactory" })
@PropertySource("classpath:dbconnection.properties")
public class HibernateConfig {

    private static final String PROPERTY_NAME_DAL_CLASSES_PACKAGE = "hibernate.dal.package";  
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";  

    @Resource
    private Environment environment;  

    @Autowired
    DataSource dataSource;

    // Bean which defines the FactoryBean for the SessionBean
    @Bean
    public LocalSessionFactoryBean sessionFactory()
    {
        LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();

        lsfb.setPackagesToScan(PROPERTY_NAME_DAL_CLASSES_PACKAGE);

        Properties hibernateProperties = new Properties();
        hibernateProperties.put("dialect", PROPERTY_NAME_HIBERNATE_DIALECT);
        lsfb.setHibernateProperties(hibernateProperties);

        lsfb.setDataSource(dataSource);
        return lsfb;
    }

    @Bean
    public HibernateTransactionManager transactionManager()
    {
        // THE EXCEPTION IS THROWN AT THIS LINE
        HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory());
        return htm;
    }
}

Next I wrote the UserDAO.java class which is a DAO for the User class which models the DB's User table.

package my.dal.dao;

import my.models.User;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Component
@Repository
@Transactional
public class UserDAO
{
    private SessionFactory sessionFactory;

    @Autowired
    public UserDAO(SessionFactory sessionFactory) {
        this.sessionFactory=sessionFactory;
    }

    public int insert(User user) {
        return (Integer) sessionFactory.getCurrentSession().save(user);
    }

    public User getByUsername(String username) {
        return (User) sessionFactory.getCurrentSession().get(User.class, username);
    }

    public void update(User user) {
        sessionFactory.getCurrentSession().merge(user); // .update(user);
    }

    public void delete(String username) {
        User u = getByUsername(username);
        sessionFactory.getCurrentSession().delete(u);
    }
}

The mapping class User.java (generated using the Eclipse's Hibernate tools) is

package my.models;

public class User implements java.io.Serializable {

    private String username;
    private String idUserKeystone;
    private String firstName;
    private String lastName;
    private String password;
    private String email;
    private String emailRef;
    private String employer;
    private boolean confirmed;

    // Getters, setters and full constructor
}

Now I want to test the DAL. The testing class is DALTest.java

package my.dal.tests;

import static org.junit.Assert.assertTrue;
import my.dal.config.DALConfig;
import my.dal.dao.UserDAO;
import my.dal.hibernateconfig.HibernateConfig;
import my.models.User;
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(classes = { DALConfig.class, HibernateConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class DALTest {

    @Autowired
    UserDAO userDAO;

    @Test
    public void testGetUser() {
        User user = null;

        // Let's see if the user "myuser" is into the database
        user = userDAO.getByUsername("myuser");

        assertTrue(null != user);
    }

}

When I run the test it throws the following exceptions

java.lang.IllegalStateException: Failed to load ApplicationContext
    ...
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class my.dal.hibernateconfig.HibernateConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.orm.hibernate4.HibernateTransactionManager my.dal.hibernateconfig.HibernateConfig.transactionManager()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
    ...
    Caused by: java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
            at my.dal.hibernateconfig.HibernateConfig.transactionManager(HibernateConfig.java:55)
            at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036.CGLIB$transactionManager$1(<generated>)
            at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036$$FastClassBySpringCGLIB$$119f2c5b.invoke(<generated>)
        ...

It seems like the problem is the cast at the line

HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory())

On the contrary, the Internet is full of example writing that line that way.

What could be the problem?

Thank you in advance

Was it helpful?

Solution

A FactoryBean<Foo> is a bean that creates objects of type Foo. It's not, itself, of type Foo (as the javadoc would show you). To get the Foo it creates, you simply call getObject() on the factory bean:

HibernateTransactionManager htm = 
    new HibernateTransactionManager(sessionFactory().getObject());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top