1

I an trying to run simple application that uses Spring 4, Hibernate 4, and c3p0 pooling, and I keep getting this error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDao': Invocation of init method failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1560)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    at ggdb.components.database.dao.GenericDao.getCurrentSession(GenericDao.java:61)
    at ggdb.components.database.dao.UserDao.getUser(UserDao.java:36)
    at ggdb.components.database.dao.UserDao.postConstruct(UserDao.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
    ... 23 more

Here is my configuration:

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class DatabaseConfigutarion implements TransactionManagementConfigurer {

    @Autowired
    private Environment env;

    public class PropertiesKeys {

        public static final String DATABASE_HOST = "database.host";
        public static final String DATABASE_PORT = "database.port";
        public static final String DATABASE_USERNAME = "database.username";
        public static final String DATABASE_PASSWORD = "database.password";
        public static final String DATABASE_NAME = "database.database_name";
        public static final String DATABASE_ADDITIONAL_CONNECTION_PROPERTIES = "database.additional.connection.properties";

        public static final String HIBERNATE_DEFAULT_SCHEMA = "hibernate.default_schema";
        public static final String HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";

    }

    @Bean
    public SessionFactory sessionFactory() {
        String databaseUrl = String.format("jdbc:mysql://%s:%s/%s", env.getProperty(PropertiesKeys.DATABASE_HOST), env.getProperty(PropertiesKeys.DATABASE_PORT), env.getProperty(PropertiesKeys.DATABASE_NAME));
        String additionnalProperties = env.getProperty(PropertiesKeys.DATABASE_ADDITIONAL_CONNECTION_PROPERTIES);
        databaseUrl = ( additionnalProperties.isEmpty() ? databaseUrl : String.format("%s?%s", databaseUrl, additionnalProperties) );

        org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
        configuration.setProperty("hibernate.connection.driver_class", com.mysql.jdbc.Driver.class.getName());
        configuration.setProperty("hibernate.connection.url", databaseUrl);
        configuration.setProperty("hibernate.connection.username", env.getProperty(PropertiesKeys.DATABASE_USERNAME));
        configuration.setProperty("hibernate.connection.password", env.getProperty(PropertiesKeys.DATABASE_PASSWORD));

        configuration.setProperty("hibernate.c3p0.min_size", "5");
        configuration.setProperty("hibernate.c3p0.max_size", "20");
        configuration.setProperty("hibernate.c3p0.timeout", "1800");
        configuration.setProperty("hibernate.c3p0.max_statements", "50");

        configuration.setProperty("hibernate.current_session_context_class", org.springframework.orm.hibernate4.SpringSessionContext.class.getName());
        configuration.setProperty("hibernate.dialect", org.hibernate.dialect.MySQL5InnoDBDialect.class.getName());
        configuration.setProperty("hibernate.show_sql", "false");
        configuration.setProperty("hibernate.format_sql", "false");
        configuration.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
        configuration.setProperty("hibernate.default_schema", env.getProperty(PropertiesKeys.HIBERNATE_DEFAULT_SCHEMA));
        configuration.setProperty("hibernate.hbm2ddl.auto", env.getProperty(PropertiesKeys.HIBERNATE_HBM2DDL_AUTO));

        configuration.addAnnotatedClass(ggdb.components.database.entities.User.class);
        configuration.addAnnotatedClass(ggdb.components.database.entities.Role.class);

        ServiceRegistry serviceRegistry = (new StandardServiceRegistryBuilder())
                .applySettings(configuration.getProperties())
                .build();

        SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        return sessionFactory;
    }

    @Bean
    public HibernateTransactionManager transactionManager(){
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory());
        return transactionManager;
    }

    @Override
    public HibernateTransactionManager annotationDrivenTransactionManager() {
        return transactionManager();
    }

    public Environment getEnv() {
        return env;
    }

    public void setEnv(Environment env) {
        this.env = env;
    }

}

And code that throws error:

@Repository
public class UserDao extends GenericDao<User> {

    public UserDao() {
        super(User.class);
    }

    // TODO: this method is temporary,
    // should be removed later,
    @PostConstruct
    @Transactional
    public void postConstruct() {
        User user = getUser("user");
        if (user == null) {
            user = new User();
            user.setUsername("user");
            user.setPassword("pass");
            save(user);
        }
    }

    @Transactional
    public User getUser(String username) {
        @SuppressWarnings("unchecked")
        List<User> users = (List<User>) getCurrentSession().getNamedQuery(User.FIND_BY_USERNAME).setParameter("username", username).list();
        return (users.isEmpty() ? null : users.get(0));
    }

}

Extended class code:

public class GenericDao<T> {

    private final Class<T> parameterClass;

    @Autowired
    protected SessionFactory sessionFactory;

    public GenericDao(Class<T> parameterClass) {
        this.parameterClass = parameterClass;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public Long save(T t) {
        return (Long) getSession().save(t);
    }

    public void delete(Long id) {
        getSession().delete(id);
    }

    @SuppressWarnings("unchecked")
    public T get(Long id) {
        return (T) getSession().get(parameterClass, id);
    }

    public void refresh(T t) {
        getSession().refresh(t);
    }

    @SuppressWarnings("unchecked")
    public T merge(T t) {
        return (T) getSession().merge(t);
    }

    public void update(T t) {
        getSession().update(t);
    }

    public void saveOrUpdate(T t) {
        getSession().saveOrUpdate(t);
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
}

Can you help me? Where is the problem?

ashu
  • 497
  • 1
  • 10
  • 21
M314
  • 925
  • 3
  • 13
  • 37
  • 2
    The `@PostConstruct` doesn't give a garantuee that everything is already setup, generally you don't have transactions setup already. – M. Deinum Jan 13 '15 at 11:43
  • Manual transaction management is soo 2003, please have a look at the `@Transactional` annotation. – Tobb Jan 13 '15 at 11:50
  • Tobb, if you have any points where I can improve my code please tell me a bit more straight forward, because I do not get your point here. – M314 Jan 13 '15 at 12:04
  • possible duplicate of [@Transactional on @PostConstruct method](http://stackoverflow.com/questions/17346679/transactional-on-postconstruct-method) – M. Deinum Jan 13 '15 at 12:05

1 Answers1

0

Invocation of init method failed. You could try to add this:

@Autowired
public void init(SessionFactory factory) {
    setSessionFactory(factory);
}

to your GenericDAO.