Home > Back-end >  Spring Boot Rest Controller Array Handling
Spring Boot Rest Controller Array Handling

Time:01-17

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)

  • Related