diff --git a/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java index 351c46e7ad..00c9a87677 100644 --- a/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/AsyncRestTemplate.java @@ -45,6 +45,7 @@ import org.springframework.util.Assert; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureAdapter; import org.springframework.web.util.AbstractUriTemplateHandler; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.UriTemplateHandler; /** @@ -163,9 +164,16 @@ public class AsyncRestTemplate extends InterceptingAsyncHttpAccessor implements */ public void setDefaultUriVariables(Map defaultUriVariables) { UriTemplateHandler handler = this.syncTemplate.getUriTemplateHandler(); - Assert.isInstanceOf(AbstractUriTemplateHandler.class, handler, - "Can only use this property in conjunction with a DefaultUriTemplateHandler"); - ((AbstractUriTemplateHandler) handler).setDefaultUriVariables(defaultUriVariables); + if (handler instanceof DefaultUriBuilderFactory) { + ((DefaultUriBuilderFactory) handler).setDefaultUriVariables(defaultUriVariables); + } + else if (handler instanceof AbstractUriTemplateHandler) { + ((AbstractUriTemplateHandler) handler).setDefaultUriVariables(defaultUriVariables); + } + else { + throw new IllegalArgumentException( + "This property is not supported with the configured UriTemplateHandler."); + } } /** diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index 316a5d2c80..22721dc212 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -53,7 +53,7 @@ import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.web.util.AbstractUriTemplateHandler; -import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.UriTemplateHandler; /** @@ -149,7 +149,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); - private UriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler(); + private UriTemplateHandler uriTemplateHandler = new DefaultUriBuilderFactory(); private final ResponseExtractor headersExtractor = new HeadersExtractor(); @@ -254,24 +254,31 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat /** * Configure default URI variable values. This is a shortcut for: *
-	 * DefaultUriTemplateHandler handler = new DefaultUriTemplateHandler();
+	 * DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
 	 * handler.setDefaultUriVariables(...);
 	 *
 	 * RestTemplate restTemplate = new RestTemplate();
 	 * restTemplate.setUriTemplateHandler(handler);
 	 * 
- * @param defaultUriVariables the default URI variable values + * @param uriVars the default URI variable values * @since 4.3 */ - public void setDefaultUriVariables(Map defaultUriVariables) { - Assert.isInstanceOf(AbstractUriTemplateHandler.class, this.uriTemplateHandler, - "Can only use this property in conjunction with an AbstractUriTemplateHandler"); - ((AbstractUriTemplateHandler) this.uriTemplateHandler).setDefaultUriVariables(defaultUriVariables); + public void setDefaultUriVariables(Map uriVars) { + if (this.uriTemplateHandler instanceof DefaultUriBuilderFactory) { + ((DefaultUriBuilderFactory) this.uriTemplateHandler).setDefaultUriVariables(uriVars); + } + else if (this.uriTemplateHandler instanceof AbstractUriTemplateHandler) { + ((AbstractUriTemplateHandler) this.uriTemplateHandler).setDefaultUriVariables(uriVars); + } + else { + throw new IllegalArgumentException( + "This property is not supported with the configured UriTemplateHandler."); + } } /** * Configure the {@link UriTemplateHandler} to use to expand URI templates. - * By default the {@link DefaultUriTemplateHandler} is used which relies on + * By default the {@link DefaultUriBuilderFactory} is used which relies on * Spring's URI template support and exposes several useful properties that * customize its behavior for encoding and for prepending a common base URL. * An alternative implementation may be used to plug an external URI diff --git a/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java b/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java index b4a8cbb318..d8a88c4637 100644 --- a/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java +++ b/spring-web/src/main/java/org/springframework/web/util/AbstractUriTemplateHandler.java @@ -33,7 +33,9 @@ import org.springframework.util.Assert; * * @author Rossen Stoyanchev * @since 4.3 + * @deprecated as of 5.0 in favor of {@link DefaultUriBuilderFactory} */ +@Deprecated public abstract class AbstractUriTemplateHandler implements UriTemplateHandler { private String baseUrl; diff --git a/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java b/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java index 8c0ad71504..9ad9357a30 100644 --- a/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java +++ b/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java @@ -33,7 +33,9 @@ import java.util.Map; * * @author Rossen Stoyanchev * @since 4.2 + * @deprecated as of 5.0 in favor of {@link DefaultUriBuilderFactory} */ +@Deprecated public class DefaultUriTemplateHandler extends AbstractUriTemplateHandler { private boolean parsePath; 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 905f29eef3..98c9a7cdd1 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 @@ -455,8 +455,9 @@ final class HierarchicalUriComponents extends UriComponents { if (getHost() != null) { builder.host(getHost()); } - if (getPort() != -1) { - builder.port(getPort()); + // Avoid parsing the port, may have URI variable.. + if (this.port != null) { + builder.port(this.port); } if (getPath() != null) { this.path.copyToUriComponentsBuilder(builder); diff --git a/spring-web/src/main/java/org/springframework/web/util/UriTemplateHandler.java b/spring-web/src/main/java/org/springframework/web/util/UriTemplateHandler.java index c03eb191ab..d394d34f31 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriTemplateHandler.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriTemplateHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -20,18 +20,14 @@ import java.net.URI; import java.util.Map; /** - * Strategy for expanding a URI template with full control over the URI template - * syntax and the encoding of variables. Also a convenient central point for - * pre-processing all URI templates for example to insert a common base path. + * Strategy for expanding a URI template. * *

Supported as a property on the {@code RestTemplate} as well as the - * {@code AsyncRestTemplate}. The {@link DefaultUriTemplateHandler} is built - * on Spring's URI template support via {@link UriComponentsBuilder}. An - * alternative implementation may be used to plug external URI template libraries. + * {@code AsyncRestTemplate}. * * @author Rossen Stoyanchev * @since 4.2 - * @see org.springframework.web.client.RestTemplate#setUriTemplateHandler + * @see DefaultUriBuilderFactory */ public interface UriTemplateHandler { diff --git a/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java b/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java index 1b3f4fe24c..1ada39213a 100644 --- a/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/RestTemplateTests.java @@ -42,7 +42,7 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.DefaultUriBuilderFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -83,7 +83,7 @@ public class RestTemplateTests { response = mock(ClientHttpResponse.class); errorHandler = mock(ResponseErrorHandler.class); converter = mock(HttpMessageConverter.class); - template = new RestTemplate(Collections.>singletonList(converter)); + template = new RestTemplate(Collections.singletonList(converter)); template.setRequestFactory(requestFactory); template.setErrorHandler(errorHandler); } @@ -273,8 +273,7 @@ public class RestTemplateTests { @Test public void getForObjectWithCustomUriTemplateHandler() throws Exception { - DefaultUriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler(); - uriTemplateHandler.setParsePath(true); + DefaultUriBuilderFactory uriTemplateHandler = new DefaultUriBuilderFactory(); template.setUriTemplateHandler(uriTemplateHandler); URI expectedUri = new URI("http://example.com/hotels/1/pic/pics%2Flogo.png/size/150x150"); 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 f7931ffcc0..c7481d7de5 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 @@ -16,12 +16,14 @@ package org.springframework.web.util; import java.net.URI; -import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode; +import static java.util.Collections.singletonMap; import static junit.framework.TestCase.assertEquals; /** @@ -30,9 +32,6 @@ import static junit.framework.TestCase.assertEquals; */ public class DefaultUriBuilderFactoryTests { - private static final String baseUrl = "http://foo.com/bar"; - - @Test public void defaultSettings() throws Exception { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); @@ -57,27 +56,39 @@ public class DefaultUriBuilderFactoryTests { @Test public void defaultUriVars() throws Exception { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar"); - factory.setDefaultUriVariables(Collections.singletonMap("host", "foo.com")); - URI uri = factory.uriString("/{id}").build(Collections.singletonMap("id", "123")); + factory.setDefaultUriVariables(singletonMap("host", "foo.com")); + URI uri = factory.uriString("/{id}").build(singletonMap("id", "123")); assertEquals("http://foo.com/bar/123", uri.toString()); } @Test public void defaultUriVarsWithOverride() throws Exception { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar"); - factory.setDefaultUriVariables(Collections.singletonMap("host", "spring.io")); - URI uri = factory.uriString("/baz").build(Collections.singletonMap("host", "docs.spring.io")); + 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()); } @Test public void defaultUriVarsWithEmptyVarArg() throws Exception { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar"); - factory.setDefaultUriVariables(Collections.singletonMap("host", "foo.com")); + 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()); } + @Test + public void defaultUriVarsSpr14147() throws Exception { + Map defaultUriVars = new HashMap<>(2); + defaultUriVars.put("host", "api.example.com"); + defaultUriVars.put("port", "443"); + DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); + factory.setDefaultUriVariables(defaultUriVars); + + URI uri = factory.expand("https://{host}:{port}/v42/customers/{id}", singletonMap("id", 123L)); + assertEquals("https://api.example.com:443/v42/customers/123", uri.toString()); + } + @Test public void encodingValuesOnly() throws Exception { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); @@ -88,7 +99,18 @@ public class DefaultUriBuilderFactoryTests { String expected = "/foo/a%2Fb/c%2Fd"; assertEquals(expected, uriBuilder.build(id).toString()); - assertEquals(expected, uriBuilder.build(Collections.singletonMap("id", id)).toString()); + assertEquals(expected, uriBuilder.build(singletonMap("id", id)).toString()); + } + + @Test + public void encodingValuesOnlySpr14147() throws Exception { + DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); + factory.setEncodingMode(EncodingMode.VALUES_ONLY); + factory.setDefaultUriVariables(singletonMap("host", "www.example.com")); + UriBuilder uriBuilder = factory.uriString("http://{host}/user/{userId}/dashboard"); + + assertEquals("http://www.example.com/user/john%3Bdoe/dashboard", + uriBuilder.build(singletonMap("userId", "john;doe")).toString()); } @Test @@ -101,7 +123,7 @@ public class DefaultUriBuilderFactoryTests { String expected = "/foo/a%2Fb/c%2Fd"; assertEquals(expected, uriBuilder.build(id).toString()); - assertEquals(expected, uriBuilder.build(Collections.singletonMap("id", id)).toString()); + assertEquals(expected, uriBuilder.build(singletonMap("id", id)).toString()); } @Test