mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-20 22:59:01 +00:00
Fix message converter customizers order
Prior to this commit, gh-48310 separated client and server message converter configurations by switching from message converter instances as beans in the application context, to server/client customizers that are applied to the `HttpMessageConverters` instances while being built. This change did not order the new ClientHttpMessageConvertersCustomizer or ServerHttpMessageConvertersCustomizer, letting those being at the "lowest precedence" default. As customizers, this means they are applied last and custom instances cannot take over. This commit ensures that such customizers provided by Spring Boot are now ordered at "0" to let applications ones take over. Fixes gh-48635
This commit is contained in:
committed by
Stéphane Nicoll
parent
5d1d5173ab
commit
9d1db6830f
+2
@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
@@ -48,6 +49,7 @@ class GsonHttpMessageConvertersConfiguration {
|
||||
static class GsonHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(GsonHttpMessageConverter.class)
|
||||
GsonHttpConvertersCustomizer gsonHttpMessageConvertersCustomizer(Gson gson) {
|
||||
return new GsonHttpConvertersCustomizer(gson);
|
||||
|
||||
+3
@@ -28,6 +28,7 @@ import org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageC
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
@@ -51,6 +52,7 @@ class Jackson2HttpMessageConvertersConfiguration {
|
||||
static class MappingJackson2HttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class)
|
||||
Jackson2JsonMessageConvertersCustomizer jackson2HttpMessageConvertersCustomizer(ObjectMapper objectMapper) {
|
||||
return new Jackson2JsonMessageConvertersCustomizer(objectMapper);
|
||||
@@ -64,6 +66,7 @@ class Jackson2HttpMessageConvertersConfiguration {
|
||||
protected static class MappingJackson2XmlHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter.class)
|
||||
Jackson2XmlMessageConvertersCustomizer mappingJackson2XmlHttpMessageConverter(
|
||||
Jackson2ObjectMapperBuilder builder) {
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
@@ -47,6 +48,7 @@ class JacksonHttpMessageConvertersConfiguration {
|
||||
static class JacksonJsonHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(value = JacksonJsonHttpMessageConverter.class,
|
||||
ignoredType = { "org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter",
|
||||
"org.springframework.data.rest.webmvc.alps.AlpsJacksonJsonHttpMessageConverter" })
|
||||
@@ -62,6 +64,7 @@ class JacksonHttpMessageConvertersConfiguration {
|
||||
protected static class JacksonXmlHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(JacksonXmlHttpMessageConverter.class)
|
||||
JacksonXmlHttpMessageConvertersCustomizer jacksonXmlHttpMessageConvertersCustomizer(XmlMapper xmlMapper) {
|
||||
return new JacksonXmlHttpMessageConvertersCustomizer(xmlMapper);
|
||||
|
||||
+2
@@ -28,6 +28,7 @@ import org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageC
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
@@ -47,6 +48,7 @@ class JsonbHttpMessageConvertersConfiguration {
|
||||
static class JsonbHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(JsonbHttpMessageConverter.class)
|
||||
JsonbHttpMessageConvertersCustomizer jsonbHttpMessageConvertersCustomizer(Jsonb jsonb) {
|
||||
return new JsonbHttpMessageConvertersCustomizer(jsonb);
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.util.ClassUtils;
|
||||
class KotlinSerializationHttpMessageConvertersConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnMissingBean(KotlinSerializationJsonHttpMessageConverter.class)
|
||||
KotlinSerializationJsonConvertersCustomizer kotlinSerializationJsonConvertersCustomizer(Json json,
|
||||
ResourceLoader resourceLoader) {
|
||||
|
||||
+64
-4
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot.http.converter.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -52,11 +53,16 @@ import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguratio
|
||||
import org.springframework.hateoas.RepresentationModel;
|
||||
import org.springframework.hateoas.mediatype.hal.forms.HalFormsHttpMessageConverter;
|
||||
import org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverters;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ClientBuilder;
|
||||
import org.springframework.http.converter.HttpMessageConverters.ServerBuilder;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
@@ -103,6 +109,14 @@ class HttpMessageConvertersAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jacksonServerCustomizer() {
|
||||
this.contextRunner.withUserConfiguration(CustomJsonConverterConfig.class).run((context) -> {
|
||||
assertConverterIsNotRegistered(context, JacksonJsonHttpMessageConverter.class);
|
||||
assertConverterIsRegistered(context, CustomConverter.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jacksonConverterWithBuilder() {
|
||||
this.contextRunner.withUserConfiguration(JacksonJsonMapperBuilderConfig.class).run((context) -> {
|
||||
@@ -455,16 +469,16 @@ class HttpMessageConvertersAutoConfigurationTests {
|
||||
|
||||
private HttpMessageConverters getClientConverters(ApplicationContext context) {
|
||||
ClientBuilder clientBuilder = HttpMessageConverters.forClient().registerDefaults();
|
||||
context.getBeansOfType(ClientHttpMessageConvertersCustomizer.class)
|
||||
.values()
|
||||
context.getBeanProvider(ClientHttpMessageConvertersCustomizer.class)
|
||||
.orderedStream()
|
||||
.forEach((customizer) -> customizer.customize(clientBuilder));
|
||||
return clientBuilder.build();
|
||||
}
|
||||
|
||||
private HttpMessageConverters getServerConverters(ApplicationContext context) {
|
||||
ServerBuilder serverBuilder = HttpMessageConverters.forServer().registerDefaults();
|
||||
context.getBeansOfType(ServerHttpMessageConvertersCustomizer.class)
|
||||
.values()
|
||||
context.getBeanProvider(ServerHttpMessageConvertersCustomizer.class)
|
||||
.orderedStream()
|
||||
.forEach((customizer) -> customizer.customize(serverBuilder));
|
||||
return serverBuilder.build();
|
||||
}
|
||||
@@ -503,6 +517,26 @@ class HttpMessageConvertersAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomJsonConverterConfig {
|
||||
|
||||
@Bean
|
||||
JsonMapper jsonMapper() {
|
||||
return new JsonMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ServerHttpMessageConvertersCustomizer jsonServerCustomizer() {
|
||||
return (configurer) -> configurer.withJsonConverter(new CustomConverter(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientHttpMessageConvertersCustomizer jsonClientCustomizer() {
|
||||
return (configurer) -> configurer.withJsonConverter(new CustomConverter(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JacksonJsonMapperBuilderConfig {
|
||||
|
||||
@@ -640,4 +674,30 @@ class HttpMessageConvertersAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
static class CustomConverter extends AbstractHttpMessageConverter<Object> {
|
||||
|
||||
CustomConverter(MediaType supportedMediaType) {
|
||||
super(supportedMediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user