From ea10ee5265f3d3175b6dad127cb7d4c3a407066b Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Wed, 12 Jun 2019 15:49:19 +0300 Subject: [PATCH 1/2] queryParam and replaceParam with List See gh-23114 --- .../web/util/DefaultUriBuilderFactory.java | 13 ++++++ .../springframework/web/util/UriBuilder.java | 27 +++++++++++- .../web/util/UriComponentsBuilder.java | 42 +++++++++++++++++-- .../web/util/UriComponentsBuilderTests.java | 41 +++++++++++++++++- 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java index 428b8e5bad84..4c3c0e5d7583 100644 --- a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java @@ -17,6 +17,7 @@ package org.springframework.web.util; import java.net.URI; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -326,12 +327,24 @@ public DefaultUriBuilder queryParam(String name, Object... values) { return this; } + @Override + public DefaultUriBuilder queryParams(String name, @Nullable Collection values) { + this.uriComponentsBuilder.queryParams(name, values); + return this; + } + @Override public DefaultUriBuilder replaceQueryParam(String name, Object... values) { this.uriComponentsBuilder.replaceQueryParam(name, values); return this; } + @Override + public DefaultUriBuilder replaceQueryParams(String name, @Nullable Collection values) { + this.uriComponentsBuilder.replaceQueryParams(name, values); + return this; + } + @Override public DefaultUriBuilder queryParams(MultiValueMap params) { this.uriComponentsBuilder.queryParams(params); diff --git a/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java index f0b8f1dcc773..d91903856da2 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.web.util; import java.net.URI; +import java.util.Collection; import java.util.Map; import org.springframework.lang.Nullable; @@ -124,9 +125,22 @@ public interface UriBuilder { * only (i.e. {@code ?foo} instead of {@code ?foo=bar}. * @param name the query parameter name * @param values the query parameter values + * @see #queryParams(String, Collection) */ UriBuilder queryParam(String name, Object... values); + /** + * Append the given query parameter to the existing query parameters. The + * given name or any of the values may contain URI template variables. If no + * values are given, the resulting URI will contain the query parameter name + * only (i.e. {@code ?foo} instead of {@code ?foo=bar}. + * @param name the query parameter name + * @param values the query parameter values + * @since 5.2.0 + * @see #queryParam(String, Object...) + */ + UriBuilder queryParams(String name, @Nullable Collection values); + /** * Add the given query parameters. * @param params the params @@ -138,9 +152,20 @@ public interface UriBuilder { * the same parameter. If no values are given, the query parameter is removed. * @param name the query parameter name * @param values the query parameter values + * @see #replaceQueryParams(String, Collection) */ UriBuilder replaceQueryParam(String name, Object... values); + /** + * Set the query parameter values overriding all existing query values for + * the same parameter. If no values are given, the query parameter is removed. + * @param name the query parameter name + * @param values the query parameter values + * @since 5.2.0 + * @see #replaceQueryParam(String, Object...) + */ + UriBuilder replaceQueryParams(String name, @Nullable Collection values); + /** * Set the query parameter values overriding all existing query values. * @param params the query parameter name diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 5e3db7e8ef04..779fd4bd8bc2 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -20,6 +20,9 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -31,6 +34,7 @@ import org.springframework.http.HttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; @@ -696,11 +700,28 @@ public UriComponentsBuilder replaceQuery(@Nullable String query) { * @param name the query parameter name * @param values the query parameter values * @return this UriComponentsBuilder + * @see #queryParams(String, Collection) */ @Override public UriComponentsBuilder queryParam(String name, Object... values) { + return queryParams(name, (!ObjectUtils.isEmpty(values) ? Arrays.asList(values) : Collections.emptyList())); + } + + /** + * Append the given query parameter to the existing query parameters. The + * given name or any of the values may contain URI template variables. If no + * values are given, the resulting URI will contain the query parameter name + * only (i.e. {@code ?foo} instead of {@code ?foo=bar}). + * @param name the query parameter name + * @param values the query parameter values + * @return this UriComponentsBuilder + * @since 5.2.0 + * @see #queryParam(String, Object...) + */ + @Override + public UriComponentsBuilder queryParams(String name, @Nullable Collection values) { Assert.notNull(name, "Name must not be null"); - if (!ObjectUtils.isEmpty(values)) { + if (!CollectionUtils.isEmpty(values)) { for (Object value : values) { String valueAsString = (value != null ? value.toString() : null); this.queryParams.add(name, valueAsString); @@ -733,13 +754,28 @@ public UriComponentsBuilder queryParams(@Nullable MultiValueMap * @param name the query parameter name * @param values the query parameter values * @return this UriComponentsBuilder + * @see #replaceQueryParams(String, Collection) */ @Override public UriComponentsBuilder replaceQueryParam(String name, Object... values) { + return replaceQueryParams(name, (!ObjectUtils.isEmpty(values) ? Arrays.asList(values) : Collections.emptyList())); + } + + /** + * Set the query parameter values overriding all existing query values for + * the same parameter. If no values are given, the query parameter is removed. + * @param name the query parameter name + * @param values the query parameter values + * @return this UriComponentsBuilder + * @see #replaceQueryParam(String, Object...) + * @since 5.2.0 + */ + @Override + public UriComponentsBuilder replaceQueryParams(String name, @Nullable Collection values) { Assert.notNull(name, "Name must not be null"); this.queryParams.remove(name); - if (!ObjectUtils.isEmpty(values)) { - queryParam(name, values); + if (!CollectionUtils.isEmpty(values)) { + queryParams(name, values); } resetSchemeSpecificPart(); return this; diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index c580a5beb9d1..d785c16e9534 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -643,7 +643,7 @@ public void replaceQuery() { } @Test - public void queryParams() { + public void queryParam() { UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); UriComponents result = builder.queryParam("baz", "qux", 42).build(); @@ -654,6 +654,18 @@ public void queryParams() { assertThat(result.getQueryParams()).isEqualTo(expectedQueryParams); } + @Test + public void queryParams() { + UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); + UriComponents result = builder.queryParams("baz", Arrays.asList("qux", 42)).build(); + + assertThat(result.getQuery()).isEqualTo("baz=qux&baz=42"); + MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); + expectedQueryParams.add("baz", "qux"); + expectedQueryParams.add("baz", "42"); + assertThat(result.getQueryParams()).isEqualTo(expectedQueryParams); + } + @Test public void emptyQueryParam() { UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); @@ -665,6 +677,18 @@ public void emptyQueryParam() { assertThat(result.getQueryParams()).isEqualTo(expectedQueryParams); } + @Test + public void emptyQueryParams() { + UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); + UriComponents result = builder.queryParams("baz", Collections.emptyList()).queryParams("foo", null).build(); + + assertThat(result.getQuery()).isEqualTo("baz&foo"); + MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); + expectedQueryParams.add("baz", null); + expectedQueryParams.add("foo", null); + assertThat(result.getQueryParams()).isEqualTo(expectedQueryParams); + } + @Test public void replaceQueryParam() { UriComponentsBuilder builder = UriComponentsBuilder.newInstance().queryParam("baz", "qux", 42); @@ -680,6 +704,21 @@ public void replaceQueryParam() { assertThat(result.getQuery()).as("Query param should have been deleted").isNull(); } + @Test + public void replaceQueryParams() { + UriComponentsBuilder builder = UriComponentsBuilder.newInstance().queryParams("baz", Arrays.asList("qux", 42)); + builder.replaceQueryParams("baz", Arrays.asList("xuq", 24)); + UriComponents result = builder.build(); + + assertThat(result.getQuery()).isEqualTo("baz=xuq&baz=24"); + + builder = UriComponentsBuilder.newInstance().queryParams("baz", Arrays.asList("qux", 42)); + builder.replaceQueryParams("baz", Collections.emptyList()); + result = builder.build(); + + assertThat(result.getQuery()).as("Query param should have been deleted").isNull(); + } + @Test public void buildAndExpandHierarchical() { UriComponents result = UriComponentsBuilder.fromPath("/{foo}").buildAndExpand("fooValue"); From fbb72eff2efaffeb50ba612bf487a80c823a53a5 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 5 Jul 2019 09:01:13 +0100 Subject: [PATCH 2/2] Polish --- .../web/util/DefaultUriBuilderFactory.java | 8 +-- .../springframework/web/util/UriBuilder.java | 8 +-- .../web/util/UriComponentsBuilder.java | 55 +++++++++---------- .../web/util/UriComponentsBuilderTests.java | 22 ++++---- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java index 4c3c0e5d7583..0cc182864247 100644 --- a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java @@ -328,8 +328,8 @@ public DefaultUriBuilder queryParam(String name, Object... values) { } @Override - public DefaultUriBuilder queryParams(String name, @Nullable Collection values) { - this.uriComponentsBuilder.queryParams(name, values); + public DefaultUriBuilder queryParam(String name, @Nullable Collection values) { + this.uriComponentsBuilder.queryParam(name, values); return this; } @@ -340,8 +340,8 @@ public DefaultUriBuilder replaceQueryParam(String name, Object... values) { } @Override - public DefaultUriBuilder replaceQueryParams(String name, @Nullable Collection values) { - this.uriComponentsBuilder.replaceQueryParams(name, values); + public DefaultUriBuilder replaceQueryParam(String name, @Nullable Collection values) { + this.uriComponentsBuilder.replaceQueryParam(name, values); return this; } diff --git a/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java index d91903856da2..bcbb96e57b15 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriBuilder.java @@ -125,7 +125,7 @@ public interface UriBuilder { * only (i.e. {@code ?foo} instead of {@code ?foo=bar}. * @param name the query parameter name * @param values the query parameter values - * @see #queryParams(String, Collection) + * @see #queryParam(String, Collection) */ UriBuilder queryParam(String name, Object... values); @@ -139,7 +139,7 @@ public interface UriBuilder { * @since 5.2.0 * @see #queryParam(String, Object...) */ - UriBuilder queryParams(String name, @Nullable Collection values); + UriBuilder queryParam(String name, @Nullable Collection values); /** * Add the given query parameters. @@ -152,7 +152,7 @@ public interface UriBuilder { * the same parameter. If no values are given, the query parameter is removed. * @param name the query parameter name * @param values the query parameter values - * @see #replaceQueryParams(String, Collection) + * @see #replaceQueryParam(String, Collection) */ UriBuilder replaceQueryParam(String name, Object... values); @@ -164,7 +164,7 @@ public interface UriBuilder { * @since 5.2.0 * @see #replaceQueryParam(String, Object...) */ - UriBuilder replaceQueryParams(String name, @Nullable Collection values); + UriBuilder replaceQueryParam(String name, @Nullable Collection values); /** * Set the query parameter values overriding all existing query values. diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 779fd4bd8bc2..99d7267d2c32 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -20,9 +20,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -34,7 +32,6 @@ import org.springframework.http.HttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; @@ -104,6 +101,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { private static final Pattern FORWARDED_PROTO_PATTERN = Pattern.compile("proto=\"?([^;,\"]+)\"?"); + private static final Object[] EMPTY_VALUES = new Object[0]; + @Nullable private String scheme; @@ -700,11 +699,22 @@ public UriComponentsBuilder replaceQuery(@Nullable String query) { * @param name the query parameter name * @param values the query parameter values * @return this UriComponentsBuilder - * @see #queryParams(String, Collection) + * @see #queryParam(String, Collection) */ @Override public UriComponentsBuilder queryParam(String name, Object... values) { - return queryParams(name, (!ObjectUtils.isEmpty(values) ? Arrays.asList(values) : Collections.emptyList())); + Assert.notNull(name, "Name must not be null"); + if (!ObjectUtils.isEmpty(values)) { + for (Object value : values) { + String valueAsString = (value != null ? value.toString() : null); + this.queryParams.add(name, valueAsString); + } + } + else { + this.queryParams.add(name, null); + } + resetSchemeSpecificPart(); + return this; } /** @@ -719,19 +729,8 @@ public UriComponentsBuilder queryParam(String name, Object... values) { * @see #queryParam(String, Object...) */ @Override - public UriComponentsBuilder queryParams(String name, @Nullable Collection values) { - Assert.notNull(name, "Name must not be null"); - if (!CollectionUtils.isEmpty(values)) { - for (Object value : values) { - String valueAsString = (value != null ? value.toString() : null); - this.queryParams.add(name, valueAsString); - } - } - else { - this.queryParams.add(name, null); - } - resetSchemeSpecificPart(); - return this; + public UriComponentsBuilder queryParam(String name, @Nullable Collection values) { + return queryParam(name, values != null ? values.toArray() : EMPTY_VALUES); } /** @@ -754,11 +753,17 @@ public UriComponentsBuilder queryParams(@Nullable MultiValueMap * @param name the query parameter name * @param values the query parameter values * @return this UriComponentsBuilder - * @see #replaceQueryParams(String, Collection) + * @see #replaceQueryParam(String, Collection) */ @Override public UriComponentsBuilder replaceQueryParam(String name, Object... values) { - return replaceQueryParams(name, (!ObjectUtils.isEmpty(values) ? Arrays.asList(values) : Collections.emptyList())); + Assert.notNull(name, "Name must not be null"); + this.queryParams.remove(name); + if (!ObjectUtils.isEmpty(values)) { + queryParam(name, values); + } + resetSchemeSpecificPart(); + return this; } /** @@ -771,14 +776,8 @@ public UriComponentsBuilder replaceQueryParam(String name, Object... values) { * @since 5.2.0 */ @Override - public UriComponentsBuilder replaceQueryParams(String name, @Nullable Collection values) { - Assert.notNull(name, "Name must not be null"); - this.queryParams.remove(name); - if (!CollectionUtils.isEmpty(values)) { - queryParams(name, values); - } - resetSchemeSpecificPart(); - return this; + public UriComponentsBuilder replaceQueryParam(String name, @Nullable Collection values) { + return replaceQueryParam(name, values != null ? values.toArray() : EMPTY_VALUES); } /** diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index d785c16e9534..761bc68cfe90 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -19,6 +19,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -644,8 +645,7 @@ public void replaceQuery() { @Test public void queryParam() { - UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); - UriComponents result = builder.queryParam("baz", "qux", 42).build(); + UriComponents result = UriComponentsBuilder.newInstance().queryParam("baz", "qux", 42).build(); assertThat(result.getQuery()).isEqualTo("baz=qux&baz=42"); MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); @@ -655,9 +655,9 @@ public void queryParam() { } @Test - public void queryParams() { + public void queryParamWithList() { UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); - UriComponents result = builder.queryParams("baz", Arrays.asList("qux", 42)).build(); + UriComponents result = builder.queryParam("baz", Arrays.asList("qux", 42)).build(); assertThat(result.getQuery()).isEqualTo("baz=qux&baz=42"); MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); @@ -679,8 +679,10 @@ public void emptyQueryParam() { @Test public void emptyQueryParams() { - UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); - UriComponents result = builder.queryParams("baz", Collections.emptyList()).queryParams("foo", null).build(); + UriComponents result = UriComponentsBuilder.newInstance() + .queryParam("baz", Collections.emptyList()) + .queryParam("foo", (Collection) null) + .build(); assertThat(result.getQuery()).isEqualTo("baz&foo"); MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); @@ -706,14 +708,14 @@ public void replaceQueryParam() { @Test public void replaceQueryParams() { - UriComponentsBuilder builder = UriComponentsBuilder.newInstance().queryParams("baz", Arrays.asList("qux", 42)); - builder.replaceQueryParams("baz", Arrays.asList("xuq", 24)); + UriComponentsBuilder builder = UriComponentsBuilder.newInstance().queryParam("baz", Arrays.asList("qux", 42)); + builder.replaceQueryParam("baz", Arrays.asList("xuq", 24)); UriComponents result = builder.build(); assertThat(result.getQuery()).isEqualTo("baz=xuq&baz=24"); - builder = UriComponentsBuilder.newInstance().queryParams("baz", Arrays.asList("qux", 42)); - builder.replaceQueryParams("baz", Collections.emptyList()); + builder = UriComponentsBuilder.newInstance().queryParam("baz", Arrays.asList("qux", 42)); + builder.replaceQueryParam("baz", Collections.emptyList()); result = builder.build(); assertThat(result.getQuery()).as("Query param should have been deleted").isNull();