Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin data class and bean validation with container element constraints

With Bean Validation 2.0 it is possible to also put constraints on container elements.

I cannot get this to work with Kotlin data classes:

data class Some(val someMap: Map<String, @Length(max = 255) String>)

This does not have any effect. Any ideas?

I created a repository with a sample project to reproduce the case: https://github.com/mduesterhoeft/bean-validation-container-constraints

like image 888
Mathias Dpunkt Avatar asked Jun 28 '18 14:06

Mathias Dpunkt


2 Answers

Starting Kotlin 1.3.70 and 1.4, this should be possible setting a specific compiler option: https://kotlinlang.org/docs/reference/whatsnew14.html#type-annotations-in-the-jvm-bytecode .

On any previous version or any situation where this support is not sufficient, you have to write a custom validator.

Example one for validating that a collection only contains hex strings:

@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD,
    AnnotationTarget.ANNOTATION_CLASS,
    AnnotationTarget.CONSTRUCTOR,
    AnnotationTarget.VALUE_PARAMETER
)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Constraint(validatedBy = [HexStringElementsValidator::class])
annotation class HexStringElements(
    val message: String = "must only contain hex values",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Any>> = []
)

class HexStringElementsValidator : ConstraintValidator<HexStringElements, Collection<Any>> {

    companion object {
        val pattern = "^[a-fA-F0-9]+\$".toRegex()
    }

    override fun isValid(value: Collection<Any>?, context: ConstraintValidatorContext?) =
        value == null || value.all { it is String && pattern.matches(it) }
}
like image 55
Dirk Bolte Avatar answered Nov 06 '22 04:11

Dirk Bolte


Add this config to your build.gradle (note that ... means whatever is already there) :

Groovy:

compileKotlin {
    kotlinOptions {
        freeCompilerArgs = [..., "-Xemit-jvm-type-annotations"]
        ...
    }
}

Kotlin DSL:

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf(..., "-Xemit-jvm-type-annotations")
        ...
    }
}

like image 40
Sam W. Avatar answered Nov 06 '22 02:11

Sam W.