diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/RouterFunctionMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/RouterFunctionMockMvcBuilder.java index 93ef21df6e..e2f8281962 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/RouterFunctionMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/RouterFunctionMockMvcBuilder.java @@ -268,6 +268,7 @@ public class RouterFunctionMockMvcBuilder extends AbstractMockMvcBuilder> converters) { converters.addAll(messageConverters); } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java index bce90b8cc0..f57cb2a1ae 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java @@ -470,6 +470,7 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder> converters) { converters.addAll(messageConverters); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java index dacf0bf96b..9aac205cd4 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/support/AllEncompassingFormHttpMessageConverter.java @@ -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> converters) { + converters.forEach(this::addPartConverter); } } diff --git a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClientBuilder.java b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClientBuilder.java index a52e34e81c..945598fd42 100644 --- a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClientBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClientBuilder.java @@ -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> messageConverters) { + public RestClient.Builder messageConverters(Iterable> messageConverters) { validateConverters(messageConverters); - this.messageConverters = Collections.unmodifiableList(messageConverters); + List> 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> 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> 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> 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")); } diff --git a/spring-web/src/main/java/org/springframework/web/client/RestClient.java b/spring-web/src/main/java/org/springframework/web/client/RestClient.java index f4327cd9c0..9b65ec47a0 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestClient.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestClient.java @@ -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>> configurer); @@ -461,7 +461,7 @@ public interface RestClient { * @since 6.2 * @see #messageConverters(Consumer) */ - Builder messageConverters(List> messageConverters); + Builder messageConverters(Iterable> messageConverters); /** * Configure the {@link io.micrometer.observation.ObservationRegistry} to use diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index 3e000395f1..5861306e2a 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -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> 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> messageConverters) { + public RestTemplate(Iterable> 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> 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> 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")); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java index acf9152439..5faa65d451 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; import org.springframework.util.CollectionUtils; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; @@ -121,11 +122,20 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { } @Override + protected void configureMessageConverters(HttpMessageConverters.Builder builder) { + this.configurers.configureMessageConverters(builder); + } + + @Override + @Deprecated(since = "7.0", forRemoval = true) + @SuppressWarnings("removal") protected void configureMessageConverters(List> converters) { this.configurers.configureMessageConverters(converters); } @Override + @Deprecated(since = "7.0", forRemoval = true) + @SuppressWarnings("removal") protected void extendMessageConverters(List> converters) { this.configurers.extendMessageConverters(converters); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index e0698900b8..a03789c6d5 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -39,31 +39,8 @@ import org.springframework.format.FormatterRegistry; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.MediaType; -import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.ResourceHttpMessageConverter; -import org.springframework.http.converter.ResourceRegionHttpMessageConverter; -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.Jackson2ObjectMapperBuilder; -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.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -906,15 +883,41 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv return this.messageConverters; } + /** - * Override this method to add custom {@link HttpMessageConverter HttpMessageConverters} + * Override this method to create a custom {@link HttpMessageConverters}. + * Converters will be used with the + * {@link RequestMappingHandlerAdapter} and the {@link ExceptionHandlerExceptionResolver}. + *

By default, this will create an instance with default message converters registered, + * if present on the classpath. + * @since 7.0 + */ + protected HttpMessageConverters createMessageConverters() { + HttpMessageConverters.Builder builder = HttpMessageConverters.withDefaults(); + configureMessageConverters(builder); + return builder.build(); + } + + /** + * Override this method to configure the message converters on the given + * {@link HttpMessageConverters.Builder builder}. + * @param builder the {@code HttpMessageConverters} builder to configure + * @since 7.0 + */ + protected void configureMessageConverters(HttpMessageConverters.Builder builder) { + } + + /** + * Override this method to add custom {@link HttpMessageConverter messsage converters} * to use with the {@link RequestMappingHandlerAdapter} and the * {@link ExceptionHandlerExceptionResolver}. *

Adding converters to the list turns off the default converters that would * otherwise be registered by default. Also see {@link #addDefaultHttpMessageConverters} * for adding default message converters. * @param converters a list to add message converters to (initially an empty list) + * @deprecated since 7.0 in favor of {@link #configureMessageConverters(HttpMessageConverters.Builder)} */ + @Deprecated(since = "7.0", forRemoval = true) protected void configureMessageConverters(List> converters) { } @@ -924,7 +927,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv * to be registered and then insert a custom converter through this method. * @param converters the list of configured converters to extend * @since 4.1.3 + * @deprecated since 7.0 in favor of {@link #configureMessageConverters(HttpMessageConverters.Builder)} */ + @Deprecated(since = "7.0", forRemoval = true) protected void extendMessageConverters(List> converters) { } @@ -932,93 +937,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv * Adds a set of default HttpMessageConverter instances to the given list. * Subclasses can call this method from {@link #configureMessageConverters}. * @param messageConverters the list to add the default message converters to + * @deprecated since 7.0 in favor of {@link #createMessageConverters()} */ - @SuppressWarnings("removal") + @Deprecated(since = "7.0", forRemoval = true) protected final void addDefaultHttpMessageConverters(List> messageConverters) { - messageConverters.add(new ByteArrayHttpMessageConverter()); - messageConverters.add(new StringHttpMessageConverter()); - messageConverters.add(new ResourceHttpMessageConverter()); - messageConverters.add(new ResourceRegionHttpMessageConverter()); - messageConverters.add(new AllEncompassingFormHttpMessageConverter()); - - if (romePresent) { - messageConverters.add(new AtomFeedHttpMessageConverter()); - messageConverters.add(new RssChannelHttpMessageConverter()); - } - - if (jacksonXmlPresent) { - messageConverters.add(new JacksonXmlHttpMessageConverter()); - } - else if (jackson2XmlPresent) { - Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml(); - if (this.applicationContext != null) { - builder.applicationContext(this.applicationContext); - } - messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build())); - } - else if (jaxb2Present) { - messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); - } - - if (kotlinSerializationProtobufPresent) { - messageConverters.add(new KotlinSerializationProtobufHttpMessageConverter()); - } - - if (jacksonPresent) { - messageConverters.add(new JacksonJsonHttpMessageConverter()); - } - else if (jackson2Present) { - Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json(); - if (this.applicationContext != null) { - builder.applicationContext(this.applicationContext); - } - messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build())); - } - else if (gsonPresent) { - messageConverters.add(new GsonHttpMessageConverter()); - } - else if (jsonbPresent) { - messageConverters.add(new JsonbHttpMessageConverter()); - } - else if (kotlinSerializationJsonPresent) { - messageConverters.add(new KotlinSerializationJsonHttpMessageConverter()); - } - - if (jacksonSmilePresent) { - messageConverters.add(new JacksonSmileHttpMessageConverter()); - } - else if (jackson2SmilePresent) { - Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile(); - if (this.applicationContext != null) { - builder.applicationContext(this.applicationContext); - } - messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build())); - } - - if (jacksonCborPresent) { - messageConverters.add(new JacksonCborHttpMessageConverter()); - } - else if (jackson2CborPresent) { - Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor(); - if (this.applicationContext != null) { - builder.applicationContext(this.applicationContext); - } - messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build())); - } - else if (kotlinSerializationCborPresent) { - messageConverters.add(new KotlinSerializationCborHttpMessageConverter()); - } - - if (jacksonYamlPresent) { - messageConverters.add(new JacksonYamlHttpMessageConverter()); - } - else if (jackson2YamlPresent) { - Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.yaml(); - if (this.applicationContext != null) { - builder.applicationContext(this.applicationContext); - } - messageConverters.add(new MappingJackson2YamlHttpMessageConverter(builder.build())); - } + HttpMessageConverters converters = createMessageConverters(); + converters.forServer().forEach(messageConverters::add); } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java index 11bd6bb83e..6dd42ce16d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java @@ -24,6 +24,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; import org.springframework.web.ErrorResponse; @@ -171,6 +172,14 @@ public interface WebMvcConfigurer { default void addReturnValueHandlers(List handlers) { } + /** + * Configure the {@link HttpMessageConverters} instance being built. + * @param builder the builder to configure + * @since 7.0 + */ + default void configureMessageConverters(HttpMessageConverters.Builder builder) { + } + /** * Configure the {@link HttpMessageConverter HttpMessageConverter}s for * reading from the request body and for writing to the response body. @@ -186,20 +195,24 @@ public interface WebMvcConfigurer { * {@link #extendMessageConverters(java.util.List)} to modify the configured * list of message converters. * @param converters initially an empty list of converters + * @deprecated since 7.0 in favor of configuring converters on {@link #configureMessageConverters(HttpMessageConverters.Builder)} */ + @Deprecated(since = "7.0", forRemoval = true) default void configureMessageConverters(List> converters) { } /** * Extend or modify the list of converters after it has been, either - * {@link #configureMessageConverters(List) configured} or initialized with + * {@link #configureMessageConverters(List) configured}, or initialized with * a default list. *

Note that the order of converter registration is important. Especially * in cases where clients accept {@link org.springframework.http.MediaType#ALL} * the converters configured earlier will be preferred. * @param converters the list of configured converters to be extended * @since 4.1.3 + * @deprecated since 7.0 in favor of configuring converters on {@link #configureMessageConverters(HttpMessageConverters.Builder)} */ + @Deprecated(since = "7.0", forRemoval = true) default void extendMessageConverters(List> converters) { } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java index 52fbd42eff..75f97a8f83 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java @@ -23,6 +23,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; import org.springframework.util.CollectionUtils; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; @@ -141,6 +142,15 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer { } @Override + public void configureMessageConverters(HttpMessageConverters.Builder builder) { + for (WebMvcConfigurer delegate : this.delegates) { + delegate.configureMessageConverters(builder); + } + } + + @Override + @Deprecated(since = "7.0", forRemoval = true) + @SuppressWarnings("removal") public void configureMessageConverters(List> converters) { for (WebMvcConfigurer delegate : this.delegates) { delegate.configureMessageConverters(converters); @@ -148,6 +158,8 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer { } @Override + @Deprecated(since = "7.0", forRemoval = true) + @SuppressWarnings("removal") public void extendMessageConverters(List> converters) { for (WebMvcConfigurer delegate : this.delegates) { delegate.extendMessageConverters(converters); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java index 6283939cc5..dd7d72d4b6 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java @@ -29,7 +29,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; import org.springframework.util.PathMatcher; import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; @@ -92,6 +92,7 @@ public class DelegatingWebMvcConfigurationTests { @Test + @SuppressWarnings("removal") void requestMappingHandlerAdapter() { webMvcConfig.setConfigurers(Collections.singletonList(webMvcConfigurer)); RequestMappingHandlerAdapter adapter = this.webMvcConfig.requestMappingHandlerAdapter( @@ -122,16 +123,11 @@ public class DelegatingWebMvcConfigurationTests { @Test void configureMessageConverters() { HttpMessageConverter customConverter = mock(); - StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); WebMvcConfigurer configurer = new WebMvcConfigurer() { - @Override - public void configureMessageConverters(List> converters) { - converters.add(stringConverter); - } @Override - public void extendMessageConverters(List> converters) { - converters.add(0, customConverter); + public void configureMessageConverters(HttpMessageConverters.Builder builder) { + builder.additionalMessageConverter(customConverter); } }; webMvcConfig.setConfigurers(Collections.singletonList(configurer)); @@ -141,9 +137,7 @@ public class DelegatingWebMvcConfigurationTests { this.webMvcConfig.mvcConversionService(), this.webMvcConfig.mvcValidator()); - assertThat(adapter.getMessageConverters()).as("One custom converter expected").hasSize(2); - assertThat(adapter.getMessageConverters()).element(0).isSameAs(customConverter); - assertThat(adapter.getMessageConverters()).element(1).isSameAs(stringConverter); + assertThat(adapter.getMessageConverters()).as("One custom converter expected").contains(customConverter); } @Test @@ -167,6 +161,7 @@ public class DelegatingWebMvcConfigurationTests { } @Test + @SuppressWarnings("removal") void handlerExceptionResolver() { webMvcConfig.setConfigurers(Collections.singletonList(webMvcConfigurer)); webMvcConfig.handlerExceptionResolver(webMvcConfig.mvcContentNegotiationManager()); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java index 0275705d5d..0a14b88893 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java @@ -36,8 +36,10 @@ import org.springframework.core.io.FileSystemResourceLoader; import org.springframework.format.FormatterRegistry; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverters; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; +import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.stereotype.Controller; import org.springframework.util.AntPathMatcher; @@ -209,9 +211,10 @@ class WebMvcConfigurationSupportExtensionTests { // Message converters List> converters = adapter.getMessageConverters(); - assertThat(converters).hasSize(2); + assertThat(converters).hasSize(3); assertThat(converters.get(0).getClass()).isEqualTo(StringHttpMessageConverter.class); assertThat(converters.get(1).getClass()).isEqualTo(JacksonJsonHttpMessageConverter.class); + assertThat(converters.get(2).getClass()).isEqualTo(AllEncompassingFormHttpMessageConverter.class); ObjectMapper objectMapper = ((JacksonJsonHttpMessageConverter) converters.get(1)).getObjectMapper(); assertThat(objectMapper.deserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse(); assertThat(objectMapper.deserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse(); @@ -347,6 +350,7 @@ class WebMvcConfigurationSupportExtensionTests { * plus WebMvcConfigurer can switch to extending WebMvcConfigurationSupport directly for * more advanced configuration needs. */ + @SuppressWarnings("removal") private static class TestWebMvcConfigurationSupport extends WebMvcConfigurationSupport implements WebMvcConfigurer { @Override @@ -354,9 +358,17 @@ class WebMvcConfigurationSupportExtensionTests { registry.addConverter(TestBean.class, String.class, testBean -> "converted"); } + @Override + protected HttpMessageConverters createMessageConverters() { + return HttpMessageConverters.create().jsonMessageConverter(new JacksonJsonHttpMessageConverter()).build(); + } + + @Override + public void configureMessageConverters(HttpMessageConverters.Builder builder) { + } + @Override public void configureMessageConverters(List> converters) { - converters.add(new JacksonJsonHttpMessageConverter()); } @Override