使用Hibernate JPA启动Spring Boot Application时出现NoSuchMethodError

时间:2017-02-14 10:55:48

标签: java spring hibernate jpa spring-boot

我有一个简单的Hello-World Spring Boot应用程序,带有JPA存储库和Hibernate。 pom.xml看起来像是:

...
<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>
...

数据库配置是非常简单的属性文件:

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

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

这适用于Spring的1.3.x版本。但是对于任何1.4.x或1.5.x版本的自动配置 Hibernate失败了:

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;

显然没有这样的方法。 Spring Boot配置的Hibernate版本是:

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

我发现了一些解决这个问题的Spring问题。他们声称这是固定的。这不是解决方法 可以在Spring Boot中使用吗?我是否必须手动更改Hibernate版本?我很新 Spring Boot,但我认为这是使用Spring Boot的原因,我得到了预设 依赖性将会起作用。我错过了什么或做错了什么?

1 个答案:

答案 0 :(得分:5)

考虑到你在pom.xml文件中使用Spring-Boot 1.5.1.RELEASE并且具有spring-boot-starter-data-jpa依赖性,Spring-Boot将获取所有与Hibernate相关的jar。请从pom.xml中删除hibernate-core依赖项,因为Spring-Boot将获取hibernate-core-5.0.11.jar以及其他hibernate jar。

您获得的错误是因为pom.xml中的Jadira版本6.0.1.GA。此版本与Hibernate 5.0版不兼容。在pom.xml中使用Jadira版本5.0.0.GA,如下所示。

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