简体   繁体   English

Kotlin Spring 引导 bean 验证不起作用

[英]Kotlin Spring Boot bean validation not working

I have quite a few projects that is slowly being migrated from Java to Kotlin, but I'm facing a problem when changing from Java POJO to Kotlin data classes. I have quite a few projects that is slowly being migrated from Java to Kotlin, but I'm facing a problem when changing from Java POJO to Kotlin data classes. Bean validation stops working in REST controllers. Bean 验证在 REST 控制器中停止工作。 I have created a very simple project directly from https://start.spring.io to demonstrate the failure.我直接从https://start.spring.io创建了一个非常简单的项目来演示失败。

@SpringBootApplication
class RestValidationApplication

fun main(args: Array<String>) {
    runApplication<RestValidationApplication>(*args)
}

@RestController
class Controller {

    @PostMapping
    fun test(@Valid @RequestBody request: Test) {
        println(request)
    }
}

data class Test(@field:NotNull val id: String)

and gradle:和 gradle:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.6.1"
    id("io.spring.dependency-management") version "1.0.11.RELEASE"
    kotlin("jvm") version "1.6.0"
    kotlin("plugin.spring") version "1.6.0"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-validation")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "17"
    }
} 

Sending a request does not trigger the bean validation, but it throws a HttpMessageNotReadableException because id is NULL.发送请求不会触发 bean 验证,但会抛出HttpMessageNotReadableException ,因为id是 NULL。

curl -X POST http://localhost:8080 -H "Content-Type: application/json" -d "{}"

I have tried both @Valid and @Validated and using @get:NotNull on the attributes, but nothing works.我已经尝试了@Valid@Validated并在属性上使用了@get:NotNull ,但没有任何效果。 I see many others have the same problem and using a Java class from a Kotlin REST controller works. I see many others have the same problem and using a Java class from a Kotlin REST controller works. Also changing to a non data class makes validation works.更改为非数据 class 也可以进行验证。 Anyone know if it's possible to get bean validation working with Kotlin data classes?任何人都知道是否可以使用 Kotlin 数据类进行 bean 验证?

Do not use data class for validation不要使用数据 class 进行验证

when you use data class you need to add @field:{} before annotation or you can use class without data class.当您使用数据 class 时,您需要在注释之前添加 @field:{} ,或者您可以在没有数据 class 的情况下使用 class。

data class:数据 class:

class AuthorInput(
    @field:NotBlank @field:Size(max = 20, min = 3) val first_name: String? = null,
    @field:NotBlank @field:Size(max = 20, min = 3) val last_name: String? = null,
    @field:NotEmpty val role: List< String?>? = null

){
    
    
}

only class:仅 class:

    class AuthorInput {
    @NotBlank
    @Size(max = 20, min = 3)
    val first_name: String? = null

    @NotBlank
    @Size(max = 20, min = 3)
    val last_name: String? = null

    @NotEmpty
    val role: List<@NotBlank String?>? = null


}

I think you are just missing @Validated annotation on top of your controller class.我认为您只是缺少 controller class 顶部的 @Validated 注释。

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import javax.validation.Valid
import javax.validation.constraints.NotEmpty

@SpringBootApplication
class BootValidationApplication

fun main(args: Array<String>) {
    runApplication<BootValidationApplication>(*args)
}

@RestController
@RequestMapping("/api/v1")
@Validated
class CustomerController {
    @PostMapping("/customer")
    fun createCustomer(@Valid @RequestBody customer: Customer) {
        println(customer)
    }
}

data class Customer(@field:NotEmpty val name: String)

output: output: 在此处输入图像描述

The issue has been fixed in Kotlin version 1.6.10.该问题已在 Kotlin 版本 1.6.10 中得到修复。 https://github.com/JetBrains/kotlin/releases/tag/v1.6.10 . https://github.com/JetBrains/kotlin/releases/tag/v1.6.10 After upgrading the exception is now org.springframework.web.bind.MethodArgumentNotValidException .升级后的异常现在是org.springframework.web.bind.MethodArgumentNotValidException

Make the field nullable even its not, and then add @field:NotNull使字段可以为空,即使它不是,然后添加 @field:NotNull

data class Test(@field:NotNull val id: String?)数据 class 测试(@field:NotNull val id: String?)

This will stop kotlin validation to happen before javax这将停止 kotlin 验证在 javax 之前发生

You have to add @get:Valid before.您必须先添加 @get:Valid 。 For example:例如:

data class Location(
    @get:Valid @get:DecimalMin("-90") @get:DecimalMax("90")  val lat: Double,
    @get:Valid @get:DecimalMin("-180") @get:DecimalMax("180") val lng: Double
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM