Refine null handling in UriComponentsBuilder#query

Closes gh-35629
This commit is contained in:
rstoyanchev
2025-10-15 12:31:08 +01:00
parent 649bd3ee2d
commit 3607f98240
3 changed files with 21 additions and 18 deletions
@@ -144,9 +144,10 @@ public interface UriBuilder {
UriBuilder pathSegment(String... pathSegments) throws IllegalArgumentException;
/**
* Parse the given query string into query parameters where parameters are
* separated with {@code '&'} and their values, if any, with {@code '='}.
* The query may contain URI template variables.
* Parse the given query string into query parameters, and append them to
* the query string. Query parameters are separated with {@code '&'} while
* their values, if any, are separated with {@code '='}. The query string
* may contain URI template variables.
* <p><strong>Note: </strong> please, review the Javadoc of
* {@link #queryParam(String, Object...)} for further notes on the treatment
* and encoding of individual query parameters.
@@ -426,7 +426,9 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
if (record.path() != null) {
path(record.path());
}
query(record.query());
if (record.query() != null) {
query(record.query());
}
}
fragment(record.fragment());
return this;
@@ -453,7 +455,9 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
port(record.portString());
}
path(record.path().toString());
query(record.query());
if (record.query() != null) {
query(record.query());
}
}
if (StringUtils.hasText(record.fragment())) {
fragment(record.fragment());
@@ -541,8 +545,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
}
@Override
public UriComponentsBuilder query(@Nullable String query) {
if (query != null) {
public UriComponentsBuilder query(String query) {
if (StringUtils.hasText(query)) {
Matcher matcher = QUERY_PARAM_PATTERN.matcher(query);
while (matcher.find()) {
String name = matcher.group(1);
@@ -479,20 +479,18 @@ class UriComponentsBuilderTests {
@ParameterizedTest
@EnumSource
void query(final ParserType parserType) {
final UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar", parserType)
.query("baz=qux")
.build();
assertThat(uriComponents.getQueryParams()).isEqualTo(Map.of("foo", List.of("bar"), "baz", List.of("qux")));
void query(ParserType parserType) {
String url = "https://example.com/foo?foo=bar";
UriComponents uric = UriComponentsBuilder.fromUriString(url, parserType).query("baz=qux").build();
assertThat(uric.getQueryParams()).isEqualTo(Map.of("foo", List.of("bar"), "baz", List.of("qux")));
}
@ParameterizedTest
@EnumSource
void queryWithNullDoesRetainQueryParameters(final ParserType parserType) {
final UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar", parserType)
.query(null)
.build();
assertThat(uriComponents.getQueryParams()).isEqualTo(Map.of("foo", List.of("bar")));
@EnumSource // gh-35628
void queryWithNull(ParserType parserType) {
String url = "https://example.com/foo?foo=bar";
UriComponents uric = UriComponentsBuilder.fromUriString(url, parserType).query(null).build();
assertThat(uric.getQueryParams()).isEqualTo(Map.of("foo", List.of("bar")));
}
@ParameterizedTest