From 261956fd08fec9f35abbd2a1667e4acbbacdfc31 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 20 Dec 2019 11:03:08 +0000 Subject: [PATCH] Improve UriBuilder Javadoc on query params Add a note on encoding for query parameters specifically mentioning the "+" sign and a link to the reference docs. Also remove duplicate Javadoc in UriComponentsBuilder which is already inherited from UriBuilder. --- .../web/util/HierarchicalUriComponents.java | 2 +- .../springframework/web/util/UriBuilder.java | 70 ++++++---- .../web/util/UriComponentsBuilder.java | 121 +----------------- 3 files changed, 48 insertions(+), 145 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 1aaa56f5a1..624bff55b1 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -588,7 +588,7 @@ final class HierarchicalUriComponents extends UriComponents { /** * Enumeration used to identify the allowed characters per URI component. *

Contains methods to indicate whether a given character is valid in a specific URI component. - * @see RFC 3986 + * @see RFC 3986 */ enum Type { 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 bd65446082..14618e7520 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 @@ -98,31 +98,40 @@ public interface UriBuilder { UriBuilder pathSegment(String... pathSegments) throws IllegalArgumentException; /** - * Append the given query to the existing query of this builder. - * The given query may contain URI template variables. - *

Note: The presence of reserved characters can prevent - * correct parsing of the URI string. For example if a query parameter - * contains {@code '='} or {@code '&'} characters, the query string cannot - * be parsed unambiguously. Such values should be substituted for URI - * variables to enable correct parsing: - *

-	 * builder.query("filter={value}").uriString("hot&cold");
-	 * 
+ * 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. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param query the query string */ UriBuilder query(String query); /** - * Set the query of this builder overriding all existing query parameters. - * @param query the query string, or {@code null} to remove all query params + * Clear existing query parameters and then delegate to {@link #query(String)}. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. + * @param query the query string; a {@code null} value removes all query parameters. */ UriBuilder replaceQuery(@Nullable String query); /** - * 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 + * Append the given query parameter. Both the parameter name and values may + * contain URI template variables to be expanded later from values. If no * values are given, the resulting URI will contain the query parameter name - * only (i.e. {@code ?foo} instead of {@code ?foo=bar}. + * only, e.g. {@code "?foo"} instead of {@code "?foo=bar"}. + *

Note: encoding, if applied, will only encode characters + * that are illegal in a query parameter name or value such as {@code "="} + * or {@code "&"}. All others that are legal as per syntax rules in + * RFC 3986 are not + * encoded. This includes {@code "+"} which sometimes needs to be encoded + * to avoid its interpretation as an encoded space. Stricter encoding may + * be applied by using a URI template variable along with stricter encoding + * on variable values. For more details please read the + * "URI Encoding" + * section of the Spring Framework reference. * @param name the query parameter name * @param values the query parameter values * @see #queryParam(String, Collection) @@ -130,10 +139,10 @@ public interface UriBuilder { 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}. + * Variant of {@link #queryParam(String, Object...)} with a Collection. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param name the query parameter name * @param values the query parameter values * @since 5.2 @@ -142,14 +151,20 @@ public interface UriBuilder { UriBuilder queryParam(String name, @Nullable Collection values); /** - * Add the given query parameters. + * Add multiple query parameters and values. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param params the params */ UriBuilder queryParams(MultiValueMap params); /** - * Set the query parameter values overriding all existing query values for - * the same parameter. If no values are given, the query parameter is removed. + * Set the query parameter values replacing existing values, or if no + * values are given, the query parameter is removed. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param name the query parameter name * @param values the query parameter values * @see #replaceQueryParam(String, Collection) @@ -157,8 +172,10 @@ public interface UriBuilder { 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. + * Variant of {@link #replaceQueryParam(String, Object...)} with a Collection. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param name the query parameter name * @param values the query parameter values * @since 5.2 @@ -167,7 +184,10 @@ public interface UriBuilder { UriBuilder replaceQueryParam(String name, @Nullable Collection values); /** - * Set the query parameter values overriding all existing query values. + * Set the query parameter values after removing all existing ones. + *

Note: please, review the Javadoc of + * {@link #queryParam(String, Object...)} for further notes on the treatment + * and encoding of individual query parameters. * @param params the query parameter name */ UriBuilder replaceQueryParams(MultiValueMap params); 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 12ca9b7eac..506f92b1a9 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 @@ -521,12 +521,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI scheme. The given scheme may contain URI template variables, - * and may also be {@code null} to clear the scheme of this builder. - * @param scheme the URI scheme - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder scheme(@Nullable String scheme) { this.scheme = scheme; @@ -547,12 +541,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI user info. The given user info may contain URI template variables, - * and may also be {@code null} to clear the user info of this builder. - * @param userInfo the URI user info - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder userInfo(@Nullable String userInfo) { this.userInfo = userInfo; @@ -560,12 +548,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI host. The given host may contain URI template variables, - * and may also be {@code null} to clear the host of this builder. - * @param host the URI host - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder host(@Nullable String host) { this.host = host; @@ -573,11 +555,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI port. Passing {@code -1} will clear the port of this builder. - * @param port the URI port - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder port(int port) { Assert.isTrue(port >= -1, "Port must be >= -1"); @@ -586,13 +563,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI port. Use this method only when the port needs to be - * parameterized with a URI variable. Otherwise use {@link #port(int)}. - * Passing {@code null} will clear the port of this builder. - * @param port the URI port - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder port(@Nullable String port) { this.port = port; @@ -600,12 +570,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Append the given path to the existing path of this builder. - * The given path may contain URI template variables. - * @param path the URI path - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder path(String path) { this.pathBuilder.addPath(path); @@ -613,13 +577,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Append path segments to the existing path. Each path segment may contain - * URI template variables and should not contain any slashes. - * Use {@code path("/")} subsequently to ensure a trailing slash. - * @param pathSegments the URI path segments - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder pathSegment(String... pathSegments) throws IllegalArgumentException { this.pathBuilder.addPathSegments(pathSegments); @@ -627,11 +584,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the path of this builder overriding all existing path and path segment values. - * @param path the URI path (a {@code null} value results in an empty path) - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder replacePath(@Nullable String path) { this.pathBuilder = new CompositePathComponentBuilder(); @@ -642,22 +594,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Append the given query to the existing query of this builder. - * The given query may contain URI template variables. - *

Note: The presence of reserved characters can prevent - * correct parsing of the URI string. For example if a query parameter - * contains {@code '='} or {@code '&'} characters, the query string cannot - * be parsed unambiguously. Such values should be substituted for URI - * variables to enable correct parsing: - *

-	 * UriComponentsBuilder.fromUriString("/hotels/42")
-	 * 	.query("filter={value}")
-	 * 	.buildAndExpand("hot&cold");
-	 * 
- * @param query the query string - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder query(@Nullable String query) { if (query != null) { @@ -676,11 +612,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the query of this builder overriding all existing query parameters. - * @param query the query string; a {@code null} value removes all query parameters. - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder replaceQuery(@Nullable String query) { this.queryParams.clear(); @@ -691,16 +622,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * 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 - * @see #queryParam(String, Collection) - */ @Override public UriComponentsBuilder queryParam(String name, Object... values) { Assert.notNull(name, "Name must not be null"); @@ -717,26 +638,13 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * 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 - * @see #queryParam(String, Object...) - */ @Override public UriComponentsBuilder queryParam(String name, @Nullable Collection values) { return queryParam(name, values != null ? values.toArray() : EMPTY_VALUES); } /** - * Add the given query parameters. - * @param params the params - * @return this UriComponentsBuilder + * {@inheritDoc} * @since 4.0 */ @Override @@ -747,14 +655,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * 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, Collection) - */ @Override public UriComponentsBuilder replaceQueryParam(String name, Object... values) { Assert.notNull(name, "Name must not be null"); @@ -766,24 +666,13 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * 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 - */ @Override public UriComponentsBuilder replaceQueryParam(String name, @Nullable Collection values) { return replaceQueryParam(name, values != null ? values.toArray() : EMPTY_VALUES); } /** - * Set the query parameter values overriding all existing query values. - * @param params the query parameter name - * @return this UriComponentsBuilder + * {@inheritDoc} * @since 4.2 */ @Override @@ -795,12 +684,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { return this; } - /** - * Set the URI fragment. The given fragment may contain URI template variables, - * and may also be {@code null} to clear the fragment of this builder. - * @param fragment the URI fragment - * @return this UriComponentsBuilder - */ @Override public UriComponentsBuilder fragment(@Nullable String fragment) { if (fragment != null) {