Weltraumschaf
Weltraumschaf

Reputation: 428

NoSuchMethodError when starting Spring Boot Application with Hibernate JPA

I have a simple Hello-World Spring Boot Application with JPA repositories and Hibernate. The pom.xml looks like:

...
<properties>
  <springframework.version>1.5.1.RELEASE</springframework.version>
  <validation-api.version>1.1.0.Final</validation-api.version>
  <dbunit.version>2.5.3</dbunit.version>
  <usertype.core.version>6.0.1.GA</usertype.core.version>
  <validate.version>2.2.0</validate.version>
  <strman.version>0.2.0</strman.version>
  <reflections.version>0.9.10</reflections.version>
  <javax.servlet.jsp-api.version>2.3.1</javax.servlet.jsp-api.version>
  <rest-assured.version>3.0.1</rest-assured.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${springframework.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<repositories>
    <repository>
        <id>spring-milestone</id>
        <url>https://repo.spring.io/libs-release</url>
    </repository>
</repositories>

<pluginRepositories>
    <pluginRepository>
        <id>spring-milestone</id>
        <url>https://repo.spring.io/libs-release</url>
    </pluginRepository>
</pluginRepositories>

<dependencies>
    <!-- Spring -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <!-- We use Logback for logging. -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
            <exclusion>
                <!-- We use Jetty because it is cooler ;) -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- JSON -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-joda</artifactId>
    </dependency>

    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>

    <!-- Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
    </dependency>

    <!-- jsr303 validation -->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>${validation-api.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
    </dependency>

    <!-- Joda-Time -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>

    <!-- To map JodaTime with database type -->
    <dependency>
        <groupId>org.jadira.usertype</groupId>
        <artifactId>usertype.core</artifactId>
        <version>${usertype.core.version}</version>
    </dependency>

    <!-- MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>de.weltraumschaf.commons</groupId>
        <artifactId>validate</artifactId>
        <version>${validate.version}</version>
    </dependency>

    <!-- String utility -->
    <dependency>
        <groupId>com.shekhargulati</groupId>
        <artifactId>strman</artifactId>
        <version>${strman.version}</version>
    </dependency>

    <dependency>
        <groupId>org.reflections</groupId>
        <artifactId>reflections</artifactId>
        <version>${reflections.version}</version>
    </dependency>

    <!-- Provided from container -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>${javax.servlet.jsp-api.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <scope>provided</scope>
    </dependency>
</dependnecies>
...

The database configuration is quite simple properties file:

spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url               = jdbc:mysql://localhost:3306/snafu?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=utf8
spring.datasource.username          = snafu
spring.datasource.password          = ***

spring.jpa.show-sql             = false
spring.jpa.hibernate.format_sql = true
spring.jpa.hibernate.ddl-auto   = update
spring.jpa.database-platform    = org.hibernate.dialect.MySQLInnoDBDialect

And DB configclass:

package org.snafu;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableJpaRepositories(basePackages = { "org.snafu.repo" })
public class DatabaseConfiguration {
    @Value("${spring.datasource.driverClassName}")
    private String driver = "";
    
    @Value("${spring.datasource.url}")
    private String url = "";
    
    @Value("${spring.datasource.username}")
    private String user = "";
    
    @Value("${spring.datasource.password}")
    private String password = "";
    
    @Value("${spring.jpa.show-sql}")
    private String showSql = "";
    
    @Value("${spring.jpa.hibernate.format_sql}")
    private String formatSql = "";
    
    @Value(value = "${spring.jpa.hibernate.ddl-auto}")
    private String ddlAuto;
    
    @Value(value = "${spring.jpa.database-platform}")
    private String dialect;
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("de.iteratec.str.iteratweet.model");

        final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());
        
        return em;
    }
    
    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }
    
    private Properties additionalProperties() {
        final Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);
        properties.setProperty("hibernate.dialect", dialect);
        properties.setProperty("hibernate.naming_strategy", "org.hibernate.cfg.EJB3NamingStrategy");
        return properties;
    }
}

This worked fine with 1.3.x Releases of Spring. But with any 1.4.x or 1.5.x Version the autoconfiguration of Hibernate fails:

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' 
defined in class path resource [org/snafu/DatabaseConfiguration.class]: Invocation of init method failed; 
nested exception is java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Map;
Caused by: java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava/util/Map;

Obviously there is no such method. The Hibernate version which is configured by Spring Boot is:

mvn dependency:tree | grep -i hibernate
[INFO] |  +- org.hibernate:hibernate-entitymanager:jar:5.0.11.Final:compile
[INFO] +- org.hibernate:hibernate-core:jar:5.0.11.Final:compile
[INFO] |  +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile
[INFO] |  \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.1.Final:compile
[INFO] +- org.hibernate:hibernate-validator:jar:5.3.4.Final:compile

I found some Spring issues which addresses this problem. They claim it is fixed. Is this fix not available in Spring Boot? Do I have to change the Hibernate version by hand? I'm very new to Spring Boot, but I thought this is the reason for using Spring Boot that I get a predefined set of dependencies which will work together. What do I miss or do wrong?

Upvotes: 5

Views: 3445

Answers (1)

abaghel
abaghel

Reputation: 15317

Considering you are using Spring-Boot 1.5.1.RELEASE and have spring-boot-starter-data-jpa dependency in pom.xml file, Spring-Boot will fetch all the Hibernate related jars. Please remove hibernate-core dependency from your pom.xml as Spring-Boot will fetch hibernate-core-5.0.11.jar along with other hibernate jars.

The error you are getting is because of Jadira version 6.0.1.GA in your pom.xml. This version is not compatible with Hibernate version 5.0. Use Jadira version 5.0.0.GA in your pom.xml like below.

<dependency>
        <groupId>org.jadira.usertype</groupId>
        <artifactId>usertype.core</artifactId>
        <version>5.0.0.GA</version>
</dependency>

Upvotes: 5

Related Questions