Kotlin Serialization with Spring 5.3
Spring 5.3 adds the support of Kotlin serialization.
Spring Web MVC
KotlinSerializationJsonHttpMessageConverter
is the HttpMessageConverter
implementation that can read and write JSON using Kotlin serialization. If Kotlin serialization class kotlinx.serialization.json.Json
is in the classpath, then this converter will be registered automatically.
This converter tries to get the KSerializer
object for a given type to determine if an object can be serialized/deserialized using Kotlin serialization. Resolved serializers are put into the cache for later use.
private KSerializer<Object> serializer(Type type) {
KSerializer<Object> serializer = serializerCache.get(type);
if (serializer == null) {
serializer = SerializersKt.serializer(type);
serializerCache.put(type, serializer);
}
return serializer;
}
When you have both Kotlin serialization and Jackson on the classpath, Kotlin serialization will be checked first. This is because KotlinSerializationJsonHttpMessageConverter
appears before Jackson in the list. See the picture below.
Note
However, this only applies to Spring
5.3.2
. If you are using Spring5.3.1
, you'll find out that Jackson will be added instead of Kotlin serialization. Make sure that you using Spring5.3.2
or higer versions, if you want to have both Kotlin serialization and Jackson in the classpath.
Use Serializers Module
If you are using your own serializers module, you need to create your own KotlinSerializationJsonHttpMessageConverter
object.
The Kotlin code belows shows an example of open polymorphism with custom serializers module.
@Serializable
abstract class Base {
abstract val name: String
}
@Serializable
class Child1(override val name: String, val v1: String) : Base()
@Serializable
class Child2(override val name: String, val v2: String) : Base()
@Serializable
data class InheritanceData(
@Polymorphic val base: Base,
val extra: Int
)
val customModule = SerializersModule {
polymorphic(Base::class) {
subclass(Child1::class)
subclass(Child2::class)
}
}
To use this serializers module, we need to update HttpMessageConverter
objects. In the WebConfig
below, we override extendMessageConverters
method to replace existing KotlinSerializationJsonHttpMessageConverter
with a new object.
See this post for more details about customizing HttpMessageConverter
objects.
@Configuration
class WebConfig : WebMvcConfigurer {
override fun extendMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
val converter = KotlinSerializationJsonHttpMessageConverter(Json {
serializersModule = customModule
ignoreUnknownKeys = true
})
converters.forEachIndexed { index, httpMessageConverter ->
if (httpMessageConverter is KotlinSerializationJsonHttpMessageConverter) {
converters[index] = converter
return
}
}
}
}
See GitHub for the complete code.
Spring WebFlux
For Spring WebFlux, KotlinSerializationJsonEncoder
and KotlinSerializationJsonDecoder
are used for encoding and decoding respectively.
RestTemplate
When using RestTemplate
to send requests, you need to be careful when both Kotlin serialization and Jackson are in the classpath. RestTemplate
checks Jackson first and only adds one converter for JSON encoding/decoding.
To solve this issue, you can force RestTemplate
to use KotlinSerializationJsonHttpMessageConverter
by passing a list of HttpMessageConverter
objects.
val restTemplate = RestTemplate(listOf(KotlinSerializationJsonHttpMessageConverter()))
Source code
See GitHub.