bean validation not working with kotlin (JSR 380)

后端 未结 2 1777
庸人自扰
庸人自扰 2021-02-07 02:41

so first of all i could not think of a better title for this question so i\'m open for changes.

I am trying to validate a bean using the bean validation mechanism (JSR-3

2条回答
  •  终归单人心
    2021-02-07 03:17

    Answer (Kotlin 1.3.70)

    Make sure to compile the kotlin code with jvm target 1.8 or greater and enable this feature by providing the -Xemit-jvm-type-annotations when compiling.

    For Spring Boot projects you only have to do the following changes (tested with Spring Boot 2.3.3 and Kotlin 1.4.0):

    1. In your pom set the following property:
      
          11
          1.4.0
      
      
    2. Add -Xemit-jvm-type-annotations to the kotlin-maven-plugin:
      
          
              kotlin-maven-plugin
              org.jetbrains.kotlin
              
                  
                      -Xjsr305=strict
                      -Xemit-jvm-type-annotations
                  
                  
                      spring
                  
              
              
                  
                      org.jetbrains.kotlin
                      kotlin-maven-allopen
                      ${kotlin.version}
                  
              
          
      
      

    Sample Project


    Workaround (pre Kotlin 1.3.70)

    Rafal G. already pointed out that we could use a custom validator as a workaround. So here's some code:

    The Annotation:

    import javax.validation.Constraint
    import javax.validation.Payload
    import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS
    import kotlin.annotation.AnnotationTarget.CONSTRUCTOR
    import kotlin.annotation.AnnotationTarget.FIELD
    import kotlin.annotation.AnnotationTarget.FUNCTION
    import kotlin.annotation.AnnotationTarget.TYPE_PARAMETER
    import kotlin.annotation.AnnotationTarget.VALUE_PARAMETER
    import kotlin.reflect.KClass
    
    @MustBeDocumented
    @Constraint(validatedBy = [NoNullElementsValidator::class])
    @Target(allowedTargets = [FUNCTION, FIELD, ANNOTATION_CLASS, CONSTRUCTOR, VALUE_PARAMETER, TYPE_PARAMETER])
    @Retention(AnnotationRetention.RUNTIME)
    annotation class NoNullElements(
        val message: String = "must not contain null elements",
        val groups: Array> = [],
        val payload: Array> = []
    )
    

    The ConstraintValidator:

    import javax.validation.ConstraintValidator
    import javax.validation.ConstraintValidatorContext
    
    class NoNullElementsValidator : ConstraintValidator> {
        override fun isValid(value: Collection?, context: ConstraintValidatorContext): Boolean {
            // null values are valid
            if (value == null) {
                return true
            }
            return value.stream().noneMatch { it == null }
        }
    }
    

    And finally the updated User class:

    data class User(
        @field:NotEmpty
        @field:NoNullElements
        var roles: MutableSet = HashSet()
    )
    

    Altough validation works now, the resulting ConstrainViolation is slightly different. For example the elementType and propertyPath differs as you can see below.

    Java:

    Kotlin:

    Source is available here: https://github.com/DarkAtra/jsr380-kotlin-issue/tree/workaround

    Thanks again for your help Rafal G.

提交回复
热议问题