Affects: Spring Framework 5.2.7
My app was working correctly with Spring Boot 2.3.0 which uses Spring Framework 5.2.6
On updating to Spring Boot 2.3.1 which users 5.2.7, some of my Web MVC forms no longer work.
The forms in question have an array of entities as one of the fields, e.g. Location[] locations, where Location is a JPA Entity I've created.
My form submits a group of checkboxes with the values as entity IDs, and up until Boot 2.3.1 Spring was transparently mapping the ID numbers submitted to the entities.
I've been digging through TypeConverterDelegate and GenericConversionService but can't seem to identify why this has stopped working. In 5.2.6 it looks like ArrayToArrayConverter kicks in to convert the String[] to a Location[] via a CollectionToArrayConverter. This then looks up a DomainClassConverter.ToEntityConverter which does the "clever bit" of getting the ID into an actual entity.
Comment From: sbrannen
Can you please provide a minimal working example that reproduces the behavior you are describing (ideally in a public repository that we can clone (such as a GitHub repo) or as a zip file that we can download)?
Comment From: leccelecce
Hi @sbrannen - minimal example attached.
1) Run the app as a standard Spring Boot app 2) Open localhost:8080 3) Click two checkboxes and hit save 4) Check the log entry on System.out
If you run this with Boot 2.3.0, it correctly picks up the two entities with IDs 1 and 2 (or whatever is assigned by H2).
If you run this with Boot 2.3.1, something seems to go wrong and the entities aren't mapped correctly - weirdly it almost looks like the ID is ending up in the name field.
Comment From: sbrannen
Thanks for the repro.zip
.
I had to change the name of the form in the HTML template to candidateForm
, but once I did that I was able to confirm the following.
Spring Boot 2.3.0
Saved successfully with locations: [{id=1, name=Test One}, {id=2, name=Test Two}]
Spring Boot 2.3.1
Saved successfully with locations: [{id=null, name=1}, {id=null, name=2}]
Thus, it indeed appears that something has changed which is causing this different behavior.
We'll investigate it!
Comment From: sbrannen
OK. I think I've narrowed this down to a change in Spring Data.
By staying on Spring Boot 2.3.0 but upgrading to Spring Framework 5.2.7, as can be seen in the following updated properties for the Maven pom.xml
, we continue to see the expected behavior.
<properties>
<java.version>14</java.version>
<spring-framework.version>5.2.7.RELEASE</spring-framework.version>
</properties>
However, if we upgrade the Spring Data version as follows, we see the change in behavior.
<properties>
<java.version>14</java.version>
<spring-framework.version>5.2.7.RELEASE</spring-framework.version>
<spring-data-releasetrain.version>Neumann-SR1</spring-data-releasetrain.version>
</properties>
@mp911de or @odrotbohm, could one of you please take a look at this?
If you determine it is in fact caused by a changed in Spring Data from Neumann-RELEASE
to Neumann-SR1
, we'll close this issue and let @spazbob open an issue in the Spring Data issue tracker.
p.s. In case it helps, here's a little test class I wrote to make it easier to execute/debug the application in question. It doesn't actually assert anything, but you can quickly check the console output.
package com.ecv.webapp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
class ApplicationTests {
@Autowired
TestRestTemplate restTemplate;
@Test
void test() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("locations[0]", "1");
map.add("locations[1]", "2");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
restTemplate.postForEntity("/save", request, String.class);
}
}
Comment From: mp911de
That’s a known issue in Spring Data 2.3.1. we fixed it already with the latest snapshots, see https://jira.spring.io/browse/DATACMNS-1743
Comment From: leccelecce
Ah, apologies, I should have spotted that DomainClassConverter was in Spring Data and investigated there.
Thank you @sbrannen for your investigation into this.