kotlin:无法获取validationAPI的注释
========== ========== UPDATE
当我将注释更改为@get:NotNull,@get:Min和@get:Max时,hibernate-validator可以读取这些注释成功。
但我仍然想知道的是:
为什么validation-api的注释,比如@NotNull,@Min和@Max不能直接在数据类的成员上使用,而JPA的注释可以是?
==========贝娄是原产地问题===========
当我尝试在数据类上使用validation-api注解时,Validator类(来自hibernate-validator)无法获得注释,所以validation失败。
我写了一个测试用例,其中包括3个数据类:
- 第一个使用JPA注释@Column和@Id,可以通过测试用例成功读取。
- 第二个在成员上使用validation-api注解@NotEmpty,@ Min,@Max,这些注解不能被测试用例读取
- 第三个使用validation-api注解@get:NotEmpty,@get:Min,@get:Max,测试用例不能读取这些注解。
@Column,@NotNull,@Min和@Max的目标和保留都是:RUNTIME和FIELD
那么,后面发生了什么? 我如何正确使用validation注释?
这里是测试用例:
import org.hibernate.validator.constraints.NotEmpty import org.junit.Test import javax.persistence.Column import javax.persistence.Id import javax.validation.constraints.Max import javax.validation.constraints.Min import kotlin.reflect.KFunction import kotlin.reflect.KProperty import kotlin.reflect.jvm.javaField import kotlin.reflect.jvm.javaMethod class KotlinFeatureTest2 { @Test fun test_get_annotation() { // can get field's annotation for BeanUseJPAAnnotation success println("Getting field annotations for BeanUseJPAAnnotation :") BeanUseJPAAnnotation::class.members.forEach { if (it is KProperty) { val field = it.javaField println("${field?.name}'s annotations:") field?.annotations?.forEachIndexed { i, an -> println(" $i is: $an") } } } println("--------------------") println("Getting field annotations for BeanUseValidationAnnotation :") // CANT get field's annotation for BeanUseJPAAnnotation success BeanUseValidationAnnotation::class.members.forEach { if (it is KProperty) { val field = it.javaField println("${field?.name}'s annotations:") field?.annotations?.forEachIndexed { i, an -> println(" $i is: $an") } } } println("--------------------") println("Getting field annotations for BeanUseValidationAnnotationOnMethod :") // CANT get field's annotation for BeanUseJPAAnnotation success BeanUseValidationAnnotationOnMethod::class.members.forEach { if (it is KFunction) { val method = it.javaMethod println("${method?.name}'s annotations: ") method?.annotations?.forEachIndexed { i, an -> println(" $i is: $an") } } } } } data class BeanUseJPAAnnotation( @Column(name = "id") @Id val id: String, @Column(name = "user_name") val name: String) data class BeanUseValidationAnnotation( @NotEmpty(message = "name can not be empty") val name: String, @Min(value = 1) @Max(value = 100) val age: Int ) data class BeanUseValidationAnnotationOnMethod( @get:NotEmpty(message = "name can not be empty") val name: String, @get:Min(value = 1) @get:Max(value = 100) val age: Int)
这里是这个测试用例的输出:
Getting field annotations for BeanUseJPAAnnotation : id's annotations: 0 is: @javax.persistence.Column(nullable=true, unique=false, precision=0, name=id, length=255, scale=0, updatable=true, columnDefinition=, table=, insertable=true) 1 is: @javax.persistence.Id() name's annotations: 0 is: @javax.persistence.Column(nullable=true, unique=false, precision=0, name=user_name, length=255, scale=0, updatable=true, columnDefinition=, table=, insertable=true) -------------------- Getting field annotations for BeanUseValidationAnnotation : age's annotations: name's annotations: -------------------- Getting field annotations for BeanUseValidationAnnotationOnMethod : component1's annotations: component2's annotations: copy's annotations: equals's annotations: hashCode's annotations: toString's annotations:
以下是javax.persistence.Column
的签名部分:
@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Column {
相反,这里是javax.validation.constraints.Min
的相同部分:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Repeatable(List.class) @Documented @Constraint(validatedBy = { }) public @interface Min {
正如你可以看到JPA持久性注释目标是METHOD
和FIELD
因此Kotlin在FIELD
级别上发射它们。 但是validation器API注释的目标是更多的构造,特别是PARAMETER
。 鉴于当为构造函数声明的属性生成注释时,Kotlin编译器只选择注释参数 。 Java中等价的BeanUseValidationAnnotation
构造函数签名如下所示:
public BeanUseValidationAnnotation(@NotEmpty(message = "name can not be empty") @NotNull String name, @Min(1L) @Max(100L) int age) {
此行为在文档中说明 :
如果您未指定使用地点目标,则根据所使用的注释的
@Target
批注选择目标。 如果有多个适用的目标,则使用以下列表中的第一个适用目标:
param
property
field