Kotlin在SpringBoot中使用@Valid校验无效

599 阅读1分钟

Data class如下:

data class BindEmailInput(
    var userId: Long = 0,
    @IsMyEmail
    var email: String = "",
    @NotBlank(message = "验证码不能为空")
    var captcha: String = "",
) : Serializable

Controller如下:

fun bindEmail(@RequestBody @Valid input: BindEmailInput): ApiResult

调用bindEmail方法,可以校验email,但是无法校验captcha

自定义注解@IsMyEmail的注解目标:

@Target({ ElementType.METHOD, ElementType.FIELD})

@NotBlank原生注解的注解目标:

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}

原因分析:

  • 在 Java 中,注解写在在实体类属性或者 get/set 方法上;在 kotlin 中,属性直接写在构造函数中
  • 似乎存在一种优先级的问题:kotlin的属性直接写在构造函数中,注解优先作用于构造参数,不能作用于参数就作用于属性。@NotBlank有ElementType.PARAMETER,所以它正好作用到BindEmailInput的参数。而自定义注解@IsMyEmail的注解目标只写了ElementType.FIELD,不能作用于参数,只能作用于BindEmailInput的属性,这就导致@IsMyEmail阴差阳错能够生效

解决@NotBlank不生效的两种办法:

  1. 添加 @field: 标识符(@field:NotBlank),field标识符能够限定注解作用于属性。
  2. 添加 @get:(@get:NotBlank)标识符。 kotlin 会直接在字节码中生成 getter 跟 setter,这样写是显式的是表明这个注解应该作用在getter上。