自定义Spring注释未调用

Kac*_*hał 6 java spring annotations kotlin spring-boot

在我的Spring Boot项目中,我创建了一个带有验证器的自定义批注,扩展ConstraintValidator了验证器以验证RequestBody中的某些字段。对于非嵌套字段,注释可以正常工作,但对于嵌套字段,则不调用验证器。

我的注释如下:

@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = [CustomValidator::class])
@Suppress("unused")
@MustBeDocumented
annotation class CustomValidation(
    val message: String = "validation failed",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)
Run Code Online (Sandbox Code Playgroud)

我的验证器类:

@Component
class CustomValidator : ConstraintValidator<CustomValidation, String> {

    override fun isValid(field: String?, context: ConstraintValidatorContext?): Boolean {
        if (field != "example") {
            return false
        }
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它可以正常工作:

data class MyRequest(
// validator works perfectly here
    @JsonProperty("example") @CustomValidation val example: String? = null,
    @JsonProperty("locale") val locale: String? = null
)
Run Code Online (Sandbox Code Playgroud)

但是当放在嵌套对象上时,不会调用验证器:

data class MyRequest(
    @JsonProperty("nested") val nested: NestedClass? = null,
    @JsonProperty("locale") val locale: String? = null
)

data class NestedClass(
// validator not called in that case
@JsonProperty("example") @CustomValidation val example: String? = null
)
Run Code Online (Sandbox Code Playgroud)

MyRequest我的班级用法RestController

@PostMapping("/endpoint")
    fun doSomething(
        @Valid @RequestBody myRequest: MyRequest,
        @RequestHeader(value = "token") token: String
    ): ResponseEntity<MyResponse> = ResponseEntity.ok(myService.getData(myRequest))
Run Code Online (Sandbox Code Playgroud)

关于如何解决该问题的任何想法?我已经尝试过将@Valid注释放在nested字段上,但仍然无法正常工作

Mad*_*hat 3

通常,为了在嵌套类中进行验证,您需要使用相同的嵌套类类型来注释父类的字段@Valid

在这里,为了对NestedClass类进行验证,您需要添加@Valid到类nested字段MyRequest。由于它是构造函数的一部分,因此应该使用注释使用站点目标来完成,如下所示:

data class MyRequest(
    @field:Valid @JsonProperty("nested") val nested: NestedClass? = null,
    @JsonProperty("locale") val locale: String? = null
)
Run Code Online (Sandbox Code Playgroud)

您的注释在不使用 use-site 目标的情况下工作的原因@CustomValidation是因为它只有一个用 定义的目标@Target(AnnotationTarget.FIELD),而@Valid注释有多个可能的目标,即@Target(value={METHOD,FIELD,CONSTRUCTOR,PARAMETER}),因此您需要有 use-site 目标来告诉编译器正确的目标。