develop with

How to get started with Spring Boot

Using Spring boot with Kotlin

Getting an application defined and setup in Kotlin for Spring boot differs a bit from how you set it up in Java. The syntax of starting the app is simplified and there are some other libraries that make using Spring boot and Kotlin together much easier.

Get the libraries

Resolve the dependency through maven by defining it in your pom.xml.

The following dependencies we need for this example: * kotlin runtime and libs * jackson * spring boot * swagger * junit 5

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.examples</groupId>
    <artifactId>my-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>My API</name>
    <description>My API</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> 
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <kotlin.version>1.3.10</kotlin.version>
        <junit.jupiter.version>5.3.2</junit.jupiter.version>
        <junit.platform.version>1.2.0</junit.platform.version>
        <maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
        <jackson.version>2.9.8</jackson.version>
        <springfox.version>2.9.2</springfox.version>
        <kotlinx.version>1.1.0</kotlinx.version>
    </properties>

    <repositories>
        <repository>
            <id>bintray-kotlin-kotlinx</id>
            <name>bintray</name>
            <url>https://kotlin.bintray.com/kotlinx</url>
        </repository>
    </repositories>

    <dependencies>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <!-- test dependencies below here -->

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>${junit.platform.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit5</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <testSourceDirectory>src/test/java</testSourceDirectory>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>
                <configuration>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                    </compilerPlugins>
                </configuration>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>

                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <failIfNoTests>true</failIfNoTests>
                    <includes>
                        <include>**/*Test.java</include>
                        <include>**/*Test.kt</include>
                        <include>**/*Tests.java</include>
                        <include>**/*Tests.kt</include>
                    </includes>
                    <properties>
                        <excludeTags>integration-test</excludeTags>
                    </properties>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>${junit.platform.version}</version>
                        <scope>runtime</scope>
                    </dependency>
                    <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-api</artifactId>
                        <version>${junit-jupiter.version}</version>
                        <scope>runtime</scope>
                    </dependency>
                    <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-engine</artifactId>
                        <version>${junit.jupiter.version}</version>
                        <scope>runtime</scope>
                    </dependency>
                </dependencies>
            </plugin>

        </plugins>
    </build>

</project>

Setting up the Application

Here is the code:

package com.examples

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

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

Simple REST API

The rest controller is very similar to the way you would define it in Java. Below is an example that also includes how to define the API with swagger defintions as well.

Here is the code:

import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.Authorization
import mu.KLogging
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.web.bind.annotation.*
import javax.servlet.http.HttpServletRequest
import javax.validation.Valid


@RestController
@RequestMapping("/api/examples", produces = ["application/json"])
@Api(tags = ["Examples"])
@Timed
class ExampleController {

    @GetMapping("/{name}")
    @ApiOperation("get", response = String::class)
    fun get(@PathVariable("name", required = false) name: String?): ResponseEntity<String> {
       return ResponseEntity("hello ${name}", HttpStatus.OK)
    }

}

Testing

Since we are including Junit 5, all the examples on getting the tests to work will be with Junit 5. The annotations for testing the Spring boot application in Junit 5 changes and makes it easier to define mock extensioins and such.

Example Rest controller test

import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.core.env.Environment
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.http.*


@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class ExampleControllerTest {
    @Autowired
    lateinit var testRestTemplate: TestRestTemplate
    
    @Test
    fun testHello() {
        val headers = HttpHeaders()
        headers.setContentType(MediaType.APPLICATION_JSON)
        val name = "World"
        val entity = HttpEntity<String>(headers)
        val response = testRestTemplate.exchange("http://localhost:${environment.getProperty("local.server.port")}/api/examples/${name}", HttpMethod.GET, entity, String::class.java)
        assertEquals("hello World", response.body)
    }
}

This should help you get going conquering your API with Kotlin and Spring boot.

If you have some other suggestions, feel free to comment below.

comments powered by Disqus

Want to see a topic covered? create a suggestion

Get more developer references and books in the developwith store.