I'm using the reactive WebClient from spring-webflux (version 5.2.0) within code generated from an OpenAPI specification to fire HTTP requests against an API. This API uses JSON in query parameters. When this query parameter gets expanded by UriComponents, the curly braces are erroneously interpreted as template placeholder, but no corresponding template variable can be found (obviously), leading to an IllegalArgumentException.
I prepared a piece of code to reproduce the issue:
import java.util.*;
import org.springframework.http.HttpMethod;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
class Scratch {
public static void main(String[] args) {
final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:80/").path("/{id}/generate");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("myjson", "{\"key\":\"value\"}");
builder.queryParams(params);
Map<String, Object> pathParams = new HashMap<>();
pathParams.put("id", 123L);
WebClient.create()
.method(HttpMethod.GET)
.uri(builder.build(false).toUriString(), pathParams);
}
}
This leads to:
Exception in thread "main" java.lang.IllegalArgumentException: Map has no value for '"key"'
at org.springframework.web.util.UriComponents$MapTemplateVariables.getValue(UriComponents.java:345)
at org.springframework.web.util.HierarchicalUriComponents$QueryUriTemplateVariables.getValue(HierarchicalUriComponents.java:1053)
at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:262)
at org.springframework.web.util.HierarchicalUriComponents.lambda$expandQueryParams$5(HierarchicalUriComponents.java:445)
at java.base/java.util.Map.forEach(Map.java:661)
at org.springframework.web.util.HierarchicalUriComponents.expandQueryParams(HierarchicalUriComponents.java:441)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:430)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:51)
at org.springframework.web.util.UriComponents.expand(UriComponents.java:161)
at org.springframework.web.util.DefaultUriBuilderFactory$DefaultUriBuilder.build(DefaultUriBuilderFactory.java:380)
at org.springframework.web.util.DefaultUriBuilderFactory.expand(DefaultUriBuilderFactory.java:200)
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.uri(DefaultWebClient.java:182)
at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.uri(DefaultWebClient.java:151)
at Scratch.main(scratch_7.java:20)
I'd like to use the UriComponentsBuilder to handle all the encoding details, but I actually don't want it to do any expanding on query parameter values.
Comment From: rstoyanchev
"{"
and "}"
are not allowed in the query and must be encoded. So such query param values cannot be in the URI template which is expected to contain legal characters. You can turn those into URI variables to be inserted. Something like this:
Map<String, Object> params = new HashMap<>();
params.put("myjson", "{\"key\":\"value\"}");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:80/").path("/{id}/generate");
params.forEach((key, values) -> builder.queryParam(key, "{" + key + "}"));
String uriTemplate = builder.build().toUriString();
params.put("id", 123L);
WebClient.create()
.method(HttpMethod.GET)
.uri(uriTemplate, params);
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.