Skip Jaxb auto-detection in HttpMessageConverters for servers

Prior to this commit, `HttpMessageConverters` would consider the JAXB
message converters when building `HttpMessageConverters` instances.
We noticed that, on the server side, the Jakarta JAXB dependency is very
common on the classpath and often brought transitively. At runtime, this
converter can use significant CPU resources when checking the
`canRead`/`canWrite` methods. This can happen when content types aren't
strictly called out on controller endpoints.

This commit changes the auto-detection mechanism in
`HttpMessageConverters` to not consider the JAXB message converter for
server use cases.
For client use cases, we keep considering this converter as the runtime
cost there is lower.

Closes gh-36302
This commit is contained in:
Brian Clozel
2026-03-24 17:23:49 +01:00
parent f1a60f1664
commit 4c1b4f33a8
7 changed files with 65 additions and 19 deletions
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.test.web.servlet.client.RestTestClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -59,7 +60,9 @@ class XmlContentTests {
""";
private final RestTestClient client = RestTestClient.bindToController(new PersonController()).build();
private final RestTestClient client = RestTestClient.bindToController(new PersonController())
.configureServer(server -> server.setMessageConverters(new Jaxb2RootElementHttpMessageConverter()))
.build();
@Test
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.Person;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -58,6 +59,7 @@ class XmlContentAssertionTests {
private final WebTestClient testClient =
MockMvcWebTestClient.bindToController(new MusicController())
.messageConverters(new Jaxb2RootElementHttpMessageConverter())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
.configureClient()
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.Person;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -60,6 +61,7 @@ class XpathAssertionTests {
private final WebTestClient testClient =
MockMvcWebTestClient.bindToController(new MusicController())
.messageConverters(new Jaxb2RootElementHttpMessageConverter())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
.configureClient()
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.Person;
import org.springframework.test.web.servlet.MockMvc;
@@ -65,6 +66,7 @@ class XmlContentAssertionTests {
@BeforeEach
void setup() {
this.mockMvc = standaloneSetup(new MusicController())
.setMessageConverters(new Jaxb2RootElementHttpMessageConverter())
.defaultRequest(get("/").accept(MediaType.APPLICATION_XML, MediaType.parseMediaType("application/xml;charset=UTF-8")))
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.Person;
import org.springframework.test.web.servlet.MockMvc;
@@ -67,6 +68,7 @@ class XpathAssertionTests {
@BeforeEach
void setup() throws Exception {
this.mockMvc = standaloneSetup(new MusicController())
.setMessageConverters(new Jaxb2RootElementHttpMessageConverter())
.defaultRequest(get("/").accept(MediaType.APPLICATION_XML, MediaType.parseMediaType("application/xml;charset=UTF-8")))
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))