-
Notifications
You must be signed in to change notification settings - Fork 41.2k
Provide auto-configuration for kotlinx.serialization and KotlinSerializationJsonHttpMessageConverter #39853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
spring.mvc.converters.preferred-json-mapper
is effectively ignored when certain serde frameworks are detected in the classpath, notably kotlinx.serialization
Until we find time to look at this in detail, as an alternative workaround, you may want to consider defining your own |
@wilkinsona Thanks for the alternative workaround. Can you maybe explain what the advantage of that approach is over the workaround I shared above? |
Using the |
@wilkinsona Thanks! By the way, when I have overridden Based on the example you linked to, I ended up with this (in Kotlin), which indeed works as well, at least in our case: import org.springframework.boot.autoconfigure.http.HttpMessageConverters
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.converter.AbstractKotlinSerializationHttpMessageConverter
import org.springframework.http.converter.HttpMessageConverter
@Configuration
class MessageConvertersConfig {
/**
* Bean provider that filters out standard [HttpMessageConverter]s that we don't want Spring to use, even when the
* serde frameworks for them are detected by Spring in the classpath.
*
* With thanks to https://github.com/spring-projects/spring-boot/issues/39853#issuecomment-1984360351 and
* https://github.com/spring-projects/spring-boot/issues/1482#issuecomment-61862787
*
* Should override [org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.messageConverters]
*/
@Bean
fun filteredMessageConverters(): HttpMessageConverters =
object : HttpMessageConverters() {
override fun postProcessConverters(converters: MutableList<HttpMessageConverter<*>>): MutableList<HttpMessageConverter<*>> {
converters.removeIf {
it is AbstractKotlinSerializationHttpMessageConverter<*>
}
return converters
}
}
} |
Yes, that's right. Just to make sure I have understood your situation correctly, am I right in understanding that:
Assuming that the above is correct, is kotlinx.serialization on the classpath for some other reason or is it there accidentally? Just trying to understand the scope of the problem and gauge how likely others are to be affected by it – this is the first time it's been raised in Boot's issues as far as I can remember. |
@wilkinsona You summarized the points correctly, but just to add some extra context to point 2: we are including a library dependency in our project, which uses The application as a whole, however, is still set up to use Jackson for (de)serialization (apart from the library that we're including for one specific purpose). We may decide to migrate the entire project from Jackson to By the way, thinking about it more, I'm not entirely sure about point 3. It's plausible, but I simply experienced certain integration tests in the application starting to fail, because it switched from Jackson to But even if it's not common to have multiple (Spring-supported) serde frameworks in the classspath, wouldn't it be reasonable to expect that the one explicitly selected in Anyway, I hope this answers your question. Just let me know in this thread if more information or clarification is needed. Thanks! |
Hi. I also encountered this issue. In my product, I use Jackson. One day, I added a certain library, and it implicitly depended on I'd be happy to see some progress. |
Fixing this in a maintenance release isn't straightforward, unfortunately. If we prioritise Jackson (or Gson, or Jsonb) over kotlinx.serialization it will be a breaking change for those who are relying on the current behavior where kotlinx.serialization is preferred. They could work around this by providing their own It could be argued that changing the behavior would align it with the documentation that currently states that Jackson is preferred. Unfortunately, given that things have behaved as they currently do ever since Spring Framework introduced support for kotlinx.serialization, I think the runtime behaviour has to trump the documentation. I think the best way to fix this is to add support for auto-configuring kotlinx.serialization. As part of that, we'd modify We can tackle this in 3.4. Until then, a custom |
As you mentioned, I agree that changing it is difficult because there are users who depend on the current behavior. I would appreciate it if there could be some sort of guide in the documentation for now. |
@wilkinsona I concur that you need to be considerate of people who depend on current behavior. But I don't think that applies when So a distinction should be made here, IMO:
Unless I somehow completely misunderstood what you are trying to say. |
Unfortunately, that's easier said than done.
We could add additional logic to |
Ah, so it's not trivial to distinguish between |
Duplicates #24238. |
Uh oh!
There was an error while loading. Please reload this page.
I initially reported this here and here at the Spring Framework project, but the
spring.mvc.converters.preferred-json-mapper
property is apparently specific to Spring Boot, so I'm reporting it here.Summary of the problem: when certain serde frameworks, notably
kotlinx.serialization
, are detected in the classpath by Spring, then the Spring Boot configuration propertyspring.mvc.converters.preferred-json-mapper
(defined inHttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY
) is effectively ignored.The reason for this is that
HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY
is only evaluated byGsonHttpMessageConvertersConfiguration
,JacksonHttpMessageConvertersConfiguration
andJsonbHttpMessageConverterConfiguration
. There is however no such configuration class forkotlinx.serialization
.Instead,
AllEncompassingFormHttpMessageConverter
just addskotlinx.serialization
to the standard HttpMessageConverters as provided byHttpMessageConvertersAutoConfiguration.messageConverters()
, and it happens to just get a higher priority than for instance Jackson when they are both in the classpath, regardless of whether the valuespring.mvc.converters.preferred-json-mapper
property is set and regardless of what value it is set to.To be more specific: bean provider method
HttpMessageConvertersAutoConfiguration.messageConverters()
invokes one of the constructors ofHttpMessageConverters
, which does not explicitly set the parameteraddDefaultConverters
tofalse
, and it remainstrue
by default, which results in a call to the private helper methodgetCombinedConverters()
, which (through some other private methods) eventually defers toWebMvcConfigurationSupport.getMessageConverters()
, which calls the protected methodaddDefaultHttpMessageConverters()
, which (among others) addsAllEncompassingFormHttpMessageConverter
, which then autodetects a number of hard-coded serde frameworks in itsinit
block.To reproduce, add the following to the
application.yml
of a Spring Boot project:Then add both Jackson and
kotlinx.serialization
dependencies to the project.You will find that Spring will automatically pick
KotlinSerializationJsonHttpMessageConverter
overMappingJackson2HttpMessageConverter
when (de)serializing JSON messages, even though Jackson was explicitly specified as the preferred JSON converter/mapper for the project.Also, according to
spring-configuration-metadata.json
, the propertyspring.mvc.converters.preferred-json-mapper
only supports the valuesgson
,jackson
andjsonb
. It doesn't have an option defined to explicitly selectkotlinx.serialization
or any of the other serde frameworks that Spring autodetects in thestatic
block of the following classes:This doesn't seem consistent, and it cost me quite a few hours to figure out why the addition of a non-spring library to my Spring project suddenly led to the project switching from Jackson to
kotlinx.serialization
, without me changing anything to the Spring configuration.In the meantime, I found that the following workaround worked for me to force Jackson to be used, even if
kotlinx.serialization
was included in the classpath as a transitive dependency of another library:But I'm reporting this as a bug, since this is not reasonably expected behavior, and it's not consistent (between the various supported serde frameworks) either.
Please let me know in this thread if you need any additional information.
Thank you for your time.
The text was updated successfully, but these errors were encountered: