【发布时间】:2019-05-16 19:16:33
【问题描述】:
我有一个使用以下转换器的Spring Boot 应用程序。
@Converter(autoApply = true)
class LocalDatePersistenceConverter implements AttributeConverter<LocalDate, java.sql.Date> {
@Override
public java.sql.Date convertToDatabaseColumn(LocalDate entityValue) {
if (entityValue != null) {
return java.sql.Date.valueOf(entityValue);
}
return null;
}
@Override
public LocalDate convertToEntityAttribute(java.sql.Date databaseValue) {
if (databaseValue != null) {
return databaseValue.toLocalDate();
}
return null;
}
}
此转换器是包私有的,可与带有 @SpringBootTest 注释的集成测试一起使用。但是,当尝试使用 jar 或 Maven spring-boot:run 目标启动应用程序时,出现以下错误:
2018-12-15 23:36:18.349 ERROR 1772 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to instantiate AttributeConverter [org.donorcalendar.persistence.LocalDatePersistenceConverter]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1745) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:853) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at org.donorcalendar.Application.main(Application.java:17) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_192]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_192]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_192]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_192]
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558) [spring-boot-maven-plugin-2.1.0.RELEASE.jar:2.1.0.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_192]
Caused by: org.hibernate.AnnotationException: Unable to instantiate AttributeConverter [org.donorcalendar.persistence.LocalDatePersistenceConverter]
at org.hibernate.cfg.AttributeConverterDefinition.instantiateAttributeConverter(AttributeConverterDefinition.java:63) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.cfg.AttributeConverterDefinition.from(AttributeConverterDefinition.java:80) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.boot.model.process.internal.ScanningCoordinator.applyScanResultsToManagedResources(ScanningCoordinator.java:235) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:82) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:99) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:232) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:167) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:51) ~[spring-orm-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390) ~[spring-orm-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) ~[spring-orm-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 22 common frames omitted
Caused by: java.lang.IllegalAccessException: Class org.hibernate.cfg.AttributeConverterDefinition can not access a member of class org.donorcalendar.persistence.LocalDatePersistenceConverter with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) ~[na:1.8.0_192]
at java.lang.Class.newInstance(Class.java:436) ~[na:1.8.0_192]
at org.hibernate.cfg.AttributeConverterDefinition.instantiateAttributeConverter(AttributeConverterDefinition.java:59) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
... 35 common frames omitted
事实上,我认为这个错误是正常行为,我想了解的是为什么在我的集成测试中正确创建和使用了这个转换器?
@SpringBootTest 注释是否使转换器以不要求它为public 的不同方式启动?我已经知道如何解决这个问题(只需制作转换器public),但我想了解为什么代码在测试期间表现不同。
我希望进行与实际应用程序尽可能相似的端到端测试。不幸的是,对于这种情况,我在应用程序启动期间遇到问题,但在测试执行期间正常初始化和执行。
有人能解释一下为什么会有这种差异吗?如有必要,我可以提供有关应用程序设置的更多详细信息。
我的问题是关于运行应用程序和集成测试时的不同行为,我已经知道如何使用转换器修复错误,所以请不要回答我只需要添加public修饰符。我想以一种与正常启动应用程序时具有相同行为(和错误)的方式配置我的测试,以便我对端到端测试更有信心。
【问题讨论】:
标签: java spring hibernate spring-boot spring-boot-test