Spring Boot 2.0.2.RELEASE 的模型验证异常
Posted
技术标签:
【中文标题】Spring Boot 2.0.2.RELEASE 的模型验证异常【英文标题】:Model validation exception with Spring Boot 2.0.2.RELEASE 【发布时间】:2018-11-12 08:14:22 【问题描述】:我在迁移到 Spring Boot 2.0.2.RELEASE 时遇到了一些问题。 似乎休眠验证器试图验证 Enum Kotlin 类型的默认文件。
有一个简单的测试代码:
gradle.build
buildscript
ext
kotlinVersion = '1.2.41'
springBootVersion = '2.0.2.RELEASE'
repositories
mavenCentral()
dependencies
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
plugins
id "io.spring.dependency-management" version "1.0.5.RELEASE"
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = test
sourceCompatibility = 1.8
compileKotlin
kotlinOptions.jvmTarget = "1.8"
compileTestKotlin
kotlinOptions.jvmTarget = "1.8"
repositories
mavenCentral()
dependencies
compile("org.springframework.boot:spring-boot-starter-web")
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile 'com.h2database:h2'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile('org.jetbrains.kotlin:kotlin-reflect')
testCompile('org.springframework.boot:spring-boot-starter-test')
主类
@EnableJpaRepositories
@SpringBootApplication
class SimpleApplication
fun main(args: Array<String>)
run(SimpleApplication::class.java, *args)
具有枚举类型的模型
@Entity
data class SimpleModel(
@Id
@GeneratedValue
var id: Long? = null,
@get:NotEmpty
@ElementCollection
@JoinTable(name = "test_group", joinColumns = [JoinColumn(name = "id")])
@Column(name = "group")
@Enumerated(STRING)
var groups: MutableSet<Group>? = null
)
enum class Group(val groupName: String, val groupDescription: String)
TEST1("TestGroup1", "Just for test"),
TEST2("TestGroup2", "Just for test")
测试类
@RunWith(SpringRunner::class)
@TestConfiguration
@SpringBootTest(webEnvironment = RANDOM_PORT)
class SimpleServiceTest
@Autowired
lateinit var applicationContext: ApplicationContext
@Test
fun testValidationError()
val model = SimpleModel().apply
groups = mutableSetOf(TEST1)
val resourceName = "$model.javaClass.simpleName.decapitalize().group[1]"
val bindingResult = BeanPropertyBindingResult(TEST1, resourceName)
val validator = applicationContext.getBean("mvcValidator", Validator::class.java)
validator.validate(TEST1, bindingResult)
测试属性 application.yml
spring:
datasource:
driver-class-name: org.h2.Driver
jdbcUrl: jdbc:h2:mem:test
jpa:
properties:
database: h2
hibernate:
hbm2ddl:
ddl: true
auto: create-drop
javax:
persistence:
validation:
mode: none
异常消息
java.lang.ArrayIndexOutOfBoundsException: 2
at java.util.Arrays$ArrayList.get(Arrays.java:3841)
at org.hibernate.validator.internal.metadata.aggregated.ParameterMetaData$Builder.build(ParameterMetaData.java:169)
at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.findParameterMetaData(ExecutableMetaData.java:435)
at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.build(ExecutableMetaData.java:388)
at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BuilderDelegate.build(BeanMetaDataImpl.java:788)
at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl$BeanMetaDataBuilder.build(BeanMetaDataImpl.java:648)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.createBeanMetaData(BeanMetaDataManager.java:192)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.lambda$getBeanMetaData$0(BeanMetaDataManager.java:160)
at java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:324)
at org.hibernate.validator.internal.metadata.BeanMetaDataManager.getBeanMetaData(BeanMetaDataManager.java:159)
at org.hibernate.validator.internal.engine.ValidationContext$ValidationContextBuilder.forValidate(ValidationContext.java:566)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:155)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:104)
at org.springframework.boot.autoconfigure.validation.ValidatorAdapter.validate(ValidatorAdapter.java:64)
at com.test.service.SimpleServiceTest.testValidationError(SimpleServiceTest.kt:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Spring Boot 1.5.10 不会发生此异常。
有人遇到过同样的问题吗?我在互联网和这里没有找到任何答案。有人可以帮帮我吗?
【问题讨论】:
您是否知道仅使用 Java 类而不使用 Kotlin 来重现相同问题的方法? 嗯...它可以按预期与 Java 类一起使用。很可能是因为在 Java 中 Enum 类型的字段 name 和 ordinal 具有私有范围,但在 Kotlin 中这些字段是公共的。 【参考方案1】:所以问题如下:
反射 API 提供的构造函数是:com.test.simple.Group(java.lang.String $enum$name, int $enum$ordinal, java.lang.String groupName, java.lang.String groupDescription)
,所以它有四个参数。我想名称和序号已传递给构造函数;
KotlinReflectionParameterNameDiscoverer
提供的参数名称仅为[groupName, groupDescription]
(因此不考虑附加参数)。
KotlinReflectionParameterNameDiscoverer
应尽量与 Java 反射 API 返回的内容保持一致。否则它绝对不能用作 HV ParameterNameProvider
的一部分。
【讨论】:
所以,实际上问题仍然存在。如果 Spring 社区的人会看到此评论,请查看本期的讨论hibernate.atlassian.net/browse/HV-1619 @xpap 我编辑了我的答案以综合该问题。我真的不明白为什么他们会在没有进一步讨论的情况下关闭它。肯定有一些事情需要他们注意。以上是关于Spring Boot 2.0.2.RELEASE 的模型验证异常的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot自动配置源码解析(基于Spring Boot 2.0.2.RELEASE)
升级到 Spring Boot 2.0.2 后 Spring Security .permitAll() 不再有效
插件 [id: 'org.springframework.boot', version: '2.0.2.RELEASE'] 未找到