From d0f57013b0ae9e716b370a28d4dcac40778ea4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 7 Nov 2025 16:44:51 +0100 Subject: [PATCH] Change default codecs ordering and add Jackson CBOR This commit updates BaseDefaultCodecs by adding Kotlin Serialization codecs before their Jackson/GSON counterparts with their new default behavior that only handles classes with `@Serializable` at type or generics level. When there is no alternative codec for the same mime type, Kotlin Serialization codecs handle all supported cases. This commit also adds missing Jackson CBOR codecs, and moves both CBOR and Protobuf codecs to a lower priority, as they are less commonly used than JSON ones, with the same ordering used on Spring MVC side. See gh-35761 Closes gh-35787 --- .../http/codec/CodecConfigurer.java | 18 ++ .../http/codec/support/BaseDefaultCodecs.java | 157 ++++++++++++++---- .../support/ClientCodecConfigurerTests.java | 34 ++-- .../codec/support/CodecConfigurerTests.java | 36 ++-- .../support/ServerCodecConfigurerTests.java | 26 ++- .../DelegatingWebFluxConfigurationTests.java | 2 +- 6 files changed, 207 insertions(+), 66 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java index 28c713a7bff..d5a7c5635a3 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java @@ -208,6 +208,24 @@ public interface CodecConfigurer { jacksonSmileEncoder(encoder); } + /** + * Override the default Jackson 3.x CBOR {@code Decoder}. + *

Note that {@link #maxInMemorySize(int)}, if configured, will be + * applied to the given decoder. + * @param decoder the decoder instance to use + * @since 7.0 + * @see org.springframework.http.codec.cbor.JacksonCborDecoder + */ + void jacksonCborDecoder(Decoder decoder); + + /** + * Override the default Jackson 3.x CBOR {@code Encoder}. + * @param encoder the encoder instance to use + * @since 7.0 + * @see org.springframework.http.codec.cbor.JacksonCborEncoder + */ + void jacksonCborEncoder(Encoder encoder); + /** * Override the default Protobuf {@code Decoder}. *

Note that {@link #maxInMemorySize(int)}, if configured, will be 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 8a4ab22d9b5..f37b4ef3514 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 @@ -51,6 +51,10 @@ import org.springframework.http.codec.ResourceHttpMessageReader; import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.ServerSentEventHttpMessageReader; import org.springframework.http.codec.ServerSentEventHttpMessageWriter; +import org.springframework.http.codec.cbor.Jackson2CborDecoder; +import org.springframework.http.codec.cbor.Jackson2CborEncoder; +import org.springframework.http.codec.cbor.JacksonCborDecoder; +import org.springframework.http.codec.cbor.JacksonCborEncoder; import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder; import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder; import org.springframework.http.codec.json.AbstractJackson2Decoder; @@ -101,6 +105,10 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private static final boolean JACKSON_2_SMILE_PRESENT; + private static final boolean JACKSON_CBOR_PRESENT; + + private static final boolean JACKSON_2_CBOR_PRESENT; + private static final boolean JAXB_2_PRESENT; private static final boolean PROTOBUF_PRESENT; @@ -121,6 +129,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure GSON_PRESENT = ClassUtils.isPresent("com.google.gson.Gson", classLoader); JACKSON_SMILE_PRESENT = JACKSON_PRESENT && ClassUtils.isPresent("tools.jackson.dataformat.smile.SmileMapper", classLoader); JACKSON_2_SMILE_PRESENT = JACKSON_2_PRESENT && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader); + JACKSON_CBOR_PRESENT = JACKSON_PRESENT && ClassUtils.isPresent("tools.jackson.dataformat.cbor.CBORMapper", classLoader); + JACKSON_2_CBOR_PRESENT = JACKSON_2_PRESENT && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.databind.CBORMapper", classLoader); JAXB_2_PRESENT = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader); PROTOBUF_PRESENT = ClassUtils.isPresent("com.google.protobuf.Message", classLoader); NETTY_BYTE_BUF_PRESENT = ClassUtils.isPresent("io.netty.buffer.ByteBuf", classLoader); @@ -142,6 +152,10 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private @Nullable Decoder jacksonSmileDecoder; + private @Nullable Encoder jacksonCborEncoder; + + private @Nullable Decoder jacksonCborDecoder; + private @Nullable Decoder protobufDecoder; private @Nullable Encoder protobufEncoder; @@ -221,6 +235,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure this.gsonEncoder = other.gsonEncoder; this.jacksonSmileDecoder = other.jacksonSmileDecoder; this.jacksonSmileEncoder = other.jacksonSmileEncoder; + this.jacksonCborDecoder = other.jacksonCborDecoder; + this.jacksonCborEncoder = other.jacksonCborEncoder; this.protobufDecoder = other.protobufDecoder; this.protobufEncoder = other.protobufEncoder; this.jaxb2Decoder = other.jaxb2Decoder; @@ -283,6 +299,19 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initTypedWriters(); } + @Override + public void jacksonCborDecoder(Decoder decoder) { + this.jacksonCborDecoder = decoder; + initObjectReaders(); + } + + @Override + public void jacksonCborEncoder(Encoder encoder) { + this.jacksonCborEncoder = encoder; + initObjectWriters(); + initTypedWriters(); + } + @Override public void protobufDecoder(Decoder decoder) { this.protobufDecoder = decoder; @@ -604,16 +633,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure if (!this.registerDefaults) { return; } - if (KOTLIN_SERIALIZATION_CBOR_PRESENT) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.kotlinSerializationCborDecoder != null ? - (KotlinSerializationCborDecoder) this.kotlinSerializationCborDecoder : - new KotlinSerializationCborDecoder())); - } - if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { - addCodec(this.objectReaders, - new DecoderHttpMessageReader<>(this.kotlinSerializationProtobufDecoder != null ? - (KotlinSerializationProtobufDecoder) this.kotlinSerializationProtobufDecoder : - new KotlinSerializationProtobufDecoder())); + if (KOTLIN_SERIALIZATION_JSON_PRESENT) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder())); } if (JACKSON_PRESENT || JACKSON_2_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonJsonDecoder())); @@ -621,16 +642,23 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure else if (GSON_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getGsonDecoder())); } - else if (KOTLIN_SERIALIZATION_JSON_PRESENT) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder())); - } if (JACKSON_SMILE_PRESENT || JACKSON_2_SMILE_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonSmileDecoder())); } + if (KOTLIN_SERIALIZATION_CBOR_PRESENT) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationCborDecoder())); + } + if (JACKSON_CBOR_PRESENT || JACKSON_2_CBOR_PRESENT) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonCborDecoder())); + } if (JAXB_2_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jaxb2Decoder != null ? (Jaxb2XmlDecoder) this.jaxb2Decoder : new Jaxb2XmlDecoder())); } + if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { + addCodec(this.objectReaders, + new DecoderHttpMessageReader<>(getKotlinSerializationProtobufDecoder())); + } // client vs server.. extendObjectReaders(this.objectReaders); @@ -744,15 +772,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure */ final List> getBaseObjectWriters() { List> writers = new ArrayList<>(); - if (KOTLIN_SERIALIZATION_CBOR_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(this.kotlinSerializationCborEncoder != null ? - (KotlinSerializationCborEncoder) this.kotlinSerializationCborEncoder : - new KotlinSerializationCborEncoder())); - } - if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(this.kotlinSerializationProtobufEncoder != null ? - (KotlinSerializationProtobufEncoder) this.kotlinSerializationProtobufEncoder : - new KotlinSerializationProtobufEncoder())); + if (KOTLIN_SERIALIZATION_JSON_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder())); } if (JACKSON_PRESENT || JACKSON_2_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonJsonEncoder())); @@ -760,16 +781,22 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure else if (GSON_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getGsonEncoder())); } - else if (KOTLIN_SERIALIZATION_JSON_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder())); - } if (JACKSON_SMILE_PRESENT || JACKSON_2_SMILE_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonSmileEncoder())); } + if (KOTLIN_SERIALIZATION_CBOR_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationCborEncoder())); + } + if (JACKSON_CBOR_PRESENT || JACKSON_2_CBOR_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonCborEncoder())); + } if (JAXB_2_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(this.jaxb2Encoder != null ? (Jaxb2XmlEncoder) this.jaxb2Encoder : new Jaxb2XmlEncoder())); } + if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationProtobufEncoder())); + } return writers; } @@ -876,14 +903,14 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure @SuppressWarnings("removal") protected Decoder getJacksonSmileDecoder() { if (this.jacksonSmileDecoder == null) { - if (JACKSON_PRESENT) { + if (JACKSON_SMILE_PRESENT) { this.jacksonSmileDecoder = new JacksonSmileDecoder(); } - else if (JACKSON_2_PRESENT) { + else if (JACKSON_2_SMILE_PRESENT) { this.jacksonSmileDecoder = new Jackson2SmileDecoder(); } else { - throw new IllegalStateException("Jackson not present"); + throw new IllegalStateException("Jackson Smile support not present"); } } return this.jacksonSmileDecoder; @@ -892,33 +919,97 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure @SuppressWarnings("removal") protected Encoder getJacksonSmileEncoder() { if (this.jacksonSmileEncoder == null) { - if (JACKSON_PRESENT) { + if (JACKSON_SMILE_PRESENT) { this.jacksonSmileEncoder = new JacksonSmileEncoder(); } - else if (JACKSON_2_PRESENT) { + else if (JACKSON_2_SMILE_PRESENT) { this.jacksonSmileEncoder = new Jackson2SmileEncoder(); } else { - throw new IllegalStateException("Jackson not present"); + throw new IllegalStateException("Jackson Smile support not present"); } } return this.jacksonSmileEncoder; } + @SuppressWarnings("removal") + protected Decoder getJacksonCborDecoder() { + if (this.jacksonCborDecoder == null) { + if (JACKSON_CBOR_PRESENT) { + this.jacksonCborDecoder = new JacksonCborDecoder(); + } + else if (JACKSON_2_CBOR_PRESENT) { + this.jacksonCborDecoder = new Jackson2CborDecoder(); + } + else { + throw new IllegalStateException("Jackson CBOR support not present"); + } + } + return this.jacksonCborDecoder; + } + + @SuppressWarnings("removal") + protected Encoder getJacksonCborEncoder() { + if (this.jacksonCborEncoder == null) { + if (JACKSON_CBOR_PRESENT) { + this.jacksonCborEncoder = new JacksonCborEncoder(); + } + else if (JACKSON_2_CBOR_PRESENT) { + this.jacksonCborEncoder = new Jackson2CborEncoder(); + } + else { + throw new IllegalStateException("Jackson CBOR support not present"); + } + } + return this.jacksonCborEncoder; + } + protected Decoder getKotlinSerializationJsonDecoder() { if (this.kotlinSerializationJsonDecoder == null) { - this.kotlinSerializationJsonDecoder = new KotlinSerializationJsonDecoder(); + this.kotlinSerializationJsonDecoder = (this.jacksonJsonDecoder != null || JACKSON_PRESENT || JACKSON_2_PRESENT || GSON_PRESENT ? + new KotlinSerializationJsonDecoder() : new KotlinSerializationJsonDecoder(type -> true)); } return this.kotlinSerializationJsonDecoder; } protected Encoder getKotlinSerializationJsonEncoder() { if (this.kotlinSerializationJsonEncoder == null) { - this.kotlinSerializationJsonEncoder = new KotlinSerializationJsonEncoder(); + this.kotlinSerializationJsonEncoder = (this.jacksonJsonDecoder != null || JACKSON_PRESENT || JACKSON_2_PRESENT || GSON_PRESENT ? + new KotlinSerializationJsonEncoder() : new KotlinSerializationJsonEncoder(type -> true)); } return this.kotlinSerializationJsonEncoder; } + protected Decoder getKotlinSerializationCborDecoder() { + if (this.kotlinSerializationCborDecoder == null) { + this.kotlinSerializationCborDecoder = (this.jacksonCborDecoder != null || JACKSON_CBOR_PRESENT ? + new KotlinSerializationCborDecoder() : new KotlinSerializationCborDecoder(type -> true)); + } + return this.kotlinSerializationCborDecoder; + } + + protected Encoder getKotlinSerializationCborEncoder() { + if (this.kotlinSerializationCborEncoder == null) { + this.kotlinSerializationCborEncoder = (this.jacksonCborDecoder != null || JACKSON_CBOR_PRESENT ? + new KotlinSerializationCborEncoder() : new KotlinSerializationCborEncoder(type -> true)); + } + return this.kotlinSerializationCborEncoder; + } + + protected Decoder getKotlinSerializationProtobufDecoder() { + if (this.kotlinSerializationProtobufDecoder == null) { + this.kotlinSerializationProtobufDecoder = new KotlinSerializationProtobufDecoder(type -> true); + } + return this.kotlinSerializationProtobufDecoder; + } + + protected Encoder getKotlinSerializationProtobufEncoder() { + if (this.kotlinSerializationProtobufEncoder == null) { + this.kotlinSerializationProtobufEncoder = new KotlinSerializationProtobufEncoder(type -> true); + } + return this.kotlinSerializationProtobufEncoder; + } + /** * Default implementation of {@link CodecConfigurer.MultipartCodecs}. 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 7847b0b64fc..3da317a699d 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 @@ -52,10 +52,14 @@ import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ResourceHttpMessageReader; import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.ServerSentEventHttpMessageReader; +import org.springframework.http.codec.cbor.JacksonCborDecoder; +import org.springframework.http.codec.cbor.JacksonCborEncoder; import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder; import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder; import org.springframework.http.codec.json.JacksonJsonDecoder; import org.springframework.http.codec.json.JacksonJsonEncoder; +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; @@ -91,7 +95,7 @@ class ClientCodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(18); + assertThat(readers).hasSize(20); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -104,11 +108,13 @@ class ClientCodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class); 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(KotlinSerializationProtobufDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonSmileDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonCborDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertSseReader(readers); assertStringDecoder(getNextDecoder(readers), false); } @@ -116,7 +122,7 @@ class ClientCodecConfigurerTests { @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(18); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -127,11 +133,13 @@ class ClientCodecConfigurerTests { assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class); 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(KotlinSerializationProtobufEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonSmileEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonCborEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertStringEncoder(getNextEncoder(writers), false); } @@ -161,7 +169,7 @@ class ClientCodecConfigurerTests { int size = 99; this.configurer.defaultCodecs().maxInMemorySize(size); List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(18); + assertThat(readers).hasSize(20); assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); @@ -173,11 +181,13 @@ class ClientCodecConfigurerTests { assertThat(((DefaultPartHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); nextReader(readers); assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((JacksonJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((JacksonSmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((JacksonCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jaxb2XmlDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); ServerSentEventHttpMessageReader reader = (ServerSentEventHttpMessageReader) nextReader(readers); assertThat(reader.getMaxInMemorySize()).isEqualTo(size); @@ -222,7 +232,7 @@ class ClientCodecConfigurerTests { writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); assertThat(sseDecoder).isNotSameAs(jacksonDecoder); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(18); } @Test // gh-24194 @@ -232,7 +242,7 @@ class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(18); } @Test @@ -246,7 +256,7 @@ class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(18); } 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 66c3f4982cd..f5a2681496a 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 @@ -47,10 +47,14 @@ import org.springframework.http.codec.ResourceHttpMessageReader; import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.ServerSentEventHttpMessageReader; import org.springframework.http.codec.ServerSentEventHttpMessageWriter; +import org.springframework.http.codec.cbor.JacksonCborDecoder; +import org.springframework.http.codec.cbor.JacksonCborEncoder; import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder; import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder; import org.springframework.http.codec.json.JacksonJsonDecoder; import org.springframework.http.codec.json.JacksonJsonEncoder; +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; @@ -88,7 +92,7 @@ class CodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(17); + assertThat(readers).hasSize(19); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -100,18 +104,20 @@ class CodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class); 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(KotlinSerializationProtobufDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonSmileDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonCborDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertStringDecoder(getNextDecoder(readers), false); } @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(16); + assertThat(writers).hasSize(18); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -122,11 +128,13 @@ class CodecConfigurerTests { assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class); 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(KotlinSerializationProtobufEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonSmileEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonCborEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertStringEncoder(getNextEncoder(writers), false); } @@ -152,7 +160,7 @@ class CodecConfigurerTests { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(21); + assertThat(readers).hasSize(23); assertThat(getNextDecoder(readers)).isSameAs(customDecoder1); assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); @@ -168,11 +176,13 @@ class CodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class); 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(KotlinSerializationProtobufDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonSmileDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonCborDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(StringDecoder.class); } @@ -198,7 +208,7 @@ class CodecConfigurerTests { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(20); + assertThat(writers).hasSize(22); assertThat(getNextEncoder(writers)).isSameAs(customEncoder1); assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); @@ -213,11 +223,13 @@ class CodecConfigurerTests { assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class); 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(KotlinSerializationProtobufEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonSmileEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonCborEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(CharSequenceEncoder.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 735c371c0fc..c6565730b87 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 @@ -52,10 +52,14 @@ import org.springframework.http.codec.ResourceHttpMessageReader; import org.springframework.http.codec.ResourceHttpMessageWriter; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.ServerSentEventHttpMessageWriter; +import org.springframework.http.codec.cbor.JacksonCborDecoder; +import org.springframework.http.codec.cbor.JacksonCborEncoder; import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder; import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder; import org.springframework.http.codec.json.JacksonJsonDecoder; import org.springframework.http.codec.json.JacksonJsonEncoder; +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; @@ -91,7 +95,7 @@ class ServerCodecConfigurerTests { @Test void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers).hasSize(17); + assertThat(readers).hasSize(19); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); @@ -103,18 +107,20 @@ class ServerCodecConfigurerTests { assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class); 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(KotlinSerializationProtobufDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonJsonDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonSmileDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(JacksonCborDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class); assertStringDecoder(getNextDecoder(readers), false); } @Test void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers).hasSize(17); + assertThat(writers).hasSize(19); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); @@ -125,11 +131,13 @@ class ServerCodecConfigurerTests { assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class); 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(KotlinSerializationProtobufEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonJsonEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonSmileEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(JacksonCborEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class); assertSseWriter(writers); assertStringEncoder(getNextEncoder(writers), false); } @@ -172,11 +180,13 @@ class ServerCodecConfigurerTests { assertThat((reader).getMaxInMemorySize()).isEqualTo(size); assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); - assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((JacksonJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((JacksonSmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((JacksonCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((Jaxb2XmlDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((StringDecoder) 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 c3bc8b75ea1..bf85f4d32ee 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 @@ -117,7 +117,7 @@ public class DelegatingWebFluxConfigurationTests { boolean condition = initializer.getValidator() instanceof LocalValidatorFactoryBean; assertThat(condition).isTrue(); assertThat(initializer.getConversionService()).isSameAs(formatterRegistry.getValue()); - assertThat(codecsConfigurer.getValue().getReaders()).hasSize(15); + assertThat(codecsConfigurer.getValue().getReaders()).hasSize(16); } @Test