Ismaïl BENHALLAM
Posted on March 9, 2023
As we known, Kotlin has a compiler for the JVM platform, which means all the codes written in Kotlin can run on the JVM. Therefore, even though Spring itself is written entirely in Java, Spring applications could be written in Java or/and in Kotlin. However, Java and Kotlin are different languages, that means a Spring application written in Kotlin requires an extra configuration.
Additional dependencies
-
kotlin-stdlib-jdk8
: This dependency includes a variant of the standard Java 8 library to Kotlin with the required classes (needed for compatibility of Java and Kotlin). -
kotlin-reflect
: Spring often uses reflection, for example, to create proxy classes, but Java and Kotlin objects are various. Therefore, we have to work with them differently. This dependency adds the ability for Spring to work with objects by reflection. -
jackson-module-kotlin
: Java and Kotlin objects have different internal structures. The standard Jackson serializer for Java may not handle Kotlin objects in some cases. Specifically, this library add support for introspection of Kotlin method/constructor parameter names, without having to add explicit property name annotation. Assuming we are using Gradle with Kotlin DSL, including these plugins would looks like:
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2")
}
Note: You can use shorthand for a dependency on a Kotlin module, for example,
kotlin("test")
for"org.jetbrains.kotlin:kotlin-test"
dependencies {
implementation(kotlin("reflect:1.8.10"))
implementation(kotlin("stdlib-jdk8:1.8.10"))
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2")
}
Additional plugins
all-open plugin
In Koltin, classes and their members are final
by default. And as you may know, Spring inherits from our classes/interfaces to create proxy classes
and overrides some methods at the runtime (ex: interfaces extending CrudRepository
, classes using @Transactional
annotation…).
This means, we need to mark almost “everything” with the open
modifier, and that could be annoying.
all-open
plugin is here to the rescue! It make Kotlin classes annotated with a specific annotation and their members open, without using the modifier open
explicitly.
plugins {
kotlin("plugin.allopen") version "1.8.10" // check the latest version
}
Now we just need to specify these annotations in an allOpen
block in the Gradle build file :
allOpen {
annotation("org.springframework.stereotype.Repository")
annotation("org.springframework.transaction.annotation.Transactional")
annotation("org.springframework.context.annotation.Configuration")
annotation("com.example.annotation.SuperAnnotation")
//...
}
Cool, right ?
Still, that’s boilerplate work, we will have to remember it whenever we create a new project, or we will end-up by copy/pasting it each time, or…
The ultimate solution for all this is called kotlin-spring
plugin.
kotlin-spring plugin
plugins {
kotlin("plugin.spring") version "1.8.10"
}
The kotlin-spring
plugin is a wrapper on top of all-open
plugin. By using it, you can omit listing Spring annotations manually in an allOpen
block. The plugin specifies the following annotations:
@Component
@Transactional
@Async
@Cacheable
@SpringBootTest
And thanks to meta-annotations support, classes annotated with : @Configuration
, @Controller
, @RestController
, @Service
, @Repository
are automatically opened since these annotations are meta-annotated with @Component
.
Moreover, we still can have an allOpen
block and list other annotations if we need that.
Note: If you use the project template generated by start.spring.io, the kotlin-spring plugin will be enabled by default.
no-arg plugin
no-arg
plugin generates an additional zero-argument constructor for some classes, the selection of these classes is done the same way it’s done with all-open
plugin; The plugin is looking for classes annotated with a special annotation.
To use the plugin, we’ll have to start by including it in our build file :
plugins {
kotlin("plugin.noarg") version "1.8.10"
}
Then, similar to the allOpen
block related to all-open
plugin, we need to add a noArg
block :
noArg {
annotation("org.example.SomeAnnotation")
//...
}
This feature could be useful when we want to use Java Persistence API, it allows JPA to instantiate a class although it doesn’t have a zero-argument constructor. We just need to list the right annotations from JPA. Let’s see how we could do it in a better way with the next plugin.
kotlin-jpa plugin
As with the kotlin-spring
plugin wrapped on top of all-open
, kotlin-jp
is wrapped on top of no-arg
. The plugin specifies the following annotations as no-arg annotations automatically :
@Entity
@Embeddable
-
@MappedSuperclass
plugins {
kotlin("plugin.jpa") version "1.8.10"
}
Posted on March 9, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.