Manuel Jordan
Manuel Jordan

Reputation: 16271

Correct and complete configuration for Spring Boot 1.5.x for Hibernate 5

About Spring Boot for the 1.5.10.RELEASE version. It works internally around with Hibernate for version 5.0.12.Final

With the purpose to avoid the following error message:

required a bean of type 'org.hibernate.SessionFactory' that could not be found

The HibernateJpaSessionFactoryBean class should be applied. It according from:

The situation here is the HibernateJpaSessionFactoryBean class is @Deprecated.

The solution how is suggested according the HibernateJpaSessionFactoryBean javadoc, is work around with EntityManagerFactory#unwrap

Thus from:

manually must be declared the following:

@Bean
public SessionFactory sessionFactory(EntityManagerFactory emf) {
    return emf.unwrap(SessionFactory.class);
}

Warning is mandatory include in the application.properties file the following (it is not mentioned in the post shared above):

spring.jpa.properties.hibernate.current_session_context_class = 
org.springframework.orm.hibernate5.SpringSessionContext

Otherwise appears:

org.springframework.orm.jpa.JpaSystemException:
No CurrentSessionContext configured!; nested exception is org.hibernate.HibernateException:
No CurrentSessionContext configured!

Until here my @Test classes working through Hibernate fails, these same @Test classes pass in other project working through Spring Framework, thus all the infrastructure for Hibernate is declared manully.

Therefore through the following code:

@Test
public void contextLoads() {

    String[] beanNames = applicationContext.getBeanDefinitionNames();
    Arrays.sort(beanNames);
    for (String beanName : beanNames) {
        logger.info("beanName: {}", beanName);
    }

    logger.info("PlatformTransactionManager");
    if(transactionManager != null) {
        logger.info("Class: {}", transactionManager.getClass().getName());
    }

}

all the beans created by Spring Boot are printed and I have confirmed the following:

 - PlatformTransactionManager 
 - Class: org.springframework.orm.jpa.JpaTransactionManager

I expected the HibernateTransactionManager instead of JpaTransactionManager.

My unique way to get the @Test methods passing is declaring again manually other @Bean:

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

Therefore:

Observation: even better if all is completely configured through the application.properties file (purpose avoid declare manually any @Bean)

How a summary, the unique way to integrate Spring Boot for plain Hibernate (Consider the scenario to migrate a complete project working through Spring Framework to Spring Boot working both with Hibernate) is through the following:

spring.jpa.hibernate.ddl-auto = none

spring.jpa.properties.hibernate.cache.provider_class = org.hibernate.cache.NoCacheProvider
spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.default_batch_fetch_size = 30
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.format_sql = true
spring.jpa.properties.hibernate.jdbc.batch_size = 30
spring.jpa.properties.hibernate.max_fetch_depth = 30
spring.jpa.properties.hibernate.order_updates = true;
spring.jpa.properties.hibernate.show_sql = false
spring.jpa.properties.hibernate.use_sql_comments = true

Plus these two mandatories @Beans

@Bean
public SessionFactory sessionFactory(EntityManagerFactory emf) {
    return emf.unwrap(SessionFactory.class);
}

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

Without these two @Beans I have all the two errors already reported.

Therefore the goal is configure Hibernate just through application.properties

Upvotes: 0

Views: 2713

Answers (1)

Vy Do
Vy Do

Reputation: 52508

This is a suggest (Spring Boot 1.5.10.RELEASE)

File application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/vy
spring.datasource.username=root
spring.datasource.password=123456
# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

File BeanConfig.java

package com.example;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManagerFactory;

@Configuration
public class BeanConfig {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Bean
    public SessionFactory getSessionFactory() {
        if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return entityManagerFactory.unwrap(SessionFactory.class);
    }

}

File UserDao.java

package com.example.dao;

import com.example.model.UserDetails;

import java.util.List;

public interface UserDao {

    List<UserDetails> getUserDetails();

}

File UserDaoImpl.java where use SessionFactory

package com.example.dao.impl;

import com.example.dao.UserDao;
import com.example.model.UserDetails;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class UserDaoImpl implements UserDao {

    @Autowired
    private SessionFactory sessionFactory;

    public List<UserDetails> getUserDetails() {
        Criteria criteria = sessionFactory.openSession().createCriteria(UserDetails.class);
        return criteria.list();
    }

}

the goal is configure Hibernate just through application.properties

--> It is ok with JPA implementation using Hibernate Session. Spring Data JPA is tight integrated with Spring Boot (at least I checked with SpringBoot 2.0.0.RC1). Configuration via application.properties, under the hood, Spring Boot is auto-configuration.

It is not ok with full features of Hibernate ORM.

Upvotes: 1

Related Questions