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 cfb5e7ac3f..b74e2e13ec 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 @@ -167,6 +167,11 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory { return new DefaultUriBuilder(uriTemplate); } + @Override + public UriBuilder builder() { + return new DefaultUriBuilder(""); + } + /** * {@link DefaultUriBuilderFactory} specific implementation of UriBuilder. @@ -182,9 +187,11 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory { private UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) { - UriComponentsBuilder result = baseUri.cloneBuilder(); - UriComponents child = UriComponentsBuilder.fromUriString(uriTemplate).build(); - result.uriComponents(child); + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(uriTemplate); + UriComponents uriComponents = uriComponentsBuilder.build(); + + UriComponentsBuilder result = (uriComponents.getHost() == null ? + baseUri.cloneBuilder().uriComponents(uriComponents) : uriComponentsBuilder); if (shouldParsePath()) { UriComponents uric = result.build(); diff --git a/spring-web/src/main/java/org/springframework/web/util/UriBuilderFactory.java b/spring-web/src/main/java/org/springframework/web/util/UriBuilderFactory.java index 504a7d5092..8eec565720 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriBuilderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriBuilderFactory.java @@ -30,14 +30,18 @@ package org.springframework.web.util; public interface UriBuilderFactory extends UriTemplateHandler { /** - * Return a builder that is initialized with the given URI string which may - * be a URI template and represent full URI or just a path. - *
Depending on the factory implementation and configuration, the builder - * may merge the given URI string with a base URI and apply other operations. - * Refer to the specific factory implementation for details. - * @param uriTemplate the URI template to create the builder with + * Return a builder initialized with the given URI string. + *
Concrete implementations may apply further initializations such as
+ * combining with a pre-configured base URI.
+ * @param uriTemplate the URI template to initialize the builder with
* @return the UriBuilder
*/
UriBuilder uriString(String uriTemplate);
+ /**
+ * Return a builder to prepare a new URI.
+ * @return the UriBuilder
+ */
+ UriBuilder builder();
+
}
diff --git a/spring-web/src/test/java/org/springframework/web/util/DefaultUriBuilderFactoryTests.java b/spring-web/src/test/java/org/springframework/web/util/DefaultUriBuilderFactoryTests.java
index cab2ad614b..a6aae94dde 100644
--- a/spring-web/src/test/java/org/springframework/web/util/DefaultUriBuilderFactoryTests.java
+++ b/spring-web/src/test/java/org/springframework/web/util/DefaultUriBuilderFactoryTests.java
@@ -41,40 +41,48 @@ public class DefaultUriBuilderFactoryTests {
@Test
public void baseUri() throws Exception {
- DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/bar?id=123");
- URI uri = factory.uriString("/baz").port(8080).build();
- assertEquals("http://foo.com:8080/bar/baz?id=123", uri.toString());
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1?id=123");
+ URI uri = factory.uriString("/bar").port(8080).build();
+ assertEquals("http://foo.com:8080/v1/bar?id=123", uri.toString());
+ }
+
+ @Test
+ public void baseUriWithFullOverride() throws Exception {
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1?id=123");
+ URI uri = factory.uriString("http://example.com/1/2").build();
+ assertEquals("Use of host should case baseUri to be completely ignored",
+ "http://example.com/1/2", uri.toString());
}
@Test
public void baseUriWithPathOverride() throws Exception {
- DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/bar");
- URI uri = factory.uriString("").replacePath("/baz").build();
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1");
+ URI uri = factory.builder().replacePath("/baz").build();
assertEquals("http://foo.com/baz", uri.toString());
}
@Test
public void defaultUriVars() throws Exception {
- DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "foo.com"));
URI uri = factory.uriString("/{id}").build(singletonMap("id", "123"));
- assertEquals("http://foo.com/bar/123", uri.toString());
+ assertEquals("http://foo.com/v1/123", uri.toString());
}
@Test
public void defaultUriVarsWithOverride() throws Exception {
- DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "spring.io"));
- URI uri = factory.uriString("/baz").build(singletonMap("host", "docs.spring.io"));
- assertEquals("http://docs.spring.io/bar/baz", uri.toString());
+ URI uri = factory.uriString("/bar").build(singletonMap("host", "docs.spring.io"));
+ assertEquals("http://docs.spring.io/v1/bar", uri.toString());
}
@Test
public void defaultUriVarsWithEmptyVarArg() throws Exception {
- DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
+ DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "foo.com"));
- URI uri = factory.uriString("/baz").build();
- assertEquals("Expected delegation to build(Map) method", "http://foo.com/bar/baz", uri.toString());
+ URI uri = factory.uriString("/bar").build();
+ assertEquals("Expected delegation to build(Map) method", "http://foo.com/v1/bar", uri.toString());
}
@Test
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
index 0a6d365659..24dca9f29d 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
@@ -38,6 +38,7 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.util.DefaultUriBuilderFactory;
+import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
@@ -150,8 +151,8 @@ class DefaultWebClient implements WebClient {
}
@Override
- public HeaderSpec uri(Function Given the following initialization:
+ * For example given this initialization:
* A base URI is applied when using a URI template:
+ * The base URI is applied to exchanges with a URI template:
* It is also applied when using a {@link UriBuilderFactory}:
+ * The base URI is also applied to exchanges with a {@code UriBuilder}:
* The base URI can be overridden with an absolute URI:
+ * The base URI can be partially overridden with a {@code UriBuilder}:
+ *
* WebClient client = WebClient.create("http://abc.com/v1");
*
*
- *
- *
* // GET http://abc.com/v1/accounts/43
- *
* Mono<Account> result = client.get()
* .uri("/accounts/{id}", 43)
* .exchange()
- * .then(response -> response.bodyToMono(String.class));
+ * .then(response -> response.bodyToMono(Account.class));
*
*
- *
-
* // GET http://abc.com/v1/accounts?q=12
- *
- * Mono<Account> result = client.get()
- * .uri(factory -> factory.uriString("/accounts").queryParam("q", "12").build())
+ * Flux<Account> result = client.get()
+ * .uri(builder -> builder.path("/accounts").queryParam("q", "12").build())
* .exchange()
- * .then(response -> response.bodyToMono(String.class));
+ * .then(response -> response.bodyToFlux(Account.class));
*
*
+ *
+ * // GET http://xyz.com/path
+ * Mono<Account> result = client.get()
+ * .uri("http://xyz.com/path")
+ * .exchange()
+ * .then(response -> response.bodyToMono(Account.class));
+ *
+ *
+ *
+ * // GET http://abc.com/v2/accounts?q=12
+ * Flux<Account> result = client.get()
+ * .uri(builder -> builder.replacePath("/v2/accounts").queryParam("q", "12").build())
+ * .exchange()
+ * .then(response -> response.bodyToFlux(Account.class));
+ *
+ *
+ *
* @param baseUrl the base URI for all requests
*/
static WebClient create(String baseUrl) {
@@ -284,7 +301,7 @@ public interface WebClient {
* Build the URI for the request using the {@link UriBuilderFactory}
* configured for this client.
*/
- HeaderSpec uri(Function