Description
Ruslan Stelmachenko opened SPR-17256 and commented
When UriComponentsBuilder.uriComponents
clones queryParams
from given UriComponents
, it leaves them as unmodifiable MultiValueMap
.
This prevents to futher adding query params with the same name into the builder.
For example:
UriComponentsBuilder
.fromUriString("http://localhost:8081")
.uriComponents(UriComponentsBuilder.fromUriString("/{path}?sort={sort}").build())
.queryParam("sort", "another_value")
.build();
The .queryParam("sort", "another_value")
line throws an exception on attempt to add another value to unmodifiable MultiValueMap
.
While this code works:
UriComponentsBuilder
.fromUriString("http://localhost:8081/{path}?sort={sort}")
.queryParam("sort", "another_value")
.build();
The interested part of code to investigate this problem is:
org.springframework.web.util.HierarchicalUriComponents#copyToUriComponentsBuilder
Here is line builder.queryParams(getQueryParams())
which sets the builder's queryParams
to unmodifiable MultiValueMap
.
I think we can clone unmodifiable queryParams here to be modifiable, or maybe better inside org.springframework.web.util.UriComponentsBuilder#queryParams
methods to make this logic independent of UriComponents
implementation.
To make the intention more clear: this pattern of use UriComponentsBuilder
is actually used in org.springframework.web.util.DefaultUriBuilderFactory.DefaultUriBuilder#initUriComponentsBuilder
where I first faced this problem.
It allows to set baseUrl
and then uriString
to concatenate them.
So this code also throws an exception:
new DefaultUriBuilderFactory("http://localhost:8081")
.uriString("/{path}?sort={sort}")
.queryParam("sort", "another_value")
.build(params);
Affects: 5.0.8, 5.1 RC2
Issue Links:
- ConcurrentModificationException when calling SimpMessagingTemplate.convertAndSend [SPR-13185] #17777 ConcurrentModificationException when calling SimpMessagingTemplate.convertAndSend
Referenced from: commits 2820831, 1d58fac, c06b952
Backported to: 5.0.10