You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中Hibernate Validator为何忽略自定义校验注解?

问题原因

自定义校验注解不生效是Kotlin语言特性差异加代码笔误共同导致的:

  • Kotlin注解默认保留级别不支持运行时反射读取:Java定义的注解默认保留策略是RUNTIME,但Kotlin注解默认保留级别是CLASS,即注解信息仅存在于编译期字节码,类加载到JVM后会被丢弃。Hibernate Validator是运行时通过反射扫描字段上的约束注解,自然识别不到你定义的两个自定义注解,这也是为什么同等逻辑写在Java里能正常生效。
  • 校验器泛型绑定笔误:FileFoundValidator实现ConstraintValidator接口时,第一个泛型参数错误写为Executable,导致该校验器无法和@FileFound注解绑定。
  • 注解作用目标不明确:Kotlin注解默认未指定作用到字段,在类属性上标注时可能会作用到属性访问器而非实际的实例字段,同样会导致校验框架扫不到注解。
  • 额外编译隐患:注解中message字段写的${validatedValue}是Hibernate Validator识别的EL表达式,不是Kotlin字符串模板,不转义的话会触发Kotlin编译期变量找不到的错误。
修复方案

给两个自定义注解补充正确的元注解,修正校验器泛型错误、转义EL表达式的$符号即可,修复后的完整代码如下:

@Validated
@ConfigurationProperties("dtn")
class ExecutableAdapterConfiguration {
    @FileFound // <-- custom
    @Executable // <-- custom
    lateinit var executable: Path
    @NotEmpty
    lateinit var user: String
    @NotEmpty
    lateinit var password: String
    @NotEmpty
    lateinit var productId: String
    @NotEmpty
    lateinit var version: String
}

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
@Constraint(validatedBy = [ExecutableValidator::class])
annotation class Executable(
    val message: String = "Missing permissions to execute '\${validatedValue}'",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)

class ExecutableValidator : ConstraintValidator<Executable, Path> {
    override fun isValid(value: Path?, context: ConstraintValidatorContext): Boolean {
        return value == null || !value.exists() || value.isExecutable()
    }
}

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
@Constraint(validatedBy = [FileFoundValidator::class])
annotation class FileFound(
    val message: String = "File '\${validatedValue}' not found",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)

class FileFoundValidator : ConstraintValidator<FileFound, Path> {
    override fun isValid(value: Path?, context: ConstraintValidatorContext): Boolean {
        return value != null  && value.exists()
    }
}
验证说明

修改完成后重新启动应用,当application.yaml中配置的dtn.executable路径不存在、或者对应文件没有可执行权限时,Spring Boot启动阶段就会抛出校验失败异常,和@NotEmpty等内置校验注解行为完全一致。

内容的提问来源于stack exchange,提问作者Kai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:21:34