Configure Jackson XML codecs when present

Closes gh-35752
This commit is contained in:
Sébastien Deleuze
2026-01-08 11:52:38 +01:00
parent a1204a405a
commit bf695c058d
2 changed files with 72 additions and 0 deletions
@@ -226,6 +226,24 @@ public interface CodecConfigurer {
*/
void jacksonCborEncoder(Encoder<?> encoder);
/**
* Override the default Jackson 3.x XML {@code Decoder}.
* <p>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}.
* <p>Note that {@link #maxInMemorySize(int)}, if configured, will be
@@ -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 ?