使用JUnit 4和Spring Data进行Spring测试JPA:NoSuchMethodError org.hibernate.engine.spi.SessionFactoryImplementor.getProperties

时间:2016-10-02 09:53:46

标签: spring hibernate spring-data spring-data-jpa spring-test

使用.add_to_cart_inline { border: 0!important; padding: 0!important; } ,JUnit 4和Spring Test我为SpringJUnit4ClassRunner编写了单元测试,它使用Spring Data JPA Service和嵌入式HSQL数据库:

Repository

我使用required javaagent option on VM运行测试,使用config:

@Ignore
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:unitTestFullConfig.xml")
public class InMemoryDBFullTestBaseClass {
}

public final class ActorServiceImplTest extends InMemoryDBFullTestBaseClass {
   @Inject
    private ActorService service;

    @Test
    public final void saveActor () throws Exception {
        service.save(new ActorDTO(null, "testName", "testSurname", new Date(), Collections.emptyList()));

        assertEquals(1, service.getAll().size());
    }
}

但我得到了:

  

使用名称' entityManagerFactory'创建bean时出错。在URL [file:/ E:/workspace/film-site/out/test/main/unitTestFullConfig.xml]中定义:init方法的调用失败;嵌套异常是java.lang.NoSuchMethodError:org.hibernate.engine.spi.SessionFactoryImplementor.getProperties()Ljava / util / Properties;       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean ...

test config和<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Configure the data source bean --> <jdbc:embedded-database id="dataSource" type="HSQL"> </jdbc:embedded-database> <!-- Enable annotation driven transaction management --> <tx:annotation-driven/> <mvc:annotation-driven/> <context:component-scan base-package="beans"/> <!-- Create default configuration for Hibernate --> <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> <!-- Configure the entity manager factory bean --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> </property> <!-- Set JPA properties --> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="javax.persistence.schema-generation.database.action">none</prop> <prop key="hibernate.ejb.use_class_enhancer">true</prop> <prop key="hibernate.hbm2ddl.auto">create</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> <!-- Set base package of your entities --> <property name="packagesToScan" value="models"/> <!-- Set share cache mode --> <property name="sharedCacheMode" value="ENABLE_SELECTIVE"/> <!-- Set validation mode --> <property name="validationMode" value="NONE"/> <property name="persistenceUnitName" value="testJPA" /> </bean> <!-- Configure the transaction manager bean --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Configure Spring Data JPA and set the base package of the repository interfaces --> <jpa:repositories base-package="beans.repositories"/> </beans> (适用于Tomcat应用程序)之间的唯一区别是测试中使用的嵌入式数据库,但即使我使用项目中的applicationContext.xml

dataSource

我仍然面临同样的问题(项目正常工作)。此外,我不认为问题是我没有<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="org.postgresql.Driver"/> <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/film-site"/> <property name="user" value="postgres"/> <property name="password" value="postgres"/> <property name="maxPoolSize" value="10"/> <property name="maxStatements" value="0"/> <property name="minPoolSize" value="5"/> </bean> 档案,因为我在这里问过:Spring Data configuration - hibernate.properties not found。我使用hibernate.propertiesSpring 4.3.2.RELEASEHibernate Core 5.2.0.FinalHibernate Entity Manager 5.1.0.FinalSpring Data 1.10.2.RELEASE JPASpring Data Commons 1.12.2.RELEASE。如果有人帮助我,我会很高兴 - 提前谢谢你。 更新:我为Spring Data Commons Core 1.4.1.RELEASEjpaProperties更改为jpaPropertyMap

entityManagerFactory

评论<property name="jpaPropertyMap"> <map> <entry key="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <entry key="javax.persistence.schema-generation.database.action" value="none" /> <entry key="hibernate.ejb.use_class_enhancer" value="true" /> <entry key="hibernate.hbm2ddl.auto" value="create" /> <entry key="hibernate.show_sql" value="true" /> </map> </property> 的依赖关系,但它仍然不起作用。当我切换到Hibernate 5.1时,我也有同样的问题 更新2:我创建了一个Java配置版本,也许它可以帮助别人看到我犯了错误:

hibernate-entitymanager

更新2016-10-04 :我创建了Github repository which shows problem,您会看到应用程序本身运行良好(只需在{{1}内的表单中添加package config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import javax.persistence.EntityManagerFactory; import javax.persistence.SharedCacheMode; import javax.persistence.ValidationMode; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration public class HibernateConfig { @Bean public DataSource dataSource () { return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build(); } // Create default configuration for Hibernate @Bean public JpaVendorAdapter jpaVendorAdapter () { return new HibernateJpaVendorAdapter(); } // Configure the entity manager factory bean @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory () { LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setDataSource(dataSource()); factory.setJpaVendorAdapter(jpaVendorAdapter()); factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); factory.setJpaPropertyMap(createJpaProperties()); factory.setPackagesToScan("models"); factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE); factory.setValidationMode(ValidationMode.NONE); factory.setPersistenceUnitName("testJPA"); return factory; } @Bean public JpaTransactionManager transactionManager () { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory((EntityManagerFactory) entityManagerFactory()); return transactionManager; } private Map<String, ?> createJpaProperties () { Map<String, Object> propertyMap = new HashMap(); propertyMap.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); propertyMap.put("javax.persistence.schema-generation.database.action", "none"); propertyMap.put("hibernate.ejb.use_class_enhancer", true); propertyMap.put("hibernate.hbm2ddl.auto", "create"); propertyMap.put("hibernate.show_sql", true); return propertyMap; } } 文件,但它不适用于测试)。附:我将Actor部署到Intellij IDEA的Tomcat 8.0.24本地实例(&#34;运行&#34;按钮)。

4 个答案:

答案 0 :(得分:3)

使用Hibernate Core 5.2 Hibernate EntityManager 5.1很可能会导致此问题。 5.2将EntityManager实现移动到核心模块中,以便最终在类路径上实现2个JPA实现,这可能导致Spring框架无法检测到Hibernate版本的引导程序。

确保您使用Hibernate 5.1并参考hibernate-entitymanager工件 5.2并仅引入hiberante-core

答案 1 :(得分:1)

在hibernate社区中修复此错误时,{strong} 5.2 中的SessionFactoryImplementor.getProperties()签名已更改为Map而不是Propertiesreference
因此,您应该使用Map

您正在使用hibernate 5.2.0 Final ,在新版本的 hibernate 5.2.3 Final 中,社区已经整合了一些hibernate-entitymanager问题。 download link。请尝试使用此版本。

建议:

1)使用以下hibernate-core和hibernate-entitymanager版本而不是 5.2.0.Final 5.1.0.Final 版本。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.2.1.Final</version>
</dependency>

2) 恢复到Hibernate 5.1.x版本(我猜你应该没有问题。)

3)如果第一个&amp;第二个建议没有奏效,然后继续发布 6.0.1.GA ,它与Hibernate 5.2兼容。 community discussion
4)而不是在配置中(仅为了试错法)。

<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
<!-- Set JPA properties -->
<property name="jpaPropertyMap">
    <map>
     ...
    </map>
</property>
...
</bean>

使用此代码:

<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 ...
  <property name="jpaPropertyMap" ref="jpaPropertyMap" />
 ...
</bean>

<util:map id="jpaPropertyMap" map-class="java.util.TreeMap"> <!-- OR <util:map id="jpaPropertyMap">   OR  <util:map id="jpaPropertyMap" map-class="java.util.HashMap">-->

  <entry key="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
  ...
  <entry key="hibernate.show_sql" value="true"/>
  ...
</util:map>

答案 2 :(得分:1)

我在GitHub上检查了你的例子,经过一些代码修改后,Unit-Test对我有用。但首先我想说一开始对我来说这是另一个例外。它如下:

Caused by: java.lang.ClassCastException: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean$$EnhancerBySpringCGLIB$$fedd095f cannot be cast to javax.persistence.EntityManagerFactory
JpaTransactionManager中的

HibernateConfig配置需要更改以解决此问题,如下所示:

@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(emf);
    return transactionManager;
}

与原始配置版本不同,在这种情况下,EntityManagerFactory被注入为Spring托管bean,而不是使用HibernateConfig.entityManagerFactory()方法创建的单独实例。

此外,还进行了其他更改,但它们与问题主题没有直接关系。如果你愿意,我也可以提供。

答案 3 :(得分:1)

这可能超出了主题,但您的示例项目也可以通过一些额外的更改来改进,以防止将来出现问题。以下改进:

  1. 明确定义您正在使用的所有Maven插件的版本和配置。至少是Maven Compiler Plugin
  2. <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
            <source>${java.source}</source>
            <target>${java.target}</target>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>
    
    1. 遵循maven项目结构惯例。在您的情况下,test相关的源代码必须放在src/test/java文件夹而不是src/main/test中:
    2. my-app
      |-- pom.xml
      `-- src
          |-- main
          |   `-- java
          |       `-- com
          |           `-- mycompany
          |               `-- app
          |                   `-- App.java
          `-- test
              `-- java
                  `-- com
                      `-- mycompany
                          `-- app
                              `-- AppTest.java
      
      1. 最好定义自己的包名称,而不仅仅是beansconfig。例如,它可以是com.pneumokok.mvccom.pneumokok.servicecom.pneumokok.testcom.pneumokok.model。它可以使用component scan名称base package帮助您。

      2. 正如您正确指出的那样,必须添加javax.servlet-api依赖关系,但定义provided范围

      3. 非常重要
        <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
        </dependency>
        
        1. 最后但并非最不重要为每个应用层和环境使用单独的Spring上下文定义。在您的示例中,可以使用几个上下文定义:
        2. <强>的src /主/资源/ COM / pneumokok /服务/ applicationContext.xml的

          服务层的弹簧上下文配置

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:tx="http://www.springframework.org/schema/tx"
                 xmlns:context="http://www.springframework.org/schema/context"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/tx
              http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd">
          
              <context:component-scan base-package="com.pneumokok.service"/>
              <!-- Enable annotation driven transaction management -->
              <tx:annotation-driven/>
          
              ...
          
          </beans>
          

          <强>的src /主/资源/ COM / pneumokok / MVC / applicationContext.xml的

          MVC层的弹簧上下文配置

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:mvc="http://www.springframework.org/schema/mvc"
                 xmlns:context="http://www.springframework.org/schema/context"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/mvc 
              http://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd">
          
              <context:component-scan base-package="com.pneumokok.mvc"/>
              <!-- Enable annotation driven transaction management -->
              <mvc:annotation-driven/>
          
              ...
          
          </beans>
          

          <强>的src /主/资源/ COM / pneumokok / applicationContext.xml的

          Servlet容器环境的Spring上下文配置

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:mvc="http://www.springframework.org/schema/mvc"
                 xmlns:context="http://www.springframework.org/schema/context"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/mvc 
              http://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd">
          
              <import resource="com/pneumokok/service/applicationContext.xml"/>
              <import resource="com/pneumokok/mvc/applicationContext.xml"/>
              <import resource="com/pneumokok/dao/applicationContext.xml"/>
          
              <bean name="dataSource"> 
              //Servlet container DataSource configuration
              </bean>
          
              ...
          
          </beans>
          

          <强>的src /主/资源/ COM / pneumokok /测试/ applicationContext.xml的

          测试环境的Spring上下文配置

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:mvc="http://www.springframework.org/schema/mvc"
                 xmlns:context="http://www.springframework.org/schema/context"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/mvc 
              http://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd">
          
              <import resource="com/pneumokok/service/applicationContext.xml"/>
              <import resource="com/pneumokok/mvc/applicationContext.xml"/>
              <import resource="com/pneumokok/dao/applicationContext.xml"/>
          
              <bean name="dataSource"> 
              //Test DataSource configuration
              </bean>
          
              ...
          
          </beans>