diff --git a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java index 52e03c997f3..e85ff586fd1 100644 --- a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java +++ b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java @@ -19,11 +19,14 @@ package org.springframework.boot.http.converter.autoconfigure; import kotlinx.serialization.Serializable; import kotlinx.serialization.json.Json; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter; /** @@ -39,8 +42,23 @@ class KotlinSerializationHttpMessageConvertersConfiguration { @Bean @ConditionalOnMissingBean - KotlinSerializationJsonHttpMessageConverter kotlinSerializationJsonHttpMessageConverter(Json json) { - return new KotlinSerializationJsonHttpMessageConverter(json); + KotlinSerializationJsonHttpMessageConverter kotlinSerializationJsonHttpMessageConverter(Json json, + ObjectProvider> converters) { + return supportsApplicationJson(converters) ? new KotlinSerializationJsonHttpMessageConverter(json) + : new KotlinSerializationJsonHttpMessageConverter(json, (type) -> true); + } + + private boolean supportsApplicationJson(ObjectProvider> converters) { + return converters.orderedStream().filter(this::supportsApplicationJson).findFirst().isPresent(); + } + + private boolean supportsApplicationJson(HttpMessageConverter converter) { + for (MediaType mediaType : converter.getSupportedMediaTypes()) { + if (!mediaType.equals(MediaType.ALL) && mediaType.isCompatibleWith(MediaType.APPLICATION_JSON)) { + return true; + } + } + return false; } } diff --git a/module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationTests.java b/module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationTests.java index b22d73864d7..77b1e89806d 100644 --- a/module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationTests.java +++ b/module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationTests.java @@ -47,6 +47,7 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; import org.springframework.hateoas.RepresentationModel; import org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter; +import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverters; import org.springframework.http.converter.HttpMessageConverters.ClientBuilder; @@ -229,6 +230,24 @@ class HttpMessageConvertersAutoConfigurationTests { }); } + @Test + void kotlinSerializationUsesLimitedPredicateWhenOtherJsonConverterIsAvailable() { + allOptionsRunner().run((context) -> { + KotlinSerializationJsonHttpMessageConverter converter = context + .getBean(KotlinSerializationJsonHttpMessageConverter.class); + assertThat(converter.canWrite(Map.class, MediaType.APPLICATION_JSON)).isFalse(); + }); + } + + @Test + void kotlinSerializationUsesUnrestrictedPredicateWhenNoOtherJsonConverterIsAvailable() { + this.contextRunner.withBean(Json.class, () -> Json.Default).run((context) -> { + KotlinSerializationJsonHttpMessageConverter converter = context + .getBean(KotlinSerializationJsonHttpMessageConverter.class); + assertThat(converter.canWrite(Map.class, MediaType.APPLICATION_JSON)).isTrue(); + }); + } + @Test void stringDefaultConverter() { this.contextRunner.run(assertConverter(StringHttpMessageConverter.class, "stringHttpMessageConverter"));