I discovered a breaking change between Spring Boot 3.1.3 and 3.1.4. It only affects users that are doing something wrong (imho), but as I discovered it in a test, maybe others have done the same mistake.

I have replicated it here: https://github.com/anderius/spring-requestbody-demo

The tests passes with Spring Boot 3.1.3, but change that to 3.1.4, and the test fails.

It seems query parameters was previously put into a parameter annotated with @RequestBody, but that changed in 3.1.4. The new behavior is the correct one, I believe.

Relevant code snippets:

@PostMapping(value = "/example", consumes = "application/x-www-form-urlencoded", produces = "text/plain")
public String take(@RequestBody String request) {
    return request;
}
@Test
void queryParameterIsRequestBody(@Autowired TestRestTemplate restTemplate) {

HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/x-www-form-urlencoded");

// Yes, I know this is not the way...
ResponseEntity<String> response = restTemplate.postForEntity("/example?query=123", new HttpEntity<Void>(headers), String.class);
assertThat(response.getBody()).isEqualTo("query=123");
}

Comment From: scottfrederick

Thanks for the sample. Spring Boot 3.1.4 upgraded the managed version of Spring Framework to from 6.0.11 to 6.0.12. With your sample, leaving the Spring Boot version at 3.1.3 and adding ext['spring-framework.version'] = '6.0.12' to upgrade the Spring Framework version to the same one used by default with Spring Boot 3.1.4 also reproduces the problem.

Comment From: anderius

Thank you for that clarification. I suspected the change might be in Spring Framework itself.

Do you want me to move the issue?

Comment From: scottfrederick

We can take care of moving the issue.

Comment From: rstoyanchev

This appears to be a regression as a result of #30942. We have logic for form data that reconstructs the request body from request parameters. This is to ensure consistent access to form data even if some code tries to access request parameters (e.g. from a Filter) which would cause the Servlet container to parse the body. The change in the referenced PR now relies on the Content-Length which in this scenario is 0.

Is your actual scenario sending a form data request with just a query and no body?

Comment From: anderius

I just had a test that did something wrong, and I have fixed that.

My purpose with this issue was just to raise the awareness of this changed behavior, as it COULD be a breaking change for someone else. For me it would be no problem if you closed this, because the breaking change was only if developers (potentially external clients) did something really wrong in the first place. :-)

Comment From: rstoyanchev

We've decided to undo the optimization from #30942 for 6.0.13, while for 6.1 we'll avoid reconstructing the body from request parameters, if the query string is not null.

Comment From: membersound

This also broke my application. Switching from @RequestBody to @RequestParam for the @PostRequest does NOT work, because then a json post body is injected as follows: LinkedHashMap("<json string...>", null).