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 d5a7c5635a3..5de3f28acb2 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 @@ -226,6 +226,24 @@ public interface CodecConfigurer { */ void jacksonCborEncoder(Encoder encoder); + /** + * Override the default Jackson 3.x XML {@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.3 + * @see org.springframework.http.codec.xml.JacksonXmlDecoder + */ + void jacksonXmlDecoder(Decoder decoder); + + /** + * Override the default Jackson 3.x XML {@code Encoder}. + * @param encoder the encoder instance to use + * @since 7.0.3 + * @see org.springframework.http.codec.xml.JacksonXmlEncoder + */ + void jacksonXmlEncoder(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 f37b4ef3514..2aff56ebf7e 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 @@ -81,6 +81,8 @@ import org.springframework.http.codec.protobuf.ProtobufEncoder; import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter; import org.springframework.http.codec.smile.JacksonSmileDecoder; import org.springframework.http.codec.smile.JacksonSmileEncoder; +import org.springframework.http.codec.xml.JacksonXmlDecoder; +import org.springframework.http.codec.xml.JacksonXmlEncoder; import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.http.codec.xml.Jaxb2XmlEncoder; import org.springframework.util.ClassUtils; @@ -109,6 +111,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private static final boolean JACKSON_2_CBOR_PRESENT; + private static final boolean JACKSON_XML_PRESENT; + private static final boolean JAXB_2_PRESENT; private static final boolean PROTOBUF_PRESENT; @@ -131,6 +135,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure 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); + JACKSON_XML_PRESENT = JACKSON_PRESENT && ClassUtils.isPresent("tools.jackson.dataformat.xml.XmlMapper", 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); @@ -156,6 +161,10 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private @Nullable Decoder jacksonCborDecoder; + private @Nullable Encoder jacksonXmlEncoder; + + private @Nullable Decoder jacksonXmlDecoder; + private @Nullable Decoder protobufDecoder; private @Nullable Encoder protobufEncoder; @@ -237,6 +246,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure this.jacksonSmileEncoder = other.jacksonSmileEncoder; this.jacksonCborDecoder = other.jacksonCborDecoder; this.jacksonCborEncoder = other.jacksonCborEncoder; + this.jacksonXmlDecoder = other.jacksonXmlDecoder; + this.jacksonXmlEncoder = other.jacksonXmlEncoder; this.protobufDecoder = other.protobufDecoder; this.protobufEncoder = other.protobufEncoder; this.jaxb2Decoder = other.jaxb2Decoder; @@ -312,6 +323,19 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure initTypedWriters(); } + @Override + public void jacksonXmlDecoder(Decoder decoder) { + this.jacksonXmlDecoder = decoder; + initObjectReaders(); + } + + @Override + public void jacksonXmlEncoder(Encoder encoder) { + this.jacksonXmlEncoder = encoder; + initObjectWriters(); + initTypedWriters(); + } + @Override public void protobufDecoder(Decoder decoder) { this.protobufDecoder = decoder; @@ -655,6 +679,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure addCodec(this.objectReaders, new DecoderHttpMessageReader<>(this.jaxb2Decoder != null ? (Jaxb2XmlDecoder) this.jaxb2Decoder : new Jaxb2XmlDecoder())); } + else if(JACKSON_XML_PRESENT) { + addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getJacksonXmlDecoder())); + } if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { addCodec(this.objectReaders, new DecoderHttpMessageReader<>(getKotlinSerializationProtobufDecoder())); @@ -794,6 +821,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure addCodec(writers, new EncoderHttpMessageWriter<>(this.jaxb2Encoder != null ? (Jaxb2XmlEncoder) this.jaxb2Encoder : new Jaxb2XmlEncoder())); } + else if (JACKSON_XML_PRESENT) { + addCodec(writers, new EncoderHttpMessageWriter<>(getJacksonXmlEncoder())); + } if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) { addCodec(writers, new EncoderHttpMessageWriter<>(getKotlinSerializationProtobufEncoder())); } @@ -964,6 +994,30 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure return this.jacksonCborEncoder; } + protected Decoder getJacksonXmlDecoder() { + if (this.jacksonXmlDecoder == null) { + if (JACKSON_XML_PRESENT) { + this.jacksonXmlDecoder = new JacksonXmlDecoder(); + } + else { + throw new IllegalStateException("Jackson XML support not present"); + } + } + return this.jacksonXmlDecoder; + } + + protected Encoder getJacksonXmlEncoder() { + if (this.jacksonXmlEncoder == null) { + if (JACKSON_XML_PRESENT) { + this.jacksonXmlEncoder = new JacksonXmlEncoder(); + } + else { + throw new IllegalStateException("Jackson XML support not present"); + } + } + return this.jacksonXmlEncoder; + } + protected Decoder getKotlinSerializationJsonDecoder() { if (this.kotlinSerializationJsonDecoder == null) { this.kotlinSerializationJsonDecoder = (this.jacksonJsonDecoder != null || JACKSON_PRESENT || JACKSON_2_PRESENT || GSON_PRESENT ?