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不生效的两种办法:
- 添加
@field:标识符(@field:NotBlank),field标识符能够限定注解作用于属性。 - 添加
@get:(@get:NotBlank)标识符。 kotlin 会直接在字节码中生成getter跟setter,这样写是显式的是表明这个注解应该作用在getter上。