Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

647
Views
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. Bean validation stops working in REST controllers. I have created a very simple project directly from https://start.spring.io to demonstrate the failure.

@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:

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.

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. 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. Anyone know if it's possible to get bean validation working with Kotlin data classes?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

The issue has been fixed in Kotlin version 1.6.10. https://github.com/JetBrains/kotlin/releases/tag/v1.6.10. After upgrading the exception is now org.springframework.web.bind.MethodArgumentNotValidException.

over 4 years ago · Santiago Trujillo Report

0

Make the field nullable even its not, and then add @field:NotNull

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

This will stop kotlin validation to happen before javax

over 4 years ago · Santiago Trujillo Report

0

I think you are just missing @Validated annotation on top of your controller class.

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.FieldError
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.*
import org.springframework.web.context.request.WebRequest
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
import java.time.LocalDateTime
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): ResponseEntity<Customer> {
        return ResponseEntity.ok(customer)
    }
}


@ControllerAdvice
class CustomerExceptionHandler : ResponseEntityExceptionHandler() {

    override fun handleMethodArgumentNotValid(
        ex: MethodArgumentNotValidException,
        headers: HttpHeaders,
        status: HttpStatus,
        request: WebRequest
    ): ResponseEntity<Any> {

        val fieldErrors: List<FieldError> = ex.fieldErrors
        val errorMapping = fieldErrors.associate { it.field to it.defaultMessage }

        val errorDetails = ErrorDetails(
            timestamp = LocalDateTime.now(),
            message = "Validation Failed",
            details = errorMapping
        )
        return ResponseEntity(errorDetails, HttpStatus.BAD_REQUEST)
    }
}

data class Customer(
    @field:NotEmpty(message = "Mandatory field: Name is missing in Request Body") val name: String
)

data class ErrorDetails(val timestamp: LocalDateTime, val message: String, val details: Map<String, String?>)

The output should look something like this enter image description here

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!