Configure JSON and XML converters on HttpMessageConverters

This commit ensures that XML and JSON converters on both client and
server are configured using the dedicated methods on
`HttpMessageConverters`, instead of pushing them ahead of default
converters.

Closes gh-47917
Fixes gh-48096
This commit is contained in:
Brian Clozel
2025-11-12 16:15:13 +01:00
parent edd530c7e1
commit 44f0c772a2
3 changed files with 33 additions and 5 deletions
@@ -54,9 +54,12 @@ class DefaultClientHttpMessageConvertersCustomizer implements ClientHttpMessageC
else if (converter instanceof KotlinSerializationJsonHttpMessageConverter) {
builder.withKotlinSerializationJsonConverter(converter);
}
else if (converter.getSupportedMediaTypes().contains(MediaType.APPLICATION_JSON)) {
else if (supportsMediaType(converter, MediaType.APPLICATION_JSON)) {
builder.withJsonConverter(converter);
}
else if (supportsMediaType(converter, MediaType.APPLICATION_XML)) {
builder.withXmlConverter(converter);
}
else {
builder.addCustomConverter(converter);
}
@@ -64,4 +67,13 @@ class DefaultClientHttpMessageConvertersCustomizer implements ClientHttpMessageC
}
}
private static boolean supportsMediaType(HttpMessageConverter<?> converter, MediaType mediaType) {
for (MediaType supportedMediaType : converter.getSupportedMediaTypes()) {
if (supportedMediaType.equalsTypeAndSubtype(mediaType)) {
return true;
}
}
return false;
}
}
@@ -52,11 +52,14 @@ class DefaultServerHttpMessageConvertersCustomizer implements ServerHttpMessageC
builder.withStringConverter(converter);
}
else if (converter instanceof KotlinSerializationJsonHttpMessageConverter) {
builder.addCustomConverter(converter);
builder.withKotlinSerializationJsonConverter(converter);
}
else if (converter.getSupportedMediaTypes().contains(MediaType.APPLICATION_JSON)) {
else if (supportsMediaType(converter, MediaType.APPLICATION_JSON)) {
builder.withJsonConverter(converter);
}
else if (supportsMediaType(converter, MediaType.APPLICATION_XML)) {
builder.withXmlConverter(converter);
}
else {
builder.addCustomConverter(converter);
}
@@ -64,4 +67,13 @@ class DefaultServerHttpMessageConvertersCustomizer implements ServerHttpMessageC
}
}
private static boolean supportsMediaType(HttpMessageConverter<?> converter, MediaType mediaType) {
for (MediaType supportedMediaType : converter.getSupportedMediaTypes()) {
if (supportedMediaType.equalsTypeAndSubtype(mediaType)) {
return true;
}
}
return false;
}
}
@@ -418,13 +418,17 @@ class HttpMessageConvertersAutoConfigurationTests {
.getBean(ClientHttpMessageConvertersCustomizer.class);
ClientBuilder clientBuilder = HttpMessageConverters.forClient().registerDefaults();
clientCustomizer.customize(clientBuilder);
assertThat(clientBuilder.build()).contains(converter);
HttpMessageConverters clientConverters = clientBuilder.build();
assertThat(clientConverters).contains(converter);
assertThat(clientConverters).filteredOn((c) -> type.isAssignableFrom(c.getClass())).hasSize(1);
ServerHttpMessageConvertersCustomizer serverCustomizer = context
.getBean(ServerHttpMessageConvertersCustomizer.class);
ServerBuilder serverBuilder = HttpMessageConverters.forServer().registerDefaults();
serverCustomizer.customize(serverBuilder);
assertThat(serverBuilder.build()).contains(converter);
HttpMessageConverters serverConverters = serverBuilder.build();
assertThat(serverConverters).contains(converter);
assertThat(serverConverters).filteredOn((c) -> type.isAssignableFrom(c.getClass())).hasSize(1);
}
private void assertConvertersBeanRegisteredWithHttpMessageConverters(AssertableApplicationContext context,