In this guide, we will be building a Kotlin RESTful web services using Spring Boot and Spring MVC / JAX-RS. Instructions are provided to use either Spring MVC or JAX-RS. We will be adding unit tests and integration tests as well. This guide assumes you have a basic knowledge of Kotlin, Spring Boot and Maven.
Note: Maven is used in the uploaded source code but instructions are provided to use Gradle instead of Maven.
- Go to Spring Initializr and generate a
Gradle/Maven
withKotlin
and Spring Boot project. - Select
Web
as dependency to build a Spring MVC RESTful webservice. - Select
Jersey (JAX-RS)
as dependency to build a JAX-RS RESTful webservice. - Fill in the
Group
andArtifact
and click on generate project.
Import the extracted folder to IntelliJ.
Add a Spring Boot application context. This class will be generated by Spring Initializr.
@SpringBootApplication
class HelloApplication
fun main(args: Array<String>) {
SpringApplication.run(HelloApplication::class.java, *args)
}
Spring MVC
@RestController
@RequestMapping("hello")
class HelloController {
@GetMapping("/string")
fun helloString() = "Hello string!"
}
JAX-RS
@Component
@Path("/hello")
class HelloResource {
@GET
@Path("/string")
fun helloString() = "Hello string!"
}
JAX-RS
Note: This is required only for JAX-RS based service. Do not add this for Spring MVC based service.
Add Jersey ResourceConfig class to your Spring context and register the JAX-RS endpoint class. This is commented out in uploaded source code. You have to uncomment it, if you are using JAX-RS.
@Component
class HelloConfig : ResourceConfig() {
init {
registerEndpoints()
}
private fun registerEndpoints() {
register(HelloResource())
}
}
Start the application from HelloApplication
class and load http://localhost:8080/hello/string
Hello string!
Let's add a service and wire it into our controller / JAX-RS endpoint.
Spring MVC and JAX-RS
@Service
class HelloService {
fun getHello() = "Hello service!"
}
Spring MVC
@Autowired
lateinit var helloService: HelloService
@GetMapping("/service")
fun helloService() = helloService.getHello()
JAX-RS
@Autowired
lateinit var helloService: HelloService
@GET
@Path("/service")
fun helloService() = helloService.getHello()
Restart the application from HelloApplication
class and load http://localhost:8080/hello/service
Hello service!
Let's add a data object to return in our controller / JAX-RS endpoint.
Spring MVC and JAX-RS
data class Hello(val message: String)
Spring MVC
@GetMapping("/data")
fun helloData() = Hello("Hello data!")
JAX-RS
@GET
@Path("/data")
@Produces("application/json")
fun helloData() = Hello("Hello data!")
jackson-module-kotlin is required to support marshaling.
Spring MVC and JAX-RS
Gradle
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
Maven
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
Restart the application from HelloApplication
class and load http://localhost:8080/hello/data
{
"message":"Hello data!"
}
Spring MVC and JAX-RS
@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class HelloEndointIntegrationTest {
@Autowired
lateinit var testRestTemplate: TestRestTemplate
@Test
fun testHelloController() {
val result = testRestTemplate.getForEntity("/hello/string", String::class.java)
assertNotNull(result)
assertEquals(result.statusCode, HttpStatus.OK)
assertEquals(result.body, "Hello string!")
}
@Test
fun testHelloService() {
val result = testRestTemplate.getForEntity("/hello/service", String::class.java)
assertNotNull(result)
assertEquals(result.statusCode, HttpStatus.OK)
assertEquals(result.body, "Hello service!")
}
@Test
fun testHelloDto() {
val result = testRestTemplate.getForEntity("/hello/data", Hello::class.java)
assertNotNull(result)
assertEquals(result.statusCode, HttpStatus.OK)
assertEquals(result.body, Hello("Hello data!"))
}
}
Spring MVC
@RunWith(MockitoJUnitRunner::class)
class HelloControllerUnitTest {
@InjectMocks
lateinit var helloController: HelloController
@Mock
lateinit var helloService: HelloService
@Test
fun testHelloController() {
val result = helloController.helloString()
assertNotNull(result)
assertEquals("Hello string!", result)
}
@Test
fun testHelloService() {
doReturn("Hello service!").`when`(helloService).getHello()
val result = helloController.helloService()
assertNotNull(result)
assertEquals("Hello service!", result)
}
@Test
fun testHelloDto() {
val result = helloController.helloData()
assertNotNull(result)
assertEquals(Hello("Hello data!"), result)
}
}
JAX-RS
@RunWith(MockitoJUnitRunner::class)
class HelloResourceUnitTest {
@InjectMocks
lateinit var helloResource: HelloResource
@Mock
lateinit var helloService: HelloService
@Test
fun testHelloController() {
val result = helloResource.helloString()
assertNotNull(result)
assertEquals("Hello string!", result)
}
@Test
fun testHelloService() {
doReturn("Hello service!").`when`(helloService).getHello()
val result = helloResource.helloService()
assertNotNull(result)
assertEquals("Hello service!", result)
}
@Test
fun testHelloDto() {
val result = helloResource.helloData()
assertNotNull(result)
assertEquals(Hello("Hello data!"), result)
}
}
Spring MVC and JAX-RS
@RunWith(MockitoJUnitRunner::class)
class HelloServiceUnitTest {
@InjectMocks
lateinit var helloService: HelloService
@Test
fun testHelloController() {
val result = helloService.getHello()
assertNotNull(result)
assertEquals("Hello service!", result)
}
}