From 8631345b719f161da044b9a1529afd0b1778889f Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Thu, 2 Oct 2025 17:33:09 +0100 Subject: [PATCH] Refine Jackson 3 vs 2 setup in CodecConfigurer Closes gh-35562 --- .../http/codec/CodecConfigurer.java | 28 +++- .../http/codec/support/BaseDefaultCodecs.java | 143 +++++++++--------- .../support/ClientDefaultCodecsImpl.java | 3 +- .../support/ServerDefaultCodecsImpl.java | 3 +- 4 files changed, 96 insertions(+), 81 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 77378d7f88..05d134171e 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 @@ -115,6 +115,7 @@ public interface CodecConfigurer { *

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.json.JacksonJsonDecoder */ void jacksonJsonDecoder(Decoder decoder); @@ -125,12 +126,17 @@ public interface CodecConfigurer { * applied to the given decoder. * @param decoder the decoder instance to use * @see org.springframework.http.codec.json.Jackson2JsonDecoder + * @deprecated in favor of {@link #jacksonJsonDecoder(Decoder)}. */ - void jackson2JsonDecoder(Decoder decoder); + @Deprecated(since = "7.0", forRemoval = true) + default void jackson2JsonDecoder(Decoder decoder) { + jacksonJsonDecoder(decoder); + } /** * Override the default Jackson 3.x JSON {@code Encoder}. * @param encoder the encoder instance to use + * @since 7.0 * @see org.springframework.http.codec.json.JacksonJsonEncoder */ void jacksonJsonEncoder(Encoder encoder); @@ -139,8 +145,12 @@ public interface CodecConfigurer { * Override the default Jackson 2.x JSON {@code Encoder}. * @param encoder the encoder instance to use * @see org.springframework.http.codec.json.Jackson2JsonEncoder + * @deprecated in favor of {@link #jacksonJsonEncoder(Encoder)}. */ - void jackson2JsonEncoder(Encoder encoder); + @Deprecated(since = "7.0", forRemoval = true) + default void jackson2JsonEncoder(Encoder encoder) { + jacksonJsonEncoder(encoder); + } /** * Override the default Gson {@code Decoder}. @@ -161,6 +171,7 @@ public interface CodecConfigurer { *

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 JacksonSmileDecoder */ void jacksonSmileDecoder(Decoder decoder); @@ -171,12 +182,17 @@ public interface CodecConfigurer { * applied to the given decoder. * @param decoder the decoder instance to use * @see org.springframework.http.codec.json.Jackson2SmileDecoder + * @deprecated in favor of {@link #jacksonSmileDecoder(Decoder)}. */ - void jackson2SmileDecoder(Decoder decoder); + @Deprecated(since = "7.0", forRemoval = true) + default void jackson2SmileDecoder(Decoder decoder) { + jacksonSmileDecoder(decoder); + } /** * Override the default Jackson 3.x Smile {@code Encoder}. * @param encoder the encoder instance to use + * @since 7.0 * @see JacksonSmileEncoder */ void jacksonSmileEncoder(Encoder encoder); @@ -185,8 +201,12 @@ public interface CodecConfigurer { * Override the default Jackson 2.x Smile {@code Encoder}. * @param encoder the encoder instance to use * @see org.springframework.http.codec.json.Jackson2SmileEncoder + * @deprecated in favor of {@link #jacksonSmileEncoder(Encoder)}. */ - void jackson2SmileEncoder(Encoder encoder); + @Deprecated(since = "7.0", forRemoval = true) + default void jackson2SmileEncoder(Encoder encoder) { + jacksonSmileEncoder(encoder); + }; /** * Override the default Protobuf {@code Decoder}. 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 7c42dfa0ff..b4fc017c3d 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 @@ -132,24 +132,16 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private @Nullable Decoder jacksonJsonDecoder; - private @Nullable Decoder jackson2JsonDecoder; - private @Nullable Encoder jacksonJsonEncoder; - private @Nullable Encoder jackson2JsonEncoder; - private @Nullable Decoder gsonDecoder; private @Nullable Encoder gsonEncoder; private @Nullable Encoder jacksonSmileEncoder; - private @Nullable Encoder jackson2SmileEncoder; - private @Nullable Decoder jacksonSmileDecoder; - private @Nullable Decoder jackson2SmileDecoder; - private @Nullable Decoder protobufDecoder; private @Nullable Encoder protobufEncoder; @@ -224,15 +216,11 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure */ protected BaseDefaultCodecs(BaseDefaultCodecs other) { this.jacksonJsonDecoder = other.jacksonJsonDecoder; - this.jackson2JsonDecoder = other.jackson2JsonDecoder; this.jacksonJsonEncoder = other.jacksonJsonEncoder; - this.jackson2JsonEncoder = other.jackson2JsonEncoder; this.gsonDecoder = other.gsonDecoder; this.gsonEncoder = other.gsonEncoder; this.jacksonSmileDecoder = other.jacksonSmileDecoder; - this.jackson2SmileDecoder = other.jackson2SmileDecoder; this.jacksonSmileEncoder = other.jacksonSmileEncoder; - this.jackson2SmileEncoder = other.jackson2SmileEncoder; this.protobufDecoder = other.protobufDecoder; this.protobufEncoder = other.protobufEncoder; this.jaxb2Decoder = other.jaxb2Decoder; @@ -262,12 +250,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initObjectReaders(); } - @Override - public void jackson2JsonDecoder(Decoder decoder) { - this.jackson2JsonDecoder = decoder; - initObjectReaders(); - } - @Override public void jacksonJsonEncoder(Encoder encoder) { this.jacksonJsonEncoder = encoder; @@ -275,13 +257,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initTypedWriters(); } - @Override - public void jackson2JsonEncoder(Encoder encoder) { - this.jackson2JsonEncoder = encoder; - initObjectWriters(); - initTypedWriters(); - } - @Override public void gsonDecoder(Decoder decoder) { this.gsonDecoder = decoder; @@ -301,12 +276,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initObjectReaders(); } - @Override - public void jackson2SmileDecoder(Decoder decoder) { - this.jackson2SmileDecoder = decoder; - initObjectReaders(); - } - @Override public void jacksonSmileEncoder(Encoder encoder) { this.jacksonSmileEncoder = encoder; @@ -314,13 +283,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initTypedWriters(); } - @Override - public void jackson2SmileEncoder(Encoder encoder) { - this.jackson2SmileEncoder = encoder; - initObjectWriters(); - initTypedWriters(); - } - @Override public void protobufDecoder(Decoder decoder) { this.protobufDecoder = decoder; @@ -637,7 +599,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure * Reset and initialize object readers. * @since 5.3.3 */ - @SuppressWarnings("removal") protected void initObjectReaders() { this.objectReaders.clear(); if (!this.registerDefaults) { @@ -654,25 +615,17 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure (KotlinSerializationProtobufDecoder) this.kotlinSerializationProtobufDecoder : new KotlinSerializationProtobufDecoder())); } - if (JACKSON_PRESENT) { + if (JACKSON_PRESENT || JACKSON_2_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonJsonDecoder())); } - else if (JACKSON_2_PRESENT) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJackson2JsonDecoder())); - } 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) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jacksonSmileDecoder != null ? - (JacksonSmileDecoder) this.jacksonSmileDecoder : new JacksonSmileDecoder())); - } - else if (JACKSON_2_SMILE_PRESENT) { - addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jackson2SmileDecoder != null ? - (Jackson2SmileDecoder) this.jackson2SmileDecoder : new Jackson2SmileDecoder())); + if (JACKSON_SMILE_PRESENT || JACKSON_2_SMILE_PRESENT) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonSmileDecoder())); } if (JAXB_2_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jaxb2Decoder != null ? @@ -789,7 +742,6 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure /** * Return "base" object writers only, i.e. common to client and server. */ - @SuppressWarnings("removal") final List> getBaseObjectWriters() { List> writers = new ArrayList<>(); if (KOTLIN_SERIALIZATION_CBOR_PRESENT) { @@ -802,25 +754,17 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure (KotlinSerializationProtobufEncoder) this.kotlinSerializationProtobufEncoder : new KotlinSerializationProtobufEncoder())); } - if (JACKSON_PRESENT) { + if (JACKSON_PRESENT || JACKSON_2_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonJsonEncoder())); } - else if (JACKSON_2_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(getJackson2JsonEncoder())); - } else if (GSON_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getGsonEncoder())); } else if (KOTLIN_SERIALIZATION_JSON_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder())); } - if (JACKSON_SMILE_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(this.jacksonSmileEncoder != null ? - (JacksonSmileEncoder) this.jacksonSmileEncoder : new JacksonSmileEncoder())); - } - else if (JACKSON_2_SMILE_PRESENT) { - addCodec(writers, new EncoderHttpMessageWriter<>(this.jackson2SmileEncoder != null ? - (Jackson2SmileEncoder) this.jackson2SmileEncoder : new Jackson2SmileEncoder())); + if (JACKSON_SMILE_PRESENT || JACKSON_2_SMILE_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonSmileEncoder())); } if (JAXB_2_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(this.jaxb2Encoder != null ? @@ -865,34 +809,55 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure // Accessors for use in subclasses... + @SuppressWarnings("removal") protected Decoder getJacksonJsonDecoder() { if (this.jacksonJsonDecoder == null) { - this.jacksonJsonDecoder = new JacksonJsonDecoder(); + if (JACKSON_PRESENT) { + this.jacksonJsonDecoder = new JacksonJsonDecoder(); + } + else if (JACKSON_2_PRESENT) { + this.jacksonJsonDecoder = new Jackson2JsonDecoder(); + } + else { + throw new IllegalStateException("Jackson not present"); + } } return this.jacksonJsonDecoder; } - @SuppressWarnings("removal") + /** + * Get or initialize a Jackson JSON decoder. + * @deprecated in favor of {@link #getJacksonJsonEncoder()} + */ + @Deprecated(since = "7.0", forRemoval = true) protected Decoder getJackson2JsonDecoder() { - if (this.jackson2JsonDecoder == null) { - this.jackson2JsonDecoder = new Jackson2JsonDecoder(); - } - return this.jackson2JsonDecoder; + return getJacksonJsonDecoder(); } + @SuppressWarnings("removal") protected Encoder getJacksonJsonEncoder() { if (this.jacksonJsonEncoder == null) { + if (JACKSON_PRESENT) { + this.jacksonJsonEncoder = new JacksonJsonEncoder(); + } + else if (JACKSON_2_PRESENT) { + this.jacksonJsonEncoder = new Jackson2JsonEncoder(); + } + else { + throw new IllegalStateException("Jackson not present"); + } this.jacksonJsonEncoder = new JacksonJsonEncoder(); } return this.jacksonJsonEncoder; } - @SuppressWarnings("removal") + /** + * Get or initialize a Jackson JSON encoder. + * @deprecated in favor of {@link #getJacksonJsonEncoder()} + */ + @Deprecated(since = "7.0", forRemoval = true) protected Encoder getJackson2JsonEncoder() { - if (this.jackson2JsonEncoder == null) { - this.jackson2JsonEncoder = new Jackson2JsonEncoder(); - } - return this.jackson2JsonEncoder; + return getJacksonJsonEncoder(); } protected Decoder getGsonDecoder() { @@ -909,6 +874,38 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure return this.gsonEncoder; } + @SuppressWarnings("removal") + protected Decoder getJacksonSmileDecoder() { + if (this.jacksonSmileDecoder == null) { + if (JACKSON_PRESENT) { + this.jacksonSmileDecoder = new JacksonSmileDecoder(); + } + else if (JACKSON_2_PRESENT) { + this.jacksonSmileDecoder = new Jackson2SmileDecoder(); + } + else { + throw new IllegalStateException("Jackson not present"); + } + } + return this.jacksonSmileDecoder; + } + + @SuppressWarnings("removal") + protected Encoder getJacksonSmileEncoder() { + if (this.jacksonSmileEncoder == null) { + if (JACKSON_PRESENT) { + this.jacksonSmileEncoder = new JacksonSmileEncoder(); + } + else if (JACKSON_2_PRESENT) { + this.jacksonSmileEncoder = new Jackson2SmileEncoder(); + } + else { + throw new IllegalStateException("Jackson not present"); + } + } + return this.jacksonSmileEncoder; + } + protected Decoder getKotlinSerializationJsonDecoder() { if (this.kotlinSerializationJsonDecoder == null) { this.kotlinSerializationJsonDecoder = new KotlinSerializationJsonDecoder(); diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java b/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java index 378cbdc444..357c4432a5 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java @@ -53,8 +53,7 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo protected void extendObjectReaders(List> objectReaders) { Decoder decoder = (this.sseDecoder != null ? this.sseDecoder : - JACKSON_PRESENT ? getJacksonJsonDecoder() : - JACKSON_2_PRESENT ? getJackson2JsonDecoder() : + (JACKSON_PRESENT || JACKSON_2_PRESENT) ? getJacksonJsonDecoder() : GSON_PRESENT ? getGsonDecoder() : KOTLIN_SERIALIZATION_JSON_PRESENT ? getKotlinSerializationJsonDecoder() : null); diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java b/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java index 40b9fa9fab..2275e6e897 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java @@ -57,8 +57,7 @@ class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecCo private @Nullable Encoder getSseEncoder() { return this.sseEncoder != null ? this.sseEncoder : - JACKSON_PRESENT ? getJacksonJsonEncoder() : - JACKSON_2_PRESENT ? getJackson2JsonEncoder() : + (JACKSON_PRESENT || JACKSON_2_PRESENT) ? getJacksonJsonEncoder() : KOTLIN_SERIALIZATION_JSON_PRESENT ? getKotlinSerializationJsonEncoder() : null; }