-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataBinder
throws StringIndexOutOfBoundsException
for map property without nested property path
#34043
Comments
Hi @n0rthdev, can you provide a concrete example (ideally in the form of a simple unit test) of a map binding that used to work in 6.1 but doesn't in 6.2? I'm especially interested in the structure of the object you store as the map's value. |
Hi @simonbasle, |
Inside of DataBinderConstructTests @Test
void mapStringBinding() {
MapValueResolver valueResolver = new MapValueResolver(Map.of(
"stringMap[a]", "value1",
"stringMap[b]", "value2",
"stringMap['c']", "value3"));
DataBinder binder = initDataBinder(MapStringClass.class);
binder.construct(valueResolver);
MapStringClass stringClass = getTarget(binder);
Map<String, String> map = stringClass.stringMap();
assertThat(map).hasSize(3);
assertThat(map.get("a")).isEqualTo("value1");
assertThat(map.get("b")).isEqualTo("value2");
assertThat(map.get("c")).isEqualTo("value3");
}
private record MapStringClass(Map<String, String> stringMap) {
} The stacktrace my test is producing.
|
Yeah I understand how there could be a |
Hmmmm. Our usecase was working in 6.1, However, we are not calling this directly so it might be that Spring 6.1 might have used different logic to parse our data structure. I can take a look if this is of value for you. Are you planning of implementing support for these kind of maps for the databinder or would you consider my testcase a use outside of the specification? |
@n0rthdev yeah if you can provide more insight / an example closer to your actual DTO structure that would be valuable. You also mentioned a change in the DTO to use string keys? Feel free to also investigate the issue further as well. I'm not sure yet if your particular use case is within what's supposed to be supported. |
Same issue here, this prevents us from upgrading to Spring Boot 3.4.0. Here is a minimal example that runs with Spring Boot 3.3.5, but fails with Spring Boot 3.4.0: package com.example.spring_web_key_value_demo
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.stereotype.Controller
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.post
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.ResponseBody
@SpringBootTest
@AutoConfigureMockMvc
class SpringWebKeyValueTests(
@Autowired val mockMvc: MockMvc,
) {
@Test
fun postKeyValue() {
mockMvc.post("/spring-web-key-value") {
param("someMap[a]", "valueA")
}.andExpect {
status { isOk() }
content { string("valueA") }
}
}
}
@Controller
class SpringWebKeyValueController {
@PostMapping("/spring-web-key-value")
@ResponseBody
fun postKeyValue(@ModelAttribute("payload") payload: PayloadWithMap): String {
println(payload)
return payload.someMap.get("a")!!
}
}
data class PayloadWithMap(
val someMap: Map<String, String?> = mutableMapOf(),
) Exception:
|
Thanks for the reproducer, @jochenchrist. I converted that from Kotlin to Java as follows. import java.util.Map;
import example.SpringWebKeyValueTests.SpringWebKeyValueController;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
@SpringJUnitWebConfig(SpringWebKeyValueController.class)
class SpringWebKeyValueTests {
@Test
void postKeyValue(WebApplicationContext wac) throws Exception {
MockMvc mockMvc = webAppContextSetup(wac).build();
mockMvc.perform(post("/spring-web-key-value").param("someMap[a]", "valueA"))
.andExpect(status().isOk())
.andExpect(content().string("valueA"));
}
record PayloadWithMap(Map<String, String> someMap) {}
@RestController
static class SpringWebKeyValueController {
@PostMapping("/spring-web-key-value")
String postKeyValue(@ModelAttribute("payload") PayloadWithMap payload) {
return payload.someMap.get("a");
}
}
} In String nestedPath = name.substring(0, endIdx + 2); ... with: String nestedPath = ((name.length() > endIdx + 1) ? name.substring(0, endIdx + 2) : ""); ... that allows I have not verified if this is the ideal solution, but the team will look into it. |
This is closely related to: And the two should be looked at in conjunction. |
DataBinder
throws StringIndexOutOfBoundsException
for map property without nested property path
Since upgrading to Spring 6.2. we have the Issue that maps in form-data requests are no longer working.
After switching the DTO to using String keys, we are now getting an IndexOutOfRange in
DataVinder.createMap
e48cbc5#diff-1f22c41307a3ddcec8f1bc7a237d3b77ac7564883f4c663402993affac8a5756R1071
the issue seems to be the +2 in
String nestedPath = name.substring(0, endIdx + 2);
this works if the name is something like:mapname[91].myparam
but not if the map is just key and value then having namemapname[91]
The tests for this method do not cover my case so I am wondering if this my usecase might no longer be supported?
The text was updated successfully, but these errors were encountered: