Spring Boot 2.0.2.RELEASE 的模型验证异常
Model validation exception with Spring Boot 2.0.2.RELEASE
我在迁移到 Spring Boot 2.0.2.RELEASE 时遇到一些问题。
似乎 hibernate 验证器试图验证 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')
}
主要class
@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")
}
测试class
@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[=17=](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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=17=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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 不会发生此异常。
有没有人遇到过同样的问题?我在互联网上和这里都没有找到任何答案。有人可以帮帮我吗?
所以问题如下:
- 反射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反射APIreturns保持一致。否则它绝对不能用作 HV ParameterNameProvider
.
的一部分
我在迁移到 Spring Boot 2.0.2.RELEASE 时遇到一些问题。 似乎 hibernate 验证器试图验证 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')
}
主要class
@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")
}
测试class
@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[=17=](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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=17=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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 不会发生此异常。
有没有人遇到过同样的问题?我在互联网上和这里都没有找到任何答案。有人可以帮帮我吗?
所以问题如下:
- 反射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反射APIreturns保持一致。否则它绝对不能用作 HV ParameterNameProvider
.