WebMvcConfigurationSupport
currently includes the AllEncompassingFormHttpMessageConverter
, see https://github.com/spring-projects/spring-framework/blob/6a8f0d6d7d4379860e0197f321f0784f8b46e5df/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java#L895.
Including a form converter on the server side makes no sense, as the servlet environment already provides form support. Effectively, including this converter can result in controllers returning form data, which makes no sense. So, the AllEncompassingFormHttpMessageConverter
should be removed from WebMvcConfigurationSupport
.
Comment From: snicoll
Here is a project that attempts to demonstrate the problem of writing a Map
: https://github.com/snicoll-scratches/spring-framework-32917
There are four tests: one local using MockMvc and three using a server with TestRestTemplate, RestTemplate and RestClient.
The MockMvc
test fails with:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /data
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.example.DemoController
Method = com.example.DemoController#plain()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/x-www-form-urlencoded", Content-Length:"20"]
Content type = application/x-www-form-urlencoded
Body = name=John+Doe&age=42
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /data
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.example.DemoController
Method = com.example.DemoController#plain()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/x-www-form-urlencoded", Content-Length:"20"]
Content type = application/x-www-form-urlencoded
Body = name=John+Doe&age=42
Forwarded URL = null
Redirected URL = null
Cookies = []
Content type [application/x-www-form-urlencoded] is not compatible with [application/json]
java.lang.AssertionError: Content type [application/x-www-form-urlencoded] is not compatible with [application/json]
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:39)
at org.springframework.test.util.AssertionErrors.assertTrue(AssertionErrors.java:73)
at org.springframework.test.web.servlet.result.ContentResultMatchers.lambda$contentTypeCompatibleWith$1(ContentResultMatchers.java:107)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:214)
at com.example.DemoControllerTests.getData(DemoControllerTests.java:29)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
The test with the RestClient
fails as follows:
Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/x-www-form-urlencoded]
org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/x-www-form-urlencoded]
at org.springframework.web.client.DefaultRestClient.readWithMessageConverters(DefaultRestClient.java:229)
at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.readBody(DefaultRestClient.java:689)
at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.toEntityInternal(DefaultRestClient.java:659)
at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.toEntity(DefaultRestClient.java:648)
at com.example.DemoControllerRestClientTests.getData(DemoControllerRestClientTests.java:46)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Switching to Spring Framework 6.2.0-M3
and they all work.
Comment From: rstoyanchev
It's not uncommon to access form data through an @RequestBody
parameter like in this test I think, so I'm not sure we can just exclude FormHttpMessageConverter
from server configuration. On the response side, the converter enables writing multipart that I believe is also a valid use case.
Comment From: poutsma
It's not uncommon to access form data through an
@RequestBody
parameter like in this test I think, so I'm not sure we can just excludeFormHttpMessageConverter
from server configuration. On the response side, the converter enables writing multipart that I believe is also a valid use case.
Understood. I guess we have no other way out that to revert #32826, as supporting maps will break too many applications. Fortunately there is still #32832, which we can keep.