0

I use an example from internet, then try to upgrade from Spring Boot 1.5.10.RELEASE to 2.0.0.RC1. The application works ok with Spring Boot version 1.5.10.RELEASE, but it has error with version 2.0.0.RC1.

File pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>spring_boot_hibernate</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <start-class>spring-boot-example.Application</start-class>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <!--<version>1.5.10.RELEASE</version>-->
        <version>2.0.0.RC1</version>

    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>spring-repo</id>
            <name>Spring Repository</name>
            <url>https://repo.spring.io/release</url>
        </repository>
        <repository>
            <id>spring-snapshot</id>
            <name>Spring Snapshot Repository</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
</project>

File application.properties

server.port=8081

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);
    }

}

The error happen at line:

if (entityManagerFactory.unwrap(SessionFactory.class) == null) {

File UserController.java

package com.example.controller;

import com.example.model.UserDetails;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ResponseEntity<List<UserDetails>> userDetails() {
        List<UserDetails> userDetails = userService.getUserDetails();
        return new ResponseEntity<List<UserDetails>>(userDetails, HttpStatus.OK);
    }

}

File UserDaoImpl.java

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();
    }

}

File UserDao.java

package com.example.dao;

import com.example.model.UserDetails;

import java.util.List;

public interface UserDao {

    List<UserDetails> getUserDetails();

}

File UserDetails.java

package com.example.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table
public class UserDetails {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column
    private String firstName;

    @Column
    private String lastName;

    @Column
    private String email;

    @Column
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

File UserServiceImpl.java

package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.model.UserDetails;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    public List<UserDetails> getUserDetails() {
        return userDao.getUserDetails();

    }

}

Error

 /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:49901,suspend=y,server=n --illegal-access=warn -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=49900 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:/Users/donhuvy/Library/Caches/IntelliJIdea2017.3/captureAgent/debugger-...
    WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (file:/Users/donhuvy/.m2/repository/org/springframework/spring-core/5.0.3.RELEASE/spring-core-5.0.3.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
    2018-02-20 07:56:04.273  INFO 1944 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$1e62766c] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
....    2018-02-20 07:56:04.538  INFO 1944 --- [           main] 
ConditionEvaluationReportLoggingListener : 

    Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
    2018-02-20 07:56:04.848 ERROR 1944 --- [           main] o.s.boot.SpringApplication               : Application run failed

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beanConfig': Unsatisfied dependency expressed through field 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getSessionFactory' defined in class path resource [com/example/BeanConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.hibernate.SessionFactory]: Circular reference involving containing bean 'beanConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'getSessionFactory' threw exception; nested exception is java.lang.NullPointerException
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:587) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:373) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1344) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:138) ~[spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
        at com.example.Application.main(Application.java:10) [classes/:na]
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getSessionFactory' defined in class path resource [com/example/BeanConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.hibernate.SessionFactory]: Circular reference involving containing bean 'beanConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'getSessionFactory' threw exception; nested exception is java.lang.NullPointerException
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:587) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1250) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        ... 19 common frames omitted
    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.hibernate.SessionFactory]: Circular reference involving containing bean 'beanConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'getSessionFactory' threw exception; nested exception is java.lang.NullPointerException
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        ... 31 common frames omitted
    Caused by: java.lang.NullPointerException: null
        at com.example.BeanConfig.getSessionFactory(BeanConfig.java:18) ~[classes/:na]
        at com.example.BeanConfig$$EnhancerBySpringCGLIB$$54b5def4.CGLIB$getSessionFactory$0(<generated>) ~[classes/:na]
        at com.example.BeanConfig$$EnhancerBySpringCGLIB$$54b5def4$$FastClassBySpringCGLIB$$bcb3b797.invoke(<generated>) ~[classes/:na]
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        at com.example.BeanConfig$$EnhancerBySpringCGLIB$$54b5def4.getSessionFactory(<generated>) ~[classes/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.0.3.RELEASE.jar:5.0.3.RELEASE]
        ... 32 common frames omitted

    Disconnected from the target VM, address: '127.0.0.1:49901', transport: 'socket'

Process finished with exit code 1

How to fix it?

Vy Do
  • 46,709
  • 59
  • 215
  • 313
  • Try to run with Java 8. – borino Feb 20 '18 at 05:39
  • 2
    Just use JPA and not plain hibernate. remove your configuration and instead of the `SessionFactory` inject the `EntityManager`. Using the plain hibernate session (with the current state of JPA) is generally sufficient. – M. Deinum Feb 20 '18 at 09:40
  • 1
    Thank you for your comment. Before the question, I create Hibernate session success. Because my web app is complex (near 500 tables, later my queries is complex), I tend to use full-feature Hibernate. Source code in question is merely an example. – Vy Do Feb 21 '18 at 13:18
  • 2
    @borino, I think Java 8 isn't matter. Because Spring framework 5 is support Java 9, No know error of Hibernate 5.2 or better with Java 9. – Vy Do Feb 21 '18 at 13:21
  • 1
    @M.Deinum I have read many questions about problems of integration of plain Hibernate in Spring Boot, many answers and comments were written by you, my question is: why you always recommend to avoid work with plain Hibernate? I remember a comment where a valid scenario could be if Native API of Hibernate is used, just how the case of this user ... is there a blog post of you with more details of this? Thanks. – Manuel Jordan Feb 28 '18 at 15:10
  • 1
    @Manuel: for one thing, the posted code here introduces a bug by using openSession in the dao (see https://stackoverflow.com/q/8046662/217324). if you stick with springdata jpa you avoid that. – Nathan Hughes Aug 09 '18 at 19:41

2 Answers2

3

In BeanConfig, you should inject the JPA EntityManager via @PersistenceUnit, not @Autowired.

And remove the getSessionFactory since the Hibernate SessionFactory is already created internally and you can always unwrap the EntityManagerFactory.

So, it should look like this:

@Configuration
public class BeanConfig {

    @PersistenceUnit
    EntityManagerFactory emf;

}
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
1

File BeanConfig.java

package com.example;

import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

@Configuration
public class BeanConfig {

    @PersistenceUnit
    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);
    }

}

An example about using method getSessionFactory

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();
    }

}

(It is a working example with Hibernate 5.2.13.Final, Spring Boot 2.0.0.RC2, and Java 9.0.4)

Vy Do
  • 46,709
  • 59
  • 215
  • 313