Kotlin in Spring 5

Spring 5 introduces first-class support for Kotlin 1.1+. Besides Groovy, Kotlin is now another JVM programming language besides Java getting tightly integrated into Spring. Given the latest push from Google and Gradle this seems especially interesting.

Kotlin Extension API

With version 5 Pivotal releases a Kotlin extension API. Currently, those extensions are available for the following Spring framework packages:

Let’s have a look at some of the newly added extensions. Many extensions basically add function extensions to already exisiting Spring APIs, making those classes easier to use from within Kotlin code and using specific language features of Kotlin to make the code more concise.

For example, in package org.springframework.beans.factory, the extension fun <T : Any> BeanFactory.getBean(): T adds support in Springs org.springframework.beans.factory.BeanFactory for querying a bean by specifying the bean type as reified type parameter instead of a Class argument:

@Autowired
lateinit var beanFactory : BeanFactory

@PostConstruct
fun init() {
    val visitRepository = beanFactory.getBean<VisitRepository>()
    // ...
}

Another interesting extension example can be found in org.springframework.ui where operator overloading is used to add an array-like setter and getter to the Model interface (JavaDoc):

model["lastName"] = "Mustermann"

Besides Spring, other Pivotal related libraries like Spring Data or Reactor will or are already providing Kotlin extensions.

Null-Safety

Null-Safety and integration with Java frameworks has been a weak point with Kotlin for some time. With version 5, Spring adds null-safety indicating annotations (found in org.springframework.lang) in the whole Spring framework API. Spring uses @NonNull, @Nullable, @NonNullApi and @NonNullFields in the org.springframework.lang package. Those annotations are meta-annotated with JSR-305 annotations:

@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull(
    when = When.MAYBE
)
@TypeQualifierNickname
public @interface Nullable {}

These annotations are used through the Spring API but they can be leveraged by application programmers to to declare nullable or non-nullable fields that may also be inspected by tools or IDEs.

In the case of the Kotlin integration those (meta-) annotations are used to guarantee null-safety. Interestingly, Spring uses null-safety also in other parts, for example, when binding HTTP request parameters. When the request param is declared as @RequestParam name: String? Spring handles the name request parameter as optional and not as a required parameter. The same goes for lateinitbean injections.

GenericApplicationContext Bean DSL

GenericApplicationContext is another component getting a Kotlin extension. In the case of GenericApplicationContext, it is adding a new capability for defining application contexts. With Spring 5, besides Java and XML based configurations, a new Kotlin BeanDefinition DSL has been added. Here is an example from the Spring documentation:

fun beans() = beans {
  bean<UserHandler>()
  bean<Routes>()
  bean<WebHandler>("webHandler") {
    RouterFunctions.toWebHandler(
      ref<Routes>().router(),
      HandlerStrategies.builder().viewResolver(ref()).build()
    )
  }

  bean("messageSource") {
    ReloadableResourceBundleMessageSource().apply {
      setBasename("messages")
      setDefaultEncoding("UTF-8")
    }
  }

  bean {
    val prefix = "classpath:/templates/"
    val suffix = ".mustache"
    val loader = MustacheResourceTemplateLoader(prefix, suffix)
    MustacheViewResolver(Mustache.compiler().withLoader(loader)).apply {
      setPrefix(prefix)
      setSuffix(suffix)
    }
  }

  profile("foo") {
    bean<Foo>()
  }
}

Sealed Classes

When integrating a framework like Spring with Kotlin, an interesting aspect is the Kotlin default behavior when defining classes. Except a class is using the open modifier, the class is basically final and can not be extended. As Spring makes heavy use of proxies, the open modifier would be necessary in order for proxies to be generated. For this to solve, Kotling comes with its own compiler-plugin kotlin-spring which automatically configues the all-open plugin for classes annotated with @Component, @Controller, @Service and other stereotype annotations.

Configuration Properties

Another thing to be aware of when writing Kotlin Spring components together with @Value is Kotlin string interpolation. As $ is a special character in string interpolation it needs escaping when used in Kotlin classes:

@Value("\${property}")

Summary

This article shows some aspects of the new Kotlin integration new Spring Framework 5. Spring adds custom Kotlin extensions to Spring framework API classes and comes with a new Spring DSL builder.