Kotlin数据类+Bean验证JSR 303

72

我正在尝试将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问题。感谢您的帮助!

注解的目标应该是构造函数参数还是字段? - voddan
2个回答

131

在构造函数中声明属性时,默认情况下会将注解应用于构造函数参数上,而不是 getter 上(JavaBeans 兼容的 hosts 可以看到该 getter),因此需要使用 注解 use-site targets 来指定注解应用目标。当有多个选项可用时,请注意选择正确的目标。此外,在这里使用 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 上不需要。

文档描述的过程如下:

  

如果您没有指定 use-site 目标,则根据正在使用的注解的 @Target 注释选择目标。 如果存在多个适用的目标,则从以下列表中使用第一个适用的目标:

  
      
  • param
  •   
  • property
  •   
  • field
  •   

@Size 注释是:

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

因此,由于PARAMETER是一个有效的目标,并且有多个可用的目标(parameter、field、method [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;
    }

    // ...
}

如果它像一些验证注解所示的那样在字段上,参见field use-site target。或者如果该字段还必须是公共可访问的,请参见Kotlin中的@JvmField注解

注意:如其他人的注释中所述,如果实体使用自动生成的ID,则应该考虑不使用data类,因为对于新对象和检索到的对象,它们的ID将不存在;并且data类将生成equalshashCode来包括所有字段,包括不应该包括的字段。您可以从Hibernate文档中阅读有关此问题的指导。Hibernate docs


你太棒了!谢谢!也可以使用@get:Size(min=5, max=15)注释。 - pellenberger
3
虽然这是正确的答案,但值得注意的是,无论如何都不应该使用data class作为实体。原因是它将使用所有属性(包括id)生成equalshashCode方法,而这不是JPA实体所期望的行为。请参考这里:https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html。 - wst
谢谢@waste,我进行了编辑,直接在答案中添加了注释。 - Jayson Minard
3
如果数据类主体中已经有equals()、hashCode()或toString()的明确实现,或者在超类中有final实现,则不会生成这些函数,而是使用现有的实现。 - forresthopkinsa
1
哦天啊,非常感谢你的回答。我浪费了一整天的时间来弄清楚为什么我的注释没有被考虑进去... - Vincent

19

使用@get@field目标适用于验证注释。不支持具有目标@param(第一个默认)和@property的注释。

例如:

@NotEmpty@field:NotEmpty

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

GL


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接