Use HttpMessageConverters in client and server config

This commit uses the new `HttpMessageConverters` class for the HTTP
client (`RestTemplate` and `RestClient`) and HTTP server support.

This effectively removes the duplication of classpath detection for
message converters in multiple places: clients, server and the multipart
converter itself.
Instead of creating multiple instances of the same converters, this
allows applications to share converter instances as much as possible for
better memory efficiency.

As a result, this change also deprecates configuration methods in the
MVC support that are superseded by the new methods introduced for
`HttpMessageConverters` support.

Closes gh-33894
This commit is contained in:
Brian Clozel
2025-06-26 17:19:33 +02:00
parent 1af25e9cb1
commit beedf0a76b
12 changed files with 130 additions and 546 deletions
@@ -17,23 +17,8 @@
package org.springframework.http.converter.support;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.cbor.JacksonCborHttpMessageConverter;
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.protobuf.KotlinSerializationProtobufHttpMessageConverter;
import org.springframework.http.converter.smile.JacksonSmileHttpMessageConverter;
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.yaml.JacksonYamlHttpMessageConverter;
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverters;
/**
* Extension of {@link org.springframework.http.converter.FormHttpMessageConverter},
@@ -47,117 +32,24 @@ import org.springframework.util.ClassUtils;
*/
public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {
private static final boolean jaxb2Present;
private static final boolean jacksonPresent;
private static final boolean jackson2Present;
private static final boolean jacksonXmlPresent;
private static final boolean jackson2XmlPresent;
private static final boolean jacksonSmilePresent;
private static final boolean jackson2SmilePresent;
private static final boolean jacksonCborPresent;
private static final boolean jackson2CborPresent;
private static final boolean jacksonYamlPresent;
private static final boolean jackson2YamlPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
private static final boolean kotlinSerializationCborPresent;
private static final boolean kotlinSerializationJsonPresent;
private static final boolean kotlinSerializationProtobufPresent;
static {
ClassLoader classLoader = AllEncompassingFormHttpMessageConverter.class.getClassLoader();
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader);
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jacksonXmlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2XmlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jacksonSmilePresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.smile.SmileMapper", classLoader);
jackson2SmilePresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jacksonCborPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.cbor.CBORMapper", classLoader);
jackson2CborPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
jacksonYamlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.yaml.YAMLMapper", classLoader);
jackson2YamlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", classLoader);
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", classLoader);
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
kotlinSerializationProtobufPresent = ClassUtils.isPresent("kotlinx.serialization.protobuf.ProtoBuf", classLoader);
}
/**
* Create a new {@link AllEncompassingFormHttpMessageConverter} instance
* that will auto-detect part converters.
*/
@SuppressWarnings("removal")
public AllEncompassingFormHttpMessageConverter() {
HttpMessageConverters.withDefaults().build().forClient().forEach(this::addPartConverter);
}
if (jaxb2Present && !jacksonXmlPresent && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}
if (jacksonPresent) {
addPartConverter(new JacksonJsonHttpMessageConverter());
}
else if (jackson2Present) {
addPartConverter(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
addPartConverter(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
addPartConverter(new JsonbHttpMessageConverter());
}
else if (kotlinSerializationJsonPresent) {
addPartConverter(new KotlinSerializationJsonHttpMessageConverter());
}
if (jacksonXmlPresent) {
addPartConverter(new JacksonXmlHttpMessageConverter());
}
else if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}
if (jacksonSmilePresent) {
addPartConverter(new JacksonSmileHttpMessageConverter());
}
else if (jackson2SmilePresent) {
addPartConverter(new MappingJackson2SmileHttpMessageConverter());
}
if (jacksonCborPresent) {
addPartConverter(new JacksonCborHttpMessageConverter());
}
else if (jackson2CborPresent) {
addPartConverter(new MappingJackson2CborHttpMessageConverter());
}
else if (kotlinSerializationCborPresent) {
addPartConverter(new KotlinSerializationCborHttpMessageConverter());
}
if (jacksonYamlPresent) {
addPartConverter(new JacksonYamlHttpMessageConverter());
}
else if (jackson2YamlPresent) {
addPartConverter(new MappingJackson2YamlHttpMessageConverter());
}
if (kotlinSerializationProtobufPresent) {
addPartConverter(new KotlinSerializationProtobufHttpMessageConverter());
}
/**
* Create a new {@link AllEncompassingFormHttpMessageConverter} instance
* using the given message converters.
* @param converters the message converters to use for part conversion
* @since 7.0
*/
public AllEncompassingFormHttpMessageConverter(Iterable<HttpMessageConverter<?>> converters) {
converters.forEach(this::addPartConverter);
}
}
@@ -43,29 +43,8 @@ import org.springframework.http.client.JettyClientHttpRequestFactory;
import org.springframework.http.client.ReactorClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.observation.ClientRequestObservationConvention;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.cbor.JacksonCborHttpMessageConverter;
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.protobuf.KotlinSerializationProtobufHttpMessageConverter;
import org.springframework.http.converter.smile.JacksonSmileHttpMessageConverter;
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.yaml.JacksonYamlHttpMessageConverter;
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverters;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -95,42 +74,6 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
private static final boolean jdkClientPresent;
// message factories
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jacksonPresent;
private static final boolean jackson2Present;
private static final boolean jacksonXmlPresent;
private static final boolean jackson2XmlPresent;
private static final boolean jacksonSmilePresent;
private static final boolean jackson2SmilePresent;
private static final boolean jacksonCborPresent;
private static final boolean jackson2CborPresent;
private static final boolean jacksonYamlPresent;
private static final boolean jackson2YamlPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
private static final boolean kotlinSerializationCborPresent;
private static final boolean kotlinSerializationJsonPresent;
private static final boolean kotlinSerializationProtobufPresent;
static {
ClassLoader loader = DefaultRestClientBuilder.class.getClassLoader();
@@ -138,25 +81,6 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
jettyClientPresent = ClassUtils.isPresent("org.eclipse.jetty.client.HttpClient", loader);
reactorNettyClientPresent = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", loader);
jdkClientPresent = ClassUtils.isPresent("java.net.http.HttpClient", loader);
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", loader);
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", loader);
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", loader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", loader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", loader);
jacksonXmlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.xml.XmlMapper", loader);
jackson2XmlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", loader);
jacksonSmilePresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.smile.SmileMapper", loader);
jackson2SmilePresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", loader);
jacksonCborPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.cbor.CBORMapper", loader);
jackson2CborPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", loader);
jacksonYamlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.yaml.YAMLMapper", loader);
jackson2YamlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", loader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", loader);
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", loader);
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", loader);
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", loader);
kotlinSerializationProtobufPresent = ClassUtils.isPresent("kotlinx.serialization.protobuf.ProtoBuf", loader);
}
private @Nullable String baseUrl;
@@ -444,9 +368,11 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
}
@Override
public RestClient.Builder messageConverters(List<HttpMessageConverter<?>> messageConverters) {
public RestClient.Builder messageConverters(Iterable<HttpMessageConverter<?>> messageConverters) {
validateConverters(messageConverters);
this.messageConverters = Collections.unmodifiableList(messageConverters);
List<HttpMessageConverter<?>> converters = new ArrayList<>();
messageConverters.forEach(converter -> converters.add(converter));
this.messageConverters = Collections.unmodifiableList(converters);
return this;
}
@@ -473,77 +399,16 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
private List<HttpMessageConverter<?>> initMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jacksonXmlPresent) {
this.messageConverters.add(new JacksonXmlHttpMessageConverter());
}
else if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (kotlinSerializationProtobufPresent) {
this.messageConverters.add(new KotlinSerializationProtobufHttpMessageConverter());
}
if (jacksonPresent) {
this.messageConverters.add(new JacksonJsonHttpMessageConverter());
}
else if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
else if (kotlinSerializationJsonPresent) {
this.messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
}
if (jacksonSmilePresent) {
this.messageConverters.add(new JacksonSmileHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jacksonCborPresent) {
this.messageConverters.add(new JacksonCborHttpMessageConverter());
}
else if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
else if (kotlinSerializationCborPresent) {
this.messageConverters.add(new KotlinSerializationCborHttpMessageConverter());
}
if (jacksonYamlPresent) {
this.messageConverters.add(new JacksonYamlHttpMessageConverter());
}
else if (jackson2YamlPresent) {
this.messageConverters.add(new MappingJackson2YamlHttpMessageConverter());
}
HttpMessageConverters.withDefaults().build().forClient().forEach(this.messageConverters::add);
}
return this.messageConverters;
}
private void validateConverters(@Nullable List<HttpMessageConverter<?>> messageConverters) {
Assert.notEmpty(messageConverters, "At least one HttpMessageConverter is required");
Assert.noNullElements(messageConverters, "The HttpMessageConverter list must not contain null elements");
private void validateConverters(@Nullable Iterable<HttpMessageConverter<?>> messageConverters) {
Assert.notNull(messageConverters, "At least one HttpMessageConverter is required");
Assert.isTrue(messageConverters.iterator().hasNext(), "At least one HttpMessageConverter is required");
messageConverters.forEach(converter ->
Assert.notNull(converter, "The HttpMessageConverter list must not contain null elements"));
}
@@ -450,7 +450,7 @@ public interface RestClient {
* @param configurer the configurer to apply on the list of default
* {@link HttpMessageConverter} pre-initialized
* @return this builder
* @see #messageConverters(List)
* @see #messageConverters(Iterable)
*/
Builder messageConverters(Consumer<List<HttpMessageConverter<?>>> configurer);
@@ -461,7 +461,7 @@ public interface RestClient {
* @since 6.2
* @see #messageConverters(Consumer)
*/
Builder messageConverters(List<HttpMessageConverter<?>> messageConverters);
Builder messageConverters(Iterable<HttpMessageConverter<?>> messageConverters);
/**
* Configure the {@link io.micrometer.observation.ObservationRegistry} to use
@@ -50,33 +50,11 @@ import org.springframework.http.client.observation.ClientRequestObservationConte
import org.springframework.http.client.observation.ClientRequestObservationConvention;
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
import org.springframework.http.client.support.InterceptingHttpAccessor;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverters;
import org.springframework.http.converter.SmartHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.cbor.JacksonCborHttpMessageConverter;
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.protobuf.KotlinSerializationProtobufHttpMessageConverter;
import org.springframework.http.converter.smile.JacksonSmileHttpMessageConverter;
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.yaml.JacksonYamlHttpMessageConverter;
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
@@ -125,65 +103,8 @@ import org.springframework.web.util.UriTemplateHandler;
*/
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jacksonPresent;
private static final boolean jackson2Present;
private static final boolean jacksonXmlPresent;
private static final boolean jackson2XmlPresent;
private static final boolean jacksonSmilePresent;
private static final boolean jackson2SmilePresent;
private static final boolean jacksonCborPresent;
private static final boolean jackson2CborPresent;
private static final boolean jacksonYamlPresent;
private static final boolean jackson2YamlPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
private static final boolean kotlinSerializationCborPresent;
private static final boolean kotlinSerializationJsonPresent;
private static final boolean kotlinSerializationProtobufPresent;
private static final ClientRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultClientRequestObservationConvention();
static {
ClassLoader classLoader = RestTemplate.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader);
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jacksonXmlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2XmlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jacksonSmilePresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.smile.SmileMapper", classLoader);
jackson2SmilePresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jacksonCborPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.cbor.CBORMapper", classLoader);
jackson2CborPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
jacksonYamlPresent = jacksonPresent && ClassUtils.isPresent("tools.jackson.dataformat.yaml.YAMLMapper", classLoader);
jackson2YamlPresent = jackson2Present && ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", classLoader);
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", classLoader);
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
kotlinSerializationProtobufPresent = ClassUtils.isPresent("kotlinx.serialization.protobuf.ProtoBuf", classLoader);
}
private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
@@ -202,72 +123,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
* Create a new instance with default settings.
* Default {@link HttpMessageConverter HttpMessageConverters} are initialized.
*/
@SuppressWarnings("removal")
public RestTemplate() {
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jacksonXmlPresent) {
this.messageConverters.add(new JacksonXmlHttpMessageConverter());
}
else if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (kotlinSerializationProtobufPresent) {
this.messageConverters.add(new KotlinSerializationProtobufHttpMessageConverter());
}
if (jacksonPresent) {
this.messageConverters.add(new JacksonJsonHttpMessageConverter());
}
else if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
else if (kotlinSerializationJsonPresent) {
this.messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
}
if (jacksonSmilePresent) {
this.messageConverters.add(new JacksonSmileHttpMessageConverter());
}
else if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jacksonCborPresent) {
this.messageConverters.add(new JacksonCborHttpMessageConverter());
}
else if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
else if (kotlinSerializationCborPresent) {
this.messageConverters.add(new KotlinSerializationCborHttpMessageConverter());
}
if (jacksonYamlPresent) {
this.messageConverters.add(new JacksonYamlHttpMessageConverter());
}
else if (jackson2YamlPresent) {
this.messageConverters.add(new MappingJackson2YamlHttpMessageConverter());
}
HttpMessageConverters.withDefaults().build().forClient().forEach(this.messageConverters::add);
updateErrorHandlerConverters();
this.uriTemplateHandler = initUriTemplateHandler();
}
@@ -288,9 +145,9 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
* @param messageConverters the list of converters to use
* @since 3.2.7
*/
public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
public RestTemplate(Iterable<HttpMessageConverter<?>> messageConverters) {
validateConverters(messageConverters);
this.messageConverters.addAll(messageConverters);
messageConverters.forEach(this.messageConverters::add);
this.uriTemplateHandler = initUriTemplateHandler();
updateErrorHandlerConverters();
}
@@ -323,9 +180,11 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
updateErrorHandlerConverters();
}
private void validateConverters(List<HttpMessageConverter<?>> messageConverters) {
Assert.notEmpty(messageConverters, "At least one HttpMessageConverter is required");
Assert.noNullElements(messageConverters, "The HttpMessageConverter list must not contain null elements");
private void validateConverters(Iterable<HttpMessageConverter<?>> messageConverters) {
Assert.notNull(messageConverters, "At least one HttpMessageConverter is required");
Assert.isTrue(messageConverters.iterator().hasNext(), "At least one HttpMessageConverter is required");
messageConverters.forEach(converter ->
Assert.notNull(converter, "The HttpMessageConverter list must not contain null elements"));
}
/**