I’ve recently had the pleasure of trying out Kotlin for a few projects at work. It’s a promising JVM language from JetBrains that includes a lot of functional elements and a strong type system. I’m told it’s a combination of the best features of Scala and Groovy.
JetBrains promises 100% interoperability with Java, but it’s not immediately obvious how to get all the pieces working together. In this post I will outline some gotchas when building a Spring Boot “Hello World”. For the impatient, there’s a fully working example at the end.
The bootRun
task requires a public static void main(String[] args)
method on the @SpringBootApplication
annotated class. Kotlin does not have static class methods, but companion objects work just as well:
@SpringBootApplication
open class App {
companion object {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(App::class.java, *args)
}
}
}
Note that the class must also be marked open
and include the @JvmStatic
annotation on the companion object.
Generally speaking, dependency injection can be done via fields, constructor, and setters.
Field injection is relatively straightforward. The one caveat is to use the lateinit
keyword, as Kotlin does not allow late initialization by default.
class SampleController {
@Autowired
lateinit var sampleService: SampleService
}
Constructor-based injection is done via Kotlin’s primary constructors. Note the addition of constructor
in the class header:
class SampleController @Autowired constructor(val sampleService: SampleService) {
}
Setter-based injection can be done, but I wasn’t able to make it work with custom setters, which makes it a little useless anyway. Here’s the Kotlin syntax:
class SampleController {
lateinit var sampleService: SampleService
@Autowired set
}
Logger initialization (such as SLF4J) is usually done with LoggerFactory#getLogger(Class<?> clazz)
. To get the Java class for your Kotlin class, you’d need to use ::class.java
:
val logger = LoggerFactory.getLogger(SampleController::class.java)
Spring Boot uses Jackson to serialize and deserialize Java objects into Json and back. Serialization works as expected, but in order to get deserialization to work, you’d need to include the Jackson Kotlin Module. In addition to adding its dependencies in build.gradle
, you would also need to add the KotlinModule
as a @Bean
:
@SpringBootApplication
open class App {
@Bean
open fun kotlinModule() = KotlinModule()
}
To see everything working together, please check out the example on GitHub at https://github.com/nadavc/nadavc-blog-code/tree/master/kotlin-boot