Springboot + JPA + Kotlin
Tags: springboot, kotlin, webdev, jpa
Published: 2020-05-23 08:26:40


Today you’ll learn how to develop REST API with Spring Boot 2 and Kotlin. Kotlin is 100% interoperable with Java. Which means you can call Java code from Kotlin and Kotlin code can be used from Java seamlessly. If you want to learn more about Kotlin, refer to [Kotlin reference doc](https://kotlinlang.org/docs/reference/).

In this tutorial we'll use an in-memory database (H2) with Spring Data to persist and retrieve data via rest API.

###Creating a New Project 

Visit [ Spring Initializr](https://start.spring.io/) and select Kotlin language. In this tutorial we'll use Maven, select Maven project. But you can also use Gradle.

Add the following dependencies:
+ Spring Data JPA
+ Spring Web
+ H2 Database
+ Spring Boot DevTools

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sn2vdit71qwztqqxd452.png)

Click `Generate` to downlaod .zip file and upack it into your working directory.

###Understanding Application entry point
`src/main/com/example/demo/DemoApplication.kt`

```kotlin
package com.example.demo

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

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
	runApplication<DemoApplication>(*args)
}
```
Main fun is the entry point for Springboot application. `runApplication<DemoApplication>(*args)` is Kotlin idiomatic alternative to `SpringApplication.run(DemoApplication::class.java, *args)` that you see mostly in Java.

##Create Project structure

Create the following packages in `src/main/com/example/demo` directory:
+ config
+ controller
+ domain
+ repository
+ service

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nsd77uxlr33777l0dcrk.png)

###Create Entity Class

Create `Product.kt` in `domain` package.

```kotlin
package com.example.demo.domain

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table

@Entity
@Table(name = "product")
class Product(
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO
        var id: Long,
        @Column
        var name: String,
        @Column
        var price: Float) {

    override fun toString(): String {
        return "Product(name='$name', price=$price)"
    }
}
``` 
Compared to Java, you can notice that we defined primary constructor as part of the class header. Kotlin will generate getter, setter, hashcode, and equals methods for us, which you can also override.

###Create Repository Interface

Create `ProductRepository.kt` in `domain` package.

```kotlin
package com.example.demo.repository

import com.example.demo.domain.Product
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository

@Repository
interface ProductRepository: CrudRepository<Product, Long> {
    fun findProductsByName(name: String): List<Product>
}
```
Compared to Java, you can notice the use of `:` to implement `CrudRepository`

###Service Interface and Implementation

Create `ProductService.kt` and `ProductServiceImpl.kt` in `service` package.

```kotlin
package com.example.demo.service

import com.example.demo.domain.Product

interface ProductService {
    fun createProduct(product: Product)
    fun findProductsByName(name: String): List<Product>
}
```

```kotlin
package com.example.demo.service

import com.example.demo.domain.Product
import com.example.demo.repository.ProductRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service

@Service
class ProductServiceImpl(@Autowired val productRepository: ProductRepository): ProductService {
    override fun createProduct(product: Product) {
        productRepository.save(product)
    }

    override fun findProductsByName(name: String): List<Product> {
        return productRepository.findProductsByName(name)
    }
}
```
Notice how we used constructor injection as part of class header to inject `ProductRepository`.

###Controller Class

Create `ProductController.kt` in `controller` package

```kotlin
package com.example.demo.controller

import com.example.demo.domain.Product
import com.example.demo.service.ProductService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("api/v1/products")
class ProductController(@Autowired val productService: ProductService) {

    @PostMapping
    fun createProduct(@RequestBody product: Product) {
        productService.createProduct(product)
    }

    @GetMapping("{name}")
    fun getProductsByName(@PathVariable("name") name: String): List<Product> {
        return productService.findProductsByName(name)
    }
}
```

###Config Swagger UI

To configure Swagger UI add the following dependencies to `pom.xml`:

```xml
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
```
Create `SwaggerConfig.kt` in `config` package.

```kotlin
package com.example.demo.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.builders.PathSelectors
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger2.annotations.EnableSwagger2

@EnableSwagger2
@Configuration
class SwaggerConfig {
    @Bean
    fun api(): Docket = Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .build()
}
```
@EnableSwagger2 annotation will enable Swagger UI for this applicaton.

Now if you run the application and visit [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html), you will be able to persist/retrieve product using swagger-ui.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xa5yoeyqwtvz0lpzwnke.png)

Code available on [github](https://github.com/Dimakzela/Springboot-JPA-Kotlin).

Thank you for reading. Please leave a comment or questing.