65

我正在尝试让 Kotlin 在 spring-data-rest 项目中使用 jsr 303 验证。

给定以下数据类声明:

@Entity data class User(
    @Id 
    @GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
    var id: Long? = null,

    @Size(min=5, max=15)
    val name: String
)

@Size 注释在这里不起作用,使我能够保存名称为 1 个字符的用户。
当执行相同的示例但在 Java 类而不是 Kotlin 中时,它运行良好。

这让我想到了一个 Kotlin 问题。

提前感谢您的帮助!

4

2 回答 2

107

您需要使用Annotation 使用站点目标,因为当有多个可用选项时,构造函数中声明的属性的默认值是针对构造函数参数上的注释而不是getter(JavaBeans 兼容主机将看到)。在这里使用data类也可能不合适(见末尾的注释)。

@Entity data class User(
    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
    var id: Long? = null,

    @get:Size(min=5, max=15) // added annotation use-site target here
    val name: String
)

Kotlin 文档中的property目标可能看起来很诱人,但它只能从 Kotlin 而不是 Java 中看到。通常get可以解决问题,并且 bean 不需要它set

文档将过程描述为:

如果您不指定使用站点目标,则根据正在使用的注释的@Target 注释选择目标。如果有多个适用目标,则使用以下列表中的第一个适用目标:

  • 参数
  • 财产
  • 场地

@Size注释是:

@Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})

因此,因为PARAMETER是一个有效的目标,并且有多个目标可用(参数、字段、方法 [get/set]),它选择PARAMETER的不是您想要的。因此,JavaBean 主机要查看属性,它将查找 getter(属性由 getter/setter 定义,而不是支持字段)。

在其中一个Java 示例中,它显示:

public class Book {
    private String title;
    private String description;

    // ...

    @NotEmpty(groups={FirstLevelCheck.class, Default.class})
    @Size(max=30)
    public String getTitle() {
        return title;
    }

    // ...
}

这与我们将它放在 getter 上的用法相匹配。如果它像某些验证注释显示的那样在现场,请参阅field使用站点目标。或者,如果该字段还必须可公开访问,请参阅 Kotlin 中的@JvmField 注释

注意: 正如其他人的笔记中所提到的,如果实体使用自动生成的 ID,您可能应该考虑不要data为实体使用类,因为新对象与检索到的对象一样,它不会存在;并且一个data类将生成equalshashCode包含所有字段,包括它不应该包含的字段。您可以从Hibernate 文档中阅读有关此内容的指南。

于 2016-03-07T20:18:44.443 回答
12

使用@getor@field目标进行验证注释。不支持带有目标的注释@param(第一个默认值) 。@property

例如:

@NotEmpty@field:NotEmpty

data class Student(
    @field:NotEmpty @field:Size(min= 2, message = "Invalid field") var name: String? = ""
)

总帐

于 2020-06-14T15:42:24.283 回答