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持久性注释目标是METHODFIELD因此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