The problem is that Kotlin code has to compile to JVM class bytecode. The inline constructor is just a syntactic sugar which results in a constructor, getters and setters being generated in the
So the above is just the idiomatic Kotlin way of going around this.
As per Kotlin docs:
If you don’t specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:
One possible way of cleaning this up is to declare your own annotations which have
@Target(FIELD) only. This way the compiler will infer the target accordingly:
@Constraint(validatedBy = arrayOf())
annotation class ValidEmail constructor(
val message: String = "ignored message",
val groups: Array<KClass<*>> = ,
val payload: Array<KClass<out Payload>> = 
data class Credentials(@ValidEmail val email: String, ...
One advantage of doing this is that you can combine multiple standard JSR-303 constraints into a single domain-specific annotation (as in the email example above, although
@Email already implies
@NotBlank so not the best illustration)