Spring boot + hibernate - naming strategy does not exists during build

152 Views Asked by At

I am trying to set up my new Spring Boot 3.1.5 project. And I found one problem with Hibernate during it. Let me show you my setup:

pom.xml - dependencies

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-mockmvc</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

as you can notice I use spring-boot-starter-data-jpa which contains hibernate dependency -

    <dependency>
      <groupId>org.hibernate.orm</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>6.2.13.Final</version>
      <scope>compile</scope>
    </dependency>

my Hibernate setup

    // setup Hibernate LocalSessionFactoryBean
    @Bean
    public LocalSessionFactoryBean sessionFactory(DataSource appDataSource) {
        final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();

        sessionFactory.setDataSource(appDataSource);
        sessionFactory.setPackagesToScan(...);

        sessionFactory.setPhysicalNamingStrategy(new AppPhysicalNamingStrategy());

        // Hibernate properties
        final Properties hibernateProperties = new Properties();
        ...
        sessionFactory.setHibernateProperties(hibernateProperties);

        return sessionFactory;
    }

    // Changing transaction manager to hibernate
    @Bean
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory);
        return transactionManager;
    }

Plus I use @EnableTransactionManagement

Everything worked fine until I used setPhysicalNamingStrategy. From that moment I could not start my project due to the following:

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:555)

The following method did not exist:

    'void org.springframework.orm.hibernate5.LocalSessionFactoryBuilder.setPhysicalNamingStrategy(org.hibernate.boot.model.naming.PhysicalNamingStrategy)'

The calling method's class, org.springframework.orm.hibernate5.LocalSessionFactoryBean, was loaded from the following location:

    jar:file:.../.m2/repository/org/springframework/spring-orm/6.0.13/spring-orm-6.0.13.jar!/org/springframework/orm/hibernate5/LocalSessionFactoryBean.class

The called method's class, org.springframework.orm.hibernate5.LocalSessionFactoryBuilder, is available from the following locations:

    jar:file:.../.m2/repository/org/springframework/spring-orm/6.0.13/spring-orm-6.0.13.jar!/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.class

The called method's class hierarchy was loaded from the following locations:

    org.springframework.orm.hibernate5.LocalSessionFactoryBuilder: file:.../.m2/repository/org/springframework/spring-orm/6.0.13/spring-orm-6.0.13.jar
    org.hibernate.cfg.Configuration: file:.../.m2/repository/org/hibernate/orm/hibernate-core/6.2.13.Final/hibernate-core-6.2.13.Final.jar


Action:

Correct the classpath of your application so that it contains compatible versions of the classes org.springframework.orm.hibernate5.LocalSessionFactoryBean and org.springframework.orm.hibernate5.LocalSessionFactoryBuilder

So the problem is with the method setPhysicalNamingStrategy which is not determined during the build.

I tried to delete my .m2 folder and reimport all dependencies again, restart IDE, mvn clean package and none of these work.

I also found one solution, when I add another hibernate property:

hibernateProperties.setProperty("hibernate.physical_naming_strategy", AppPhysicalNamingStrategy.class.getName());

However, I am not completely satisfied with this because I still don't understand why the method is available in the code and not available during the build.

So my question is why this happens? Or is there something wrong with my dependencies, what else i can do?

I will be really glad for your help. Thanks for your help all

1

There are 1 best solutions below

0
Anders Bergquist On

Old question but someone might end up here for the same reason I did. I've run into similar problem when upgrading from Spring Boot 2.7.x / Hibernate 5.8.x to 3.2.x / 6.4.x

The main issue is that Hibernate 6.x can't really be used directly in Spring Framework 6.x.

From https://docs.spring.io/spring-framework/reference/data-access/orm/hibernate.html

Hibernate ORM 6.x is only supported as a JPA provider (HibernateJpaVendorAdapter). Plain SessionFactory setup with the orm.hibernate5 package is not supported anymore. We recommend Hibernate ORM 6.1/6.2 with JPA-style setup for new development projects.

Meaning, the LocalSessionFactoryBean, which resides in the org.springframework.orm.hibernate5 package, does not work with creating SessionFactories for Hibernate 6.x.

However, I did manage to get this working a bit by extending LocalSessionFactoryBean.

class MyLocalSessionFactoryBean extends LocalSessionFactoryBean {

  @Override
  protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
    sfb.setImplicitNamingStrategy(new ImplicitNamingStrategy())
    return super.buildSessionFactory(sfb)
  }
}

Using this class, you don't run into the issue that a method is missing. Now, I didn't pursue this solution because it feels a bit "hacky" and I'm unsure what consequences it might lead to down the road.

There is probably a reason why LocalSessionFactoryBean wasn't updated to support Hibernate 6.x so I'm in the process of implementing Hibernate as a JPA provider.