Affects: \< Spring Boot 2.1.2.RELEASE>


I have a simple rest controller with the method the get requests mapped on:

@GetMapping("/cis_list")
public Map<String, CisFrontendDto> cisList(@RequestParam(value = "cis") List<String> cis) {
        log.debug("#cisList: started with cisIds = {}", cis);
        return cisService.findByIds(cis);
    }

I try to pass string hello, world! as a single element of List cis parameter:

curl -X GET "http://127.0.0.1:8095/api/v3/facade/cis/cis_list?cis=hello%2C%20world!" -H "accept: /"

I have expected the list contains only one string but аs it turned the list contains two elements although the comma has been escaped in source request.

Spring Why escaped comma is the delimiter for @RequestParam List<String>?

In this way there's not a difference between requests:

curl -X GET "http://127.0.0.1:8095/api/v3/facade/cis/cis_list?cis=hello%2C%20world!" -H "accept: /"

and

curl -X GET "http://127.0.0.1:8095/api/v3/facade/cis/cis_list?cis=hello,%20world!" -H "accept: /"

So, I'm not able to map parameters of HTTP GET requests to Java List if they contain escaped commas.

Comment From: rstoyanchev

This is due to the StringToCollectionConverter which gets involved if there is 1 request parameter value and we have to convert from String to List<String>. When there are multiple values the ArrayToCollectionConverter is used, so the behavior is specific to single values. It is a bit surprising I will admit, but we're unlikely to change this behavior at this time. Rather I can suggest that you remove the String to Collection conversion through the formatters callback in the WebMvcConfig.

Comment From: nschrader

Let's be honest, it's just broken. The parameter is sent with a percent escaped , (%2C) and according to RFC 3986, parameters need to be separated by an unescaped ,. Things that belong together get ripped apart, although we have the information that they shouldn't.

(And the RFC even explicitly states that commas are allowed as parameter values as long as they are percent escaped.)

Comment From: helderhernandez

I managed to solve the problem by applying the following: - How to prevent parameter binding from interpreting commas in Spring 3.0.5? - How to prevent Spring MVC from interpreting commas when converting to a Collection in Spring Boot?

The trick is done by the following lines of code

@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}

My classes were as follows:

Clase Search (works as a wrapper)

public class Search {
    private String[] search = new String[] {};

    public Search() {
        super();
    }

    public Search(String[] search) {
        super();
        this.search = search;
    }

    public String[] getSearch() {
        return search;
    }

    public void setSearch(String[] search) {
        this.search = search;
    }

    public List<String> toList() {
        return Arrays.asList(this.search);
    }

    @Override
    public String toString() {
        return "Search [search=" + Arrays.toString(search) + "]";
    }
}

Endpoint

@InitBinder
public void initBinder(WebDataBinder binder) {
  binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}

@GetMapping("/search")
@ResponseStatus(HttpStatus.OK)
@ApiOperation(value = "Search providers")
//@formatter:off
@ApiImplicitParams({
    @ApiImplicitParam(
        name = "search", 
        allowMultiple = true, 
        dataType = "string", 
        paramType = "query", 
        value = "Search by field: description"
    ) 
})
//@formatter:on
public List<String> search(Search search) {
    System.out.println(search.toList().size());
    search.toList().forEach(System.out::println);

    //..... your code
}

Results

Spring Why escaped comma is the delimiter for @RequestParam List<String>?

Spring Why escaped comma is the delimiter for @RequestParam List<String>?