Hello Spring Developers
I have a spring-boot related issue, which I don't know how to resolve properly.
This issue is a direct consequence of spring's behaviour with query parameters:
When a single query parameter contains the ,
character it will be split by that comma.
Example:
XXX?array=1,2,3 => ["1", "2", "3"]
When a query parameter - containing the ,
character - is defined multiple times, spring will not split every value by the comma.
Example:
XXX?array=1,2&array=3 => ["1,2", "3"]
Issue: Some of our query parameters may contain a ,
character.
Since spring does not behave like the RFC is stated I need a way to NOT split the query parameters by commas.
My Controller
@RestController
public class Controller {
@GetMapping(path = "arrays", produces = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
public List<String> getArrayQueryParameters(@RequestParam("array") String[] array) {
return Arrays.asList(array);
}
}
My Testcase
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = Controller.class)
@AutoConfigureMockMvc
@EnableAutoConfiguration(exclude=SecurityAutoConfiguration.class)
public class ControllerMvcTest {
@Autowired
private MockMvc mvc;
// This Test fails
@Test
void oneParameter() throws Exception {
mvc.perform(get("/arrays?array=1,2,3,4,5")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0]", is("1,2,3,4,5")));
}
@Test
void parameterTwoTimes() throws Exception {
mvc.perform(get("/arrays?array=1,2&array=3,4,5")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0]", is("1,2")))
.andExpect(jsonPath("$[1]", is("3,4,5")));
}
@Test
void parameterThreeTimes() throws Exception {
mvc.perform(get("/arrays?array=1,2&array=3&array=4,5")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0]", is("1,2")))
.andExpect(jsonPath("$[1]", is("3")))
.andExpect(jsonPath("$[2]", is("4,5")));
}
}
You can find an example github repo here: https://github.com/arolfes/RestArrayParametersSample
CodePudding user response:
You can make query params not split by commas using @InitBinder
and DataBinder
.
Spring DataBinder
uses StringToArrayConverter
for converting String
to String[]
, which behaves as you experienced. (Related source codes)
Classes annotated with @Controller
or @ControllerAdvice
can have methods with @InitBinder
.
You can utilize registerCustomEditor()
of DataBinder
to applying PropertyEditor
which not using the comma delimiter.
If you add this method for your ControllerServletRequest
, the first test case will succeed. (I checked.)
@InitBinder
private void initBinder(DataBinder binder) {
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}
As you can see, I intentionally give null
for constructor of StringArrayPropertyEditor
because the arg is delimiter, whose default value is ","
. (Related source codes)