Minor fixes: UriComponentsBuilder, UriComponents, docs
After the latest changes, two small fixes in the clone method to copy the encode flag, and in the encodeUriTemplate method to account for possible null query params. Improvements in the URI encoding section. Issue: SPR-17039, SPR-17027
This commit is contained in:
		
							parent
							
								
									51c7ceb95d
								
							
						
					
					
						commit
						28cd6978b5
					
				| 
						 | 
					@ -100,6 +100,9 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final MultiValueMap<String, String> EMPTY_QUERY_PARAMS =
 | 
				
			||||||
 | 
								CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<>(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Nullable
 | 
						@Nullable
 | 
				
			||||||
	private final String userInfo;
 | 
						private final String userInfo;
 | 
				
			||||||
| 
						 | 
					@ -127,22 +130,21 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
	 * @param host the host
 | 
						 * @param host the host
 | 
				
			||||||
	 * @param port the port
 | 
						 * @param port the port
 | 
				
			||||||
	 * @param path the path
 | 
						 * @param path the path
 | 
				
			||||||
	 * @param queryParams the query parameters
 | 
						 * @param query the query parameters
 | 
				
			||||||
	 * @param fragment the fragment
 | 
						 * @param fragment the fragment
 | 
				
			||||||
	 * @param encoded whether the components are already encoded
 | 
						 * @param encoded whether the components are already encoded
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	HierarchicalUriComponents(@Nullable String scheme, @Nullable String fragment, @Nullable String userInfo,
 | 
						HierarchicalUriComponents(@Nullable String scheme, @Nullable String fragment, @Nullable String userInfo,
 | 
				
			||||||
			@Nullable String host, @Nullable String port, @Nullable PathComponent path,
 | 
								@Nullable String host, @Nullable String port, @Nullable PathComponent path,
 | 
				
			||||||
			@Nullable MultiValueMap<String, String> queryParams, boolean encoded) {
 | 
								@Nullable MultiValueMap<String, String> query, boolean encoded) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		super(scheme, fragment);
 | 
							super(scheme, fragment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.userInfo = userInfo;
 | 
							this.userInfo = userInfo;
 | 
				
			||||||
		this.host = host;
 | 
							this.host = host;
 | 
				
			||||||
		this.port = port;
 | 
							this.port = port;
 | 
				
			||||||
		this.path = (path != null ? path : NULL_PATH_COMPONENT);
 | 
							this.path = path != null ? path : NULL_PATH_COMPONENT;
 | 
				
			||||||
		this.queryParams = CollectionUtils.unmodifiableMultiValueMap(
 | 
							this.queryParams = query != null ? CollectionUtils.unmodifiableMultiValueMap(query) : EMPTY_QUERY_PARAMS;
 | 
				
			||||||
				queryParams != null ? queryParams : new LinkedMultiValueMap<>(0));
 | 
					 | 
				
			||||||
		this.encodeState = encoded ? EncodeState.FULLY_ENCODED : EncodeState.RAW;
 | 
							this.encodeState = encoded ? EncodeState.FULLY_ENCODED : EncodeState.RAW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Check for illegal characters..
 | 
							// Check for illegal characters..
 | 
				
			||||||
| 
						 | 
					@ -151,19 +153,18 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private HierarchicalUriComponents(@Nullable String scheme, @Nullable String fragment, @Nullable String userInfo,
 | 
						private HierarchicalUriComponents(@Nullable String scheme, @Nullable String fragment,
 | 
				
			||||||
			@Nullable String host, @Nullable String port, @Nullable PathComponent path,
 | 
								@Nullable String userInfo, @Nullable String host, @Nullable String port,
 | 
				
			||||||
			@Nullable MultiValueMap<String, String> queryParams, EncodeState encodeState,
 | 
								PathComponent path, MultiValueMap<String, String> queryParams,
 | 
				
			||||||
			@Nullable UnaryOperator<String> variableEncoder) {
 | 
								EncodeState encodeState, @Nullable UnaryOperator<String> variableEncoder) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		super(scheme, fragment);
 | 
							super(scheme, fragment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.userInfo = userInfo;
 | 
							this.userInfo = userInfo;
 | 
				
			||||||
		this.host = host;
 | 
							this.host = host;
 | 
				
			||||||
		this.port = port;
 | 
							this.port = port;
 | 
				
			||||||
		this.path = (path != null ? path : NULL_PATH_COMPONENT);
 | 
							this.path = path;
 | 
				
			||||||
		this.queryParams = CollectionUtils.unmodifiableMultiValueMap(
 | 
							this.queryParams = queryParams;
 | 
				
			||||||
				queryParams != null ? queryParams : new LinkedMultiValueMap<>(0));
 | 
					 | 
				
			||||||
		this.encodeState = encodeState;
 | 
							this.encodeState = encodeState;
 | 
				
			||||||
		this.variableEncoder = variableEncoder;
 | 
							this.variableEncoder = variableEncoder;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -254,6 +255,11 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Encoding
 | 
						// Encoding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Identical to {@link #encode()} but skipping over URI variable placeholders.
 | 
				
			||||||
 | 
						 * Also {@link #variableEncoder} is initialized with the given charset for
 | 
				
			||||||
 | 
						 * use later when URI variables are expanded.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	HierarchicalUriComponents encodeTemplate(Charset charset) {
 | 
						HierarchicalUriComponents encodeTemplate(Charset charset) {
 | 
				
			||||||
		if (this.encodeState.isEncoded()) {
 | 
							if (this.encodeState.isEncoded()) {
 | 
				
			||||||
			return this;
 | 
								return this;
 | 
				
			||||||
| 
						 | 
					@ -268,10 +274,10 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
		String userInfoTo = (getUserInfo() != null ? encoder.apply(getUserInfo(), Type.USER_INFO) : null);
 | 
							String userInfoTo = (getUserInfo() != null ? encoder.apply(getUserInfo(), Type.USER_INFO) : null);
 | 
				
			||||||
		String hostTo = (getHost() != null ? encoder.apply(getHost(), getHostType()) : null);
 | 
							String hostTo = (getHost() != null ? encoder.apply(getHost(), getHostType()) : null);
 | 
				
			||||||
		PathComponent pathTo = this.path.encode(encoder);
 | 
							PathComponent pathTo = this.path.encode(encoder);
 | 
				
			||||||
		MultiValueMap<String, String> paramsTo = encodeQueryParams(encoder);
 | 
							MultiValueMap<String, String> queryParamsTo = encodeQueryParams(encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
							return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
				
			||||||
				hostTo, this.port, pathTo, paramsTo, EncodeState.TEMPLATE_ENCODED, this.variableEncoder);
 | 
									hostTo, this.port, pathTo, queryParamsTo, EncodeState.TEMPLATE_ENCODED, this.variableEncoder);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
| 
						 | 
					@ -287,10 +293,10 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
		String hostTo = (this.host != null ? encodeUriComponent(this.host, charset, getHostType()) : null);
 | 
							String hostTo = (this.host != null ? encodeUriComponent(this.host, charset, getHostType()) : null);
 | 
				
			||||||
		BiFunction<String, Type, String> encoder = (s, type) -> encodeUriComponent(s, charset, type);
 | 
							BiFunction<String, Type, String> encoder = (s, type) -> encodeUriComponent(s, charset, type);
 | 
				
			||||||
		PathComponent pathTo = this.path.encode(encoder);
 | 
							PathComponent pathTo = this.path.encode(encoder);
 | 
				
			||||||
		MultiValueMap<String, String> paramsTo = encodeQueryParams(encoder);
 | 
							MultiValueMap<String, String> queryParamsTo = encodeQueryParams(encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
							return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
				
			||||||
				hostTo, this.port, pathTo, paramsTo, EncodeState.FULLY_ENCODED, null);
 | 
									hostTo, this.port, pathTo, queryParamsTo, EncodeState.FULLY_ENCODED, null);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private MultiValueMap<String, String> encodeQueryParams(BiFunction<String, Type, String> encoder) {
 | 
						private MultiValueMap<String, String> encodeQueryParams(BiFunction<String, Type, String> encoder) {
 | 
				
			||||||
| 
						 | 
					@ -300,11 +306,11 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
			String name = encoder.apply(key, Type.QUERY_PARAM);
 | 
								String name = encoder.apply(key, Type.QUERY_PARAM);
 | 
				
			||||||
			List<String> encodedValues = new ArrayList<>(values.size());
 | 
								List<String> encodedValues = new ArrayList<>(values.size());
 | 
				
			||||||
			for (String value : values) {
 | 
								for (String value : values) {
 | 
				
			||||||
				encodedValues.add(encoder.apply(value, Type.QUERY_PARAM));
 | 
									encodedValues.add(value != null ? encoder.apply(value, Type.QUERY_PARAM) : null);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			result.put(name, encodedValues);
 | 
								result.put(name, encodedValues);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		return result;
 | 
							return CollectionUtils.unmodifiableMultiValueMap(result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -428,10 +434,10 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
		String hostTo = expandUriComponent(this.host, uriVariables, this.variableEncoder);
 | 
							String hostTo = expandUriComponent(this.host, uriVariables, this.variableEncoder);
 | 
				
			||||||
		String portTo = expandUriComponent(this.port, uriVariables, this.variableEncoder);
 | 
							String portTo = expandUriComponent(this.port, uriVariables, this.variableEncoder);
 | 
				
			||||||
		PathComponent pathTo = this.path.expand(uriVariables, this.variableEncoder);
 | 
							PathComponent pathTo = this.path.expand(uriVariables, this.variableEncoder);
 | 
				
			||||||
		MultiValueMap<String, String> paramsTo = expandQueryParams(uriVariables);
 | 
							MultiValueMap<String, String> queryParamsTo = expandQueryParams(uriVariables);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
							return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo,
 | 
				
			||||||
				hostTo, portTo, pathTo, paramsTo, this.encodeState, this.variableEncoder);
 | 
									hostTo, portTo, pathTo, queryParamsTo, this.encodeState, this.variableEncoder);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private MultiValueMap<String, String> expandQueryParams(UriTemplateVariables variables) {
 | 
						private MultiValueMap<String, String> expandQueryParams(UriTemplateVariables variables) {
 | 
				
			||||||
| 
						 | 
					@ -446,7 +452,7 @@ final class HierarchicalUriComponents extends UriComponents {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			result.put(name, expandedValues);
 | 
								result.put(name, expandedValues);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		return result;
 | 
							return CollectionUtils.unmodifiableMultiValueMap(result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,8 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
 | 
				
			||||||
		this.pathBuilder = other.pathBuilder.cloneBuilder();
 | 
							this.pathBuilder = other.pathBuilder.cloneBuilder();
 | 
				
			||||||
		this.queryParams.putAll(other.queryParams);
 | 
							this.queryParams.putAll(other.queryParams);
 | 
				
			||||||
		this.fragment = other.fragment;
 | 
							this.fragment = other.fragment;
 | 
				
			||||||
 | 
							this.encodeTemplate = other.encodeTemplate;
 | 
				
			||||||
 | 
							this.charset = other.charset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -753,10 +753,10 @@ public class UriComponentsBuilderTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testClone() {
 | 
						public void testClone() {
 | 
				
			||||||
		UriComponentsBuilder builder1 = UriComponentsBuilder.newInstance();
 | 
							UriComponentsBuilder builder1 = UriComponentsBuilder.newInstance();
 | 
				
			||||||
		builder1.scheme("http").host("e1.com").path("/p1").pathSegment("ps1").queryParam("q1").fragment("f1");
 | 
							builder1.scheme("http").host("e1.com").path("/p1").pathSegment("ps1").queryParam("q1").fragment("f1").encode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		UriComponentsBuilder builder2 = (UriComponentsBuilder) builder1.clone();
 | 
							UriComponentsBuilder builder2 = (UriComponentsBuilder) builder1.clone();
 | 
				
			||||||
		builder2.scheme("https").host("e2.com").path("p2").pathSegment("ps2").queryParam("q2").fragment("f2");
 | 
							builder2.scheme("https").host("e2.com").path("p2").pathSegment("{ps2}").queryParam("q2").fragment("f2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		UriComponents result1 = builder1.build();
 | 
							UriComponents result1 = builder1.build();
 | 
				
			||||||
		assertEquals("http", result1.getScheme());
 | 
							assertEquals("http", result1.getScheme());
 | 
				
			||||||
| 
						 | 
					@ -765,10 +765,10 @@ public class UriComponentsBuilderTests {
 | 
				
			||||||
		assertEquals("q1", result1.getQuery());
 | 
							assertEquals("q1", result1.getQuery());
 | 
				
			||||||
		assertEquals("f1", result1.getFragment());
 | 
							assertEquals("f1", result1.getFragment());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		UriComponents result2 = builder2.build();
 | 
							UriComponents result2 = builder2.buildAndExpand("ps2;a");
 | 
				
			||||||
		assertEquals("https", result2.getScheme());
 | 
							assertEquals("https", result2.getScheme());
 | 
				
			||||||
		assertEquals("e2.com", result2.getHost());
 | 
							assertEquals("e2.com", result2.getHost());
 | 
				
			||||||
		assertEquals("/p1/ps1/p2/ps2", result2.getPath());
 | 
							assertEquals("/p1/ps1/p2/ps2%3Ba", result2.getPath());
 | 
				
			||||||
		assertEquals("q1&q2", result2.getQuery());
 | 
							assertEquals("q1&q2", result2.getQuery());
 | 
				
			||||||
		assertEquals("f2", result2.getFragment());
 | 
							assertEquals("f2", result2.getFragment());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +8,8 @@
 | 
				
			||||||
[source,java,indent=0]
 | 
					[source,java,indent=0]
 | 
				
			||||||
[subs="verbatim,quotes"]
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
	String uriTemplate = "http://example.com/hotels/{hotel}";
 | 
						UriComponents uriComponents = UriComponentsBuilder
 | 
				
			||||||
 | 
								.fromUriString("http://example.com/hotels/{hotel}")  // <1>
 | 
				
			||||||
	UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate)  // <1>
 | 
					 | 
				
			||||||
			.queryParam("q", "{q}")  // <2>
 | 
								.queryParam("q", "{q}")  // <2>
 | 
				
			||||||
			.encode() // <3>
 | 
								.encode() // <3>
 | 
				
			||||||
			.build(); // <4>
 | 
								.build(); // <4>
 | 
				
			||||||
| 
						 | 
					@ -23,18 +22,40 @@
 | 
				
			||||||
<4> Build a `UriComponents`.
 | 
					<4> Build a `UriComponents`.
 | 
				
			||||||
<5> Expand variables, and obtain the `URI`.
 | 
					<5> Expand variables, and obtain the `URI`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The above can also be done in shorthand form:
 | 
					The above can be consolidated into one chain and shortened with `buildAndExpand`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[source,java,indent=0]
 | 
					[source,java,indent=0]
 | 
				
			||||||
[subs="verbatim,quotes"]
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
	URI uri = UriComponentsBuilder.fromUriString(uriTemplate)
 | 
						URI uri = UriComponentsBuilder
 | 
				
			||||||
 | 
								.fromUriString("http://example.com/hotels/{hotel}")
 | 
				
			||||||
			.queryParam("q", "{q}")
 | 
								.queryParam("q", "{q}")
 | 
				
			||||||
			.encode()
 | 
								.encode()
 | 
				
			||||||
			.buildAndExpand("Westin", "123")
 | 
								.buildAndExpand("Westin", "123")
 | 
				
			||||||
			.toUri();
 | 
								.toUri();
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It can be shortened further by going directly to URI (which implies encoding):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[source,java,indent=0]
 | 
				
			||||||
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
						URI uri = UriComponentsBuilder
 | 
				
			||||||
 | 
								.fromUriString("http://example.com/hotels/{hotel}")
 | 
				
			||||||
 | 
								.queryParam("q", "{q}")
 | 
				
			||||||
 | 
								.build("Westin", "123");
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or shorter further yet, with a full URI template:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[source,java,indent=0]
 | 
				
			||||||
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
						URI uri = UriComponentsBuilder
 | 
				
			||||||
 | 
								.fromUriString("http://example.com/hotels/{hotel}?q={q}")
 | 
				
			||||||
 | 
								.build("Westin", "123");
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[web-uribuilder]]
 | 
					[[web-uribuilder]]
 | 
				
			||||||
= UriBuilder
 | 
					= UriBuilder
 | 
				
			||||||
| 
						 | 
					@ -125,15 +146,34 @@ Example usage using option 1:
 | 
				
			||||||
[source,java,indent=0]
 | 
					[source,java,indent=0]
 | 
				
			||||||
[subs="verbatim,quotes"]
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
	UriComponentsBuilder.fromPath("/hotel list/{city}")
 | 
					URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
 | 
				
			||||||
			.queryParam("q", "{q}")
 | 
								.queryParam("q", "{q}")
 | 
				
			||||||
			.encode()
 | 
								.encode()
 | 
				
			||||||
			.buildAndexpand("New York", "foo+bar")
 | 
								.buildAndExpand("New York", "foo+bar")
 | 
				
			||||||
			.toUriString();
 | 
								.toUri();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Result is "/hotel%20list/New%20York?foo%2Bbar"
 | 
						// Result is "/hotel%20list/New%20York?foo%2Bbar"
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above can be shortened by going directly to URI (which implies encoding):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[source,java,indent=0]
 | 
				
			||||||
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
 | 
				
			||||||
 | 
								.queryParam("q", "{q}")
 | 
				
			||||||
 | 
								.build("New York", "foo+bar")
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or shorter further yet, with a full URI template:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[source,java,indent=0]
 | 
				
			||||||
 | 
					[subs="verbatim,quotes"]
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
 | 
				
			||||||
 | 
								.build("New York", "foo+bar")
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The `WebClient` and the `RestTemplate` expand and encode URI templates internally through
 | 
					The `WebClient` and the `RestTemplate` expand and encode URI templates internally through
 | 
				
			||||||
the `UriBuilderFactory` strategy. Both can be configured with a custom strategy:
 | 
					the `UriBuilderFactory` strategy. Both can be configured with a custom strategy:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue