
SpringBoot Rest with Kotlin
There aren’t many Androids, but it’s time to take a look at how Kotlin can work in other environments. For example, in a classic Enterprise solution like Rest service
To get started, here is my build file (I decided to use gradle):
buildscript {
ext {
kotlinVersion = '1.2.71'
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: "kotlin-jpa"
group = 'com.criticalgnome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-mustache')
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
runtime('com.h2database:h2')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
A few notes: SpringBoot is used with the Web, Mustache, and H2 database plugins. Used the kotlin-jpa plugin to create empty constructors in entity objects. Hibernate will not start without this.
Now going to the main files. The starter class is very concise:
@SpringBootApplication
class SpringBootKotlinDemoApplication
fun main(args: Array<String>) {
runApplication<SpringBootKotlinDemoApplication>(*args)
}
Now in turn is an entity object. For the test, it will be very simple, but it supports all possible dependencies, however complex:
@Entity
data class User(
@Id @GeneratedValue val id: Long,
val firstName: String,
val lastName: String
)
Now is time to add the repository. As with Java, it is very minimalistic (at least when using only standard CRUD operations):
@Repository
interface UserRepository: JpaRepository<User, Long>
The time has come for the business logic layer. For some reason, I decided to do it wisely and immediately put standard operations into a separate base class. These guys are:
open class BaseService<T>(private val repository: JpaRepository<T, Long>) {
fun getOne(id: Long): T = repository.getOne(id)
fun getAll(pageable: Pageable): Page<T> = repository.findAll(pageable)
fun save(t: T): T = repository.save(t)
fun delete(id: Long) = repository.deleteById(id)
fun count(): Long = repository.count()
}
@Service
class UserService(@Autowired private val userRepository: UserRepository): BaseService<User>(userRepository)
Now add a controller. Since I do same with the base class of the service, I will do the same trick here:
open class BaseController<T>(private val service: BaseService<T>) {
@GetMapping("{id}") fun getOne(@PathVariable id: Long): T = service.getOne(id)
@GetMapping fun getAll(pageable: Pageable): Page<T> = service.getAll(pageable)
@PostMapping fun create(@RequestBody t: T): T = service.save(t)
@PutMapping fun update(@RequestBody t: T): T = service.save(t)
@DeleteMapping("{id}") fun delete(@PathVariable id: Long) = service.delete(id)
@GetMapping("count") fun count(): Long = service.count()
}
@RestController
@RequestMapping("users")
class UserController(@Autowired private val userService: UserService): BaseController<User, Long>(userService)
And it’s all. You can run and enjoy. As always, I put all the code on my GitLab, otherwise GitHub behaves strangely today 🙁