kotlin:无法获得验证api的注释

时间:2016-10-28 03:47:18

标签: annotations kotlin

========== UPDATE ==========

当我将注释更改为@get:NotNull,@ get:Min和@get:Max时,hibernate-validator可以读取这些注释成功。

但我仍然想知道的是:

为什么验证-api的注释,例如@NotNull,@ Min和@Max不能直接用于数据类的成员,而JPA的注释可以是? ???

==========贝娄是原产地问题===========

当我尝试在数据类上使用validation-api的注释时,Validator类(来自hibernate-validator)无法获取注释,因此验证失败。

我写了一个测试用例,其中包括3个数据类:

  • 第一个使用JPA注释@Column和@Id,可以通过测试用例成功读取。
  • 第二个在成员上使用validation-api注释@NotEmpty,@ Min,@ Max,这些注释无法通过测试用例读取
  • 第3个使用validation-api注释@get:NotEmpty,@ get:Min,@ get:Max,测试用例无法读取这些注释。

@Column,@ NotNull,@ Min和@Max的目标和保留都是:   RUNTIME和FIELD

那么,背后发生了什么?我该如何正确使用验证注释?

这是测试用例:

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: 

1 个答案:

答案 0 :(得分:2)

以下是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级别上发出它们。然而,验证器API注释针对更多构造,特别是PARAMETER。鉴于在为构造函数声明的属性生成注释时,Kotlin编译器选择仅注释参数。 Java中等效的BeanUseValidationAnnotation构造函数签名如下所示:

public BeanUseValidationAnnotation(@NotEmpty(message = "name can not be empty") @NotNull String name, @Min(1L) @Max(100L) int age) {

此行为已声明为in the documentation

  

如果未指定使用地点目标,则根据目标选择目标   到正在使用的注释的@Target注释。如果有   多个适用的目标,第一个适用的目标来自   使用以下列表:

     
      
  • param
  •   
  • property
  •   
  • field
  •