From 70778095613142bb901bed7d21b93163f4b0c4a9 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 11 Feb 2025 20:05:53 +0100 Subject: [PATCH] Configure Kotlin JSON converters as Jackson alternative Prior to this commit, Spring MVC and WebFlux would consider the "kotlinx.serialization" JSON codecs and converters in addition to other JSON alternatives like Jackson, Gson and Jsonb. This would cause issues because while in most cases this library is only involved if the type is annotated with "@Serializable", this is not true for Java enums. In this particular case, the codec shadows Jackson and causes issues. This commit now considers kotlinx.serialization JSON support as an alternative to Jackson. Just like Jsonb and GSON, this is only auto-detected if Jackson is not present. We received consistent feedback that kotlinx.serialization is popular in Kotlin libraries and is often a transitive dependency. As a result, we cannot consider its presence on the classpath as a strong enough signal to configure it by default. Closes gh-34410 --- .../pages/web/webmvc/message-converters.adoc | 5 +++++ .../http/codec/support/BaseDefaultCodecs.java | 12 ++++++------ .../support/ClientCodecConfigurerTests.java | 17 ++++++----------- .../codec/support/CodecConfigurerTests.java | 14 ++++---------- .../support/ServerCodecConfigurerTests.java | 9 ++------- .../DelegatingWebFluxConfigurationTests.java | 2 +- .../WebFluxConfigurationSupportTests.java | 6 +++--- .../annotation/WebMvcConfigurationSupport.java | 6 +++--- 8 files changed, 30 insertions(+), 41 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/message-converters.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/message-converters.adoc index 2b86c30d53..fc6d5a1847 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc/message-converters.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc/message-converters.adoc @@ -54,6 +54,11 @@ You can customize XML mapping as needed through the use of JAXB or Jackson's pro When you need further control (for cases where custom XML serializers/deserializers need to be provided for specific types), you can inject a custom `XmlMapper` through the `ObjectMapper` property. By default, this converter supports `application/xml`. This requires the `com.fasterxml.jackson.dataformat:jackson-dataformat-xml` dependency. +| `KotlinSerializationJsonHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write JSON using `kotlinx.serialization`. +This converter is not configured by default, as this conflicts with Jackson. +Developers must configure it as an additional converter ahead of the Jackson one. + | `MappingJackson2CborHttpMessageConverter` | `com.fasterxml.jackson.dataformat:jackson-dataformat-cbor` diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java index 766e2b3f0a..50c532dec2 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java @@ -575,9 +575,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure (KotlinSerializationCborDecoder) this.kotlinSerializationCborDecoder : new KotlinSerializationCborDecoder())); } - if (kotlinSerializationJsonPresent) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder())); - } if (kotlinSerializationProtobufPresent) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.kotlinSerializationProtobufDecoder != null ? @@ -587,6 +584,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure if (jackson2Present) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJackson2JsonDecoder())); } + else if (kotlinSerializationJsonPresent) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder())); + } if (jackson2SmilePresent) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jackson2SmileDecoder != null ? (Jackson2SmileDecoder) this.jackson2SmileDecoder : new Jackson2SmileDecoder())); @@ -713,9 +713,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure (KotlinSerializationCborEncoder) this.kotlinSerializationCborEncoder : new KotlinSerializationCborEncoder())); } - if (kotlinSerializationJsonPresent) { - addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder())); - } if (kotlinSerializationProtobufPresent) { addCodec(writers, new EncoderHttpMessageWriter<>(this.kotlinSerializationProtobufEncoder != null ? (KotlinSerializationProtobufEncoder) this.kotlinSerializationProtobufEncoder : @@ -724,6 +721,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure if (jackson2Present) { addCodec(writers, new EncoderHttpMessageWriter<>(getJackson2JsonEncoder())); } + else if (kotlinSerializationJsonPresent) { + addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder())); + } if (jackson2SmilePresent) { addCodec(writers, new EncoderHttpMessageWriter<>(this.jackson2SmileEncoder != null ? (Jackson2SmileEncoder) this.jackson2SmileEncoder : new Jackson2SmileEncoder())); diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java index feddf42d62..049d46d402 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java @@ -60,8 +60,6 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; import org.springframework.http.codec.json.Jackson2SmileEncoder; -import org.springframework.http.codec.json.KotlinSerializationJsonDecoder; -import org.springframework.http.codec.json.KotlinSerializationJsonEncoder; import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; @@ -94,7 +92,7 @@ class ClientCodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(19); + assertThat(readers).hasSize(18); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -108,7 +106,6 @@ class ClientCodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); - assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class); @@ -120,7 +117,7 @@ class ClientCodecConfigurerTests { @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(16); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -132,7 +129,6 @@ class ClientCodecConfigurerTests { assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class); assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); - assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class); @@ -188,7 +184,7 @@ class ClientCodecConfigurerTests { int size = 99; this.configurer.defaultCodecs().maxInMemorySize(size); List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(19); + assertThat(readers).hasSize(18); assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); @@ -201,7 +197,6 @@ class ClientCodecConfigurerTests { nextReader(readers); assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jackson2JsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jackson2SmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); @@ -250,7 +245,7 @@ class ClientCodecConfigurerTests { writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); assertThat(sseDecoder).isNotSameAs(jackson2Decoder); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(16); } @Test // gh-24194 @@ -260,7 +255,7 @@ class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(16); } @Test @@ -274,7 +269,7 @@ class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(16); } private Decoder getNextDecoder(List> readers) { diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java index d0174ae237..45c8436659 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java @@ -53,8 +53,6 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; import org.springframework.http.codec.json.Jackson2SmileEncoder; -import org.springframework.http.codec.json.KotlinSerializationJsonDecoder; -import org.springframework.http.codec.json.KotlinSerializationJsonEncoder; import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; @@ -90,7 +88,7 @@ class CodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(18); + assertThat(readers).hasSize(17); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -103,7 +101,6 @@ class CodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); - assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class); @@ -114,7 +111,7 @@ class CodecConfigurerTests { @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(16); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -126,7 +123,6 @@ class CodecConfigurerTests { assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); - assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class); @@ -156,7 +152,7 @@ class CodecConfigurerTests { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(22); + assertThat(readers).hasSize(21); assertThat(getNextDecoder(readers)).isSameAs(customDecoder1); assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); @@ -173,7 +169,6 @@ class CodecConfigurerTests { assertThat(getNextDecoder(readers)).isSameAs(customDecoder2); assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader2); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); - assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class); @@ -203,7 +198,7 @@ class CodecConfigurerTests { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(21); + assertThat(writers).hasSize(20); assertThat(getNextEncoder(writers)).isSameAs(customEncoder1); assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); @@ -219,7 +214,6 @@ class CodecConfigurerTests { assertThat(getNextEncoder(writers)).isSameAs(customEncoder2); assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter2); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); - assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class); diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java index 1fc00e5639..7dd1508da5 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java @@ -58,8 +58,6 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; import org.springframework.http.codec.json.Jackson2SmileEncoder; -import org.springframework.http.codec.json.KotlinSerializationJsonDecoder; -import org.springframework.http.codec.json.KotlinSerializationJsonEncoder; import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; @@ -92,7 +90,7 @@ class ServerCodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(18); + assertThat(readers).hasSize(17); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -105,7 +103,6 @@ class ServerCodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); - assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class); @@ -116,7 +113,7 @@ class ServerCodecConfigurerTests { @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(18); + assertThat(writers).hasSize(17); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -128,7 +125,6 @@ class ServerCodecConfigurerTests { assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class); assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); - assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class); @@ -176,7 +172,6 @@ class ServerCodecConfigurerTests { assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jackson2JsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jackson2SmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java index 6348851971..9c5d52414b 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java @@ -116,7 +116,7 @@ public class DelegatingWebFluxConfigurationTests { boolean condition = initializer.getValidator() instanceof LocalValidatorFactoryBean; assertThat(condition).isTrue(); assertThat(initializer.getConversionService()).isSameAs(formatterRegistry.getValue()); - assertThat(codecsConfigurer.getValue().getReaders()).hasSize(16); + assertThat(codecsConfigurer.getValue().getReaders()).hasSize(15); } @Test diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java index e6662045af..870d793619 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java @@ -114,7 +114,7 @@ class WebFluxConfigurationSupportTests { assertThat(adapter).isNotNull(); List> readers = adapter.getMessageReaders(); - assertThat(readers).hasSize(16); + assertThat(readers).hasSize(15); ResolvableType multiValueMapType = forClassWithGenerics(MultiValueMap.class, String.class, String.class); @@ -169,7 +169,7 @@ class WebFluxConfigurationSupportTests { assertThat(handler.getOrder()).isEqualTo(0); List> writers = handler.getMessageWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(15); assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM); assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM); @@ -197,7 +197,7 @@ class WebFluxConfigurationSupportTests { assertThat(handler.getOrder()).isEqualTo(100); List> writers = handler.getMessageWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(15); assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM); assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index b9e4bed4de..8da9e517c7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -894,9 +894,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv if (kotlinSerializationCborPresent) { messageConverters.add(new KotlinSerializationCborHttpMessageConverter()); } - if (kotlinSerializationJsonPresent) { - messageConverters.add(new KotlinSerializationJsonHttpMessageConverter()); - } if (kotlinSerializationProtobufPresent) { messageConverters.add(new KotlinSerializationProtobufHttpMessageConverter()); } @@ -914,6 +911,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv else if (jsonbPresent) { messageConverters.add(new JsonbHttpMessageConverter()); } + else if (kotlinSerializationJsonPresent) { + messageConverters.add(new KotlinSerializationJsonHttpMessageConverter()); + } if (jackson2SmilePresent) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();