Sent from Hauptstadt!

ein Blog für den geneigten Leser

Spring Boot REST Validierung mit Kotlin

Tags: ,

Kategorie Software Engineering | Keine Kommentare »

In meinem aktuellen Projekt setze ich die Programmiersprache Kotlin zusammen mit dem Spring Boot Framework ein. Ich mache gerade meine ersten Kotlin Schritte und stolpere jetzt natürlich über alle möglichen Probleme. Erster Stolperstein: Validierung von REST API Eingaben.

Die notwendigen Maven Abhängigkeiten für Spring Boot Validierung lauten:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-kotlin</artifactId>
</dependency>

Möchte ich den Request Body eines REST Endpoints validieren, füge ich die @Valid Annotation hinzu:

import javax.validation.Valid

@RestController
@RequestMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
class EchoController {
    @PostMapping
    fun echo(
        @RequestBody @Valid message: MessageDto,
    ) = message
}

Jetzt muss ich nur noch eine MessageDto Klasse erstellen und alle Properties mit den gewünschten Annotationen für die Validierung versehen. Hier bietet sich in Kotlin natürlich eine Data Class an.

import javax.validation.constraints.NotBlank

data class MessageDto (
    @NotBlank
    val message: String
)

Leider ist es nicht ganz so einfach :-(

Der Kotlin Compiler generiert im Fall einer Property wie „message“ mehrere Elemente:

  • ein Feld
  • ein Parameter im Default Constructor
  • eine getter Funktion
  • eine setter Funktion, wenn die Property als änderbar („var“) statt fix („val“) deklariert wäre

Die Annotation kann sich aber nur auf eines dieser Elemente beziehen. Der Kotlin Compiler schaut zunächst, welche Ziele in der Definition der Annotation laut @Target erlaubt sind. @NotBlank kann auf eine ganze Reihe von Code Elementen angewendet werden:

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })

Der Kotlin Compiler prüft diese Targets gegen folgende Liste:

  • PARAMETER
  • PROPERTY
  • FIELD

Das oberste Element Parameter ist sowohl in der @Target als auch in der internen Compiler Liste enthalten und deshalb wird die Annotation auf den generierten Parameter im Default Constructor angewendet.

Tatsächlich muss die @NotBlank Annotation an das zur Property gehörende Feld oder an die getter Funktion gebunden werden. Dazu gibt es die so genannten „use-site targets“. Die korrekte Annotation (siehe Zeile 4) muss also lauten:

import javax.validation.constraints.NotBlank

data class MessageDto (
    @field:NotBlank
    val message: String
)

Dann funktioniert die Validierung auch wie erwartet.

Schreiben sie ein Kommentar