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.

repro.zip

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.