bean validation not working with kotlin (JSR 380)

后端 未结 2 1780
庸人自扰
庸人自扰 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:01

    Try adding ? like this:

    data class User(
        @field:Valid
        @field:NotEmpty
        var roles: MutableSet<@NotNull Role?> = HashSet()
    )
    

    Then the kotlin compiler should realise roles could be null, and it might honor the validation, I know little about JSR380 so i'm just guessing though.

    0 讨论(0)
  • 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:
      <properties>
          <java.version>11</java.version>
          <kotlin.version>1.4.0</kotlin.version>
      </properties>
      
    2. Add <arg>-Xemit-jvm-type-annotations</arg> to the kotlin-maven-plugin:
      <build>
          <plugin>
              <artifactId>kotlin-maven-plugin</artifactId>
              <groupId>org.jetbrains.kotlin</groupId>
              <configuration>
                  <args>
                      <arg>-Xjsr305=strict</arg>
                      <arg>-Xemit-jvm-type-annotations</arg>
                  </args>
                  <compilerPlugins>
                      <plugin>spring</plugin>
                  </compilerPlugins>
              </configuration>
              <dependencies>
                  <dependency>
                      <groupId>org.jetbrains.kotlin</groupId>
                      <artifactId>kotlin-maven-allopen</artifactId>
                      <version>${kotlin.version}</version>
                  </dependency>
              </dependencies>
          </plugin>
      </build>
      

    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<KClass<out Any>> = [],
        val payload: Array<KClass<out Payload>> = []
    )
    

    The ConstraintValidator:

    import javax.validation.ConstraintValidator
    import javax.validation.ConstraintValidatorContext
    
    class NoNullElementsValidator : ConstraintValidator<NoNullElements, Collection<Any>> {
        override fun isValid(value: Collection<Any>?, 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<Role> = 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.

    0 讨论(0)
提交回复
热议问题