Hi, I have a spring boot application and I'm trying to use kotlin serialization, i have set up my pr...
g
Hi, I have a spring boot application and I'm trying to use kotlin serialization, i have set up my project according by the springs docs. So I trying to test my controller if it returns the expected result. If I boot my application the content is not as expected as I have some transient fields in my class but nonetheless the appear on the response. So I created a test to assert the expected body but I'm getting an error from fasterxml.jackson invalid definition. So far my guess is for some reason I'm not using kotlins seralization. The catch is my object has a field with type any and marked with contextual , so I tried to create my own serializers module based on kotlin.serialization docs/guides but I had no luck to be able to tell spring to use my own custom serializers module . Any idea ? Thanks In advance !
I have created a custom serializer for the Any field but still is not working, though i expected that to work so probably im missing something? I have created a sample version of my poblem if anyone wants to check out : https://github.com/GeorgePap-719/simple-springboot-kotlinx-serialization/tree/master
TL;DR : The error i get is Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
org.apiplayground.apitest.payload.SharedPayload
(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
e
Hi George! I think you need to configure KotlinX serialization both for inbound requests and outbound requests.. This is done by registering a
WebFluxConfigurer
bean and
ExchangeStrategies
.. We have something like this in place.
Copy code
@Configuration
class SerializationConfig {

    @Bean
    fun json(): Json = Json {
       // Your config for KotlinX serialization
    }

    @Bean
    fun kotlinSerializationJsonEncoder(json: Json) = KotlinSerializationJsonEncoder(json)

    @Bean
    fun kotlinSerializationJsonDecoder(json: Json) = KotlinSerializationJsonDecoder(json)

    @Bean
    fun exchangeStrategies(
        encoder: KotlinSerializationJsonEncoder,
        decoder: KotlinSerializationJsonDecoder
    ): ExchangeStrategies =
        ExchangeStrategies.builder()
            .codecs { configurer ->
                configurer.defaultCodecs()
                    .apply {
                        kotlinSerializationJsonDecoder(decoder)
                        kotlinSerializationJsonEncoder(encoder)
                    }
            }
            .build()

    @Bean
    fun webFluxConfigurer(
        encoder: KotlinSerializationJsonEncoder,
        decoder: KotlinSerializationJsonDecoder
    ): WebFluxConfigurer =
        object : WebFluxConfigurer {
            override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
                configurer.defaultCodecs().kotlinSerializationJsonEncoder(encoder)
                configurer.defaultCodecs().kotlinSerializationJsonDecoder(decoder)
            }
        }
}
ExchangeStrategies
will be used by
WebClient
for outbound requests and
WebFluxConfigurer
setups up your controllers to use KotlinX.serialization for inbound requests (IIRC)
g
Thanks for your help Emil, but it seems that neither that config helps. Although now i know how to inject my custom serializersmodule in spring. The error seems to be the same and again when i hit the api the transient fields still show up
e
Which transient fields? Can you point to a class in your example
g
Sure, my package org.apiplayground.apitest.payload.SharedSharedPayloadFromBuilder
has some transient fields including the r mHttpStatus, which i can still see when i call the api manual. Also when i run the test for the same controller it breaks up
e
Seems jackson is still in use.. can be tested by adding these annotations to check what is picked upπŸ€”
g
yup that's actually my problem and im not sure why jackson is in use, also i think that;s verify why the test is breaking and complaining about fasterxml.jackson
s
Jackson is likely transitively included via the Spring Boot Web or WebFlux starter. Exclude it and Kotlin Serialization should be used automatically.
g
Thanks for the help, Sebastien, yup that's indeed force to use kotlin's serialization, though now i get the exception: Open polymorphic serialization is not supported yet. I knew beforehand that indeed is not supported by spring yet but i think my approach with providing my own serializer for the type Any should not count as open polymorphism, or at least that's my understanding from reading the docs. (probably im missing smth)
So, any ideas? Or should i just avoid the Any type?
Also, strangely enough, after i converted Any to String, i still get the same error,
Copy code
Open polymorphic serialization is not supported yet
But, i think im not using at all open polymorphic serialization. Just simple @Serializable with some Transient fields. This can be checked out on my example project on github.
e
What serialier is used?
g
Json
e
I mean actual class serializer, not engine πŸ™‚
g
So, after you pointed where to add the breakpoint, it indeed tries to use The SharedPayload interface as a polymorphicSerializer
Well, i just looked up again the docs and
Copy code
Interfaces are used in the Kotlin language to enable polymorphism, so all interfaces are considered to be implicitly serializable with the PolymorphicSerializer strategy.
So by default my interfaces is considered polymorphic , im dumbπŸ™ƒ
Any known workaroud? It doesn't feel right to avoid that interface.. But anyway i appreciate the help emil πŸ™‚
e
IIRC it works fine to use sealed class hierarchies. I think that’s what I would prefer
πŸ‘Œ 1
279 Views