0

In a Kotlin project I am trying to get some Springboot Configuration properties JSR303 validated. Some custom validations seem to be necessary for me:

@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
}

@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()
    }
}

@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<Executable, Path> {
    override fun isValid(value: Path?, context: ConstraintValidatorContext): Boolean {
        return value != null  && value.exists()
    }
}

The path to the executable is supposed to be existing and, well, executable. When the Validator logic is tested (gradle bootRun, application.yaml points to dummy path), the two new validators are not executed. I was debugging into Hibernate Validator and when it lists found annotations, the custom ones are not added in the bean meta data definition. But when I do the same with a Java annotation definition, it is found and used.

Kai
  • 2,145
  • 1
  • 20
  • 35
  • What if you try `@field:FileFound` and `@field:Executable`? – Slaw Jun 24 '22 at 14:16
  • Haven't tried that yet, I found it was working as expected when writing my custom annotation as Java class instead - it should not make a difference as bytecode, but somehow it does. – Kai Jun 27 '22 at 23:41
  • It does matter. You are not using the [`@Target`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-target/) meta-annotation in your Kotlin class. Read that documentation to see what targets are allowed when that meta-annotation is absent. That list includes "property". Then check out [my answer to this other Q&A](https://stackoverflow.com/questions/59925099/). If you don't declare a "use-site target", the annotation is applied to "param", "property", or "field", **in that order**. – Slaw Jun 28 '22 at 07:11
  • So, your _Kotlin annotation_ ends up being applied to the _Kotlin property_, which is not visible to Java reflection. If Hibernate Validator does not make use of Kotlin reflection (in addition to Java reflection), then it will not see your annotation. But your _Java annotation_ cannot be applied to Kotlin properties, and so it gets applies to the _backing field_ (that actual Java field), which _is_ visible to Java reflection. – Slaw Jun 28 '22 at 07:13

0 Answers0