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 2b86c30d530..fc6d5a18476 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 766e2b3f0a1..50c532dec2a 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 feddf42d628..049d46d4020 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 d0174ae237e..45c8436659b 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 1fc00e56397..7dd1508da5e 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 63488519712..9c5d52414b4 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 e6662045afd..870d7936190 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 b9e4bed4dea..8da9e517c7a 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();