With Spring 5 now having dedicated Kotlin support, let’s have a look into the features that are designed to make these technologies work seamless together.
SPRING BOOT & KOTLIN DOMAIN @Entity data class GotCharacter(val firstName: String, val lastName: String, val age: Int, val actor: String, @Id @GeneratedValue(strategy = GenerationType.AUTO) val id: Long = -1)
SPRING BOOT & KOTLIN CONTROLLER @RestController class GotController(private val repository: GotCharacterRepository) { @GetMapping("/") fun findAll() = repository.findAll() @GetMapping("/{lastName}") fun findByLastName(@PathVariable lastName: String) = repository.findByLastName(lastName) }
SPRING & KOTLIN NULL-SAFETY OF SPRING FRAMEWORK API ▸ Spring 5 introduces non-null API declaration for all packages ▸ Explicitly nullable arguments and return values annotated as such ▸ ➜ Spring framework APIs = null-safe from Kotlin side (Kotlin 1.1.50+)
SPRING & KOTLIN NULL-SAFETY OF SPRING FRAMEWORK API ▸ Spring 5 introduces non-null API declaration for all packages ▸ Explicitly nullable arguments and return values annotated as such ▸ ➜ Spring framework APIs = null-safe from Kotlin side (Kotlin 1.1.50+) @NonNullApi package org.springframework.core; /** * Return the "Cache-Control" header value. * @return {@code null} if no directive was added, or the header value otherwise */ @Nullable public String getHeaderValue()
SPRING & KOTLIN LEVERAGE KOTLIN NULLABLE INFORMATION IN SPRING ANNOTATIONS // "GET /foo" and "GET /foo?bar=baz" are allowed @GetMapping("/foo") fun foo(@RequestParam bar: String?) = ... // "GET /foo?bar=baz" is allowed and "GET /foo" will error @GetMapping("/foo") fun foo(@RequestParam bar: String) = ...
SPRING & KOTLIN REACTOR KOTLIN BUILTIN SUPPORT ▸ Mono, Flux, StepVerifier APIs ▸ Kotlin extensions ▸ any class instance to Mono instance with foo.toMono() ▸ create Flux from Java 8 Streams wih stream.toFlux() ▸ extensions for Iterable, CompletableFuture, Throwable
SPRING & KOTLIN KOTLIN-SPRING PLUGIN ▸ Kotlin classes = final by default ➜ add open keyword on each class / member functions of Spring beans ▸ @Component @Async @Transactional @Cacheable
SPRING & KOTLIN KOTLIN-SPRING PLUGIN ▸ Kotlin classes = final by default ➜ add open keyword on each class / member functions of Spring beans ▸ @Component @Async @Transactional @Cacheable ▸ Meta-annotations support: @Configuration, @Controller, @RestController, @Service, @Repository
SPRING & KOTLIN WEBFLUX ANNOTATION BASED @RestController class ReactiveGotController(private val repository: ReactiveGotRepository) { @GetMapping("/reactive/characters") fun findAll() = repository.findAll() @GetMapping("/reactive/character/{id}") fun findOne(@PathVariable id: String) = repository.findById(id) @PostMapping("/reactive/character") fun save(@RequestBody character: GotCharacter) = repository.save(character) } interface ReactiveGotRepository { fun findAll(): Flux fun findById(id: String): Mono fun save(character: GotCharacter): Mono }