Add defaultUriVariables property to RestTemplate

Issue: SPR-14147
This commit is contained in:
Rossen Stoyanchev 2016-04-22 16:18:26 -04:00
parent 0d007a328b
commit 065b7968a3
4 changed files with 109 additions and 5 deletions

View File

@ -44,6 +44,7 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureAdapter;
import org.springframework.web.util.DefaultUriTemplateHandler;
import org.springframework.web.util.UriTemplateHandler;
/**
@ -150,6 +151,26 @@ public class AsyncRestTemplate extends InterceptingAsyncHttpAccessor implements
return this.syncTemplate.getErrorHandler();
}
/**
* Configure default URI variable values. This is a shortcut for:
* <pre class="code">
*
* DefaultUriTemplateHandler handler = new DefaultUriTemplateHandler();
* handler.setDefaultUriVariables(...);
*
* AsyncRestTemplate restTemplate = new AsyncRestTemplate();
* restTemplate.setUriTemplateHandler(handler);
* </pre>
* @param defaultUriVariables the default URI variable values
* @since 4.3
*/
public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) {
UriTemplateHandler handler = this.syncTemplate.getUriTemplateHandler();
Assert.isInstanceOf(DefaultUriTemplateHandler.class, handler,
"Can only use this property in conjunction with a DefaultUriTemplateHandler.");
((DefaultUriTemplateHandler) handler).setDefaultUriVariables(defaultUriVariables);
}
/**
* This property has the same purpose as the corresponding property on the
* {@code RestTemplate}. For more details see

View File

@ -236,6 +236,25 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
return this.errorHandler;
}
/**
* Configure default URI variable values. This is a shortcut for:
* <pre class="code">
*
* DefaultUriTemplateHandler handler = new DefaultUriTemplateHandler();
* handler.setDefaultUriVariables(...);
*
* RestTemplate restTemplate = new RestTemplate();
* restTemplate.setUriTemplateHandler(handler);
* </pre>
* @param defaultUriVariables the default URI variable values
* @since 4.3
*/
public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) {
Assert.isInstanceOf(DefaultUriTemplateHandler.class, this.uriTemplateHandler,
"Can only use this property in conjunction with a DefaultUriTemplateHandler.");
((DefaultUriTemplateHandler) this.uriTemplateHandler).setDefaultUriVariables(defaultUriVariables);
}
/**
* Configure the {@link UriTemplateHandler} to use to expand URI templates.
* By default the {@link DefaultUriTemplateHandler} is used which relies on

View File

@ -19,6 +19,7 @@ package org.springframework.web.util;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -41,6 +42,7 @@ public class DefaultUriTemplateHandler implements UriTemplateHandler {
private String baseUrl;
private final Map<String, Object> defaultUriVariables = new HashMap<String, Object>();
private boolean parsePath;
@ -72,6 +74,28 @@ public class DefaultUriTemplateHandler implements UriTemplateHandler {
return this.baseUrl;
}
/**
* Configure default URI variable values to use with every expanded URI
* template. This default values apply only when expanding with a Map, and
* not with an array, where the Map supplied to expand can override the
* default values.
* @param defaultUriVariables the default URI variable values
* @since 4.3
*/
public void setDefaultUriVariables(Map<String, ?> defaultUriVariables) {
this.defaultUriVariables.clear();
if (defaultUriVariables != null) {
this.defaultUriVariables.putAll(defaultUriVariables);
}
}
/**
* Return a read-only copy of the configured default URI variables.
*/
public Map<String, ?> getDefaultUriVariables() {
return Collections.unmodifiableMap(this.defaultUriVariables);
}
/**
* Whether to parse the path of a URI template string into path segments.
* <p>If set to {@code true} the URI template path is immediately decomposed
@ -152,15 +176,23 @@ public class DefaultUriTemplateHandler implements UriTemplateHandler {
}
protected UriComponents expandAndEncode(UriComponentsBuilder builder, Map<String, ?> uriVariables) {
if (!isStrictEncoding()) {
// Simple scenario: use the input map
if (getDefaultUriVariables().isEmpty() && !isStrictEncoding()) {
return builder.build().expand(uriVariables).encode();
}
// Create a new map
Map<String, Object> variablesToUse = new HashMap<String, Object>();
variablesToUse.putAll(getDefaultUriVariables());
variablesToUse.putAll(uriVariables);
if (!isStrictEncoding()) {
return builder.build().expand(variablesToUse).encode();
}
else {
Map<String, Object> encodedUriVars = new HashMap<String, Object>(uriVariables.size());
for (Map.Entry<String, ?> entry : uriVariables.entrySet()) {
encodedUriVars.put(entry.getKey(), applyStrictEncoding(entry.getValue()));
for (Map.Entry<String, ?> entry : variablesToUse.entrySet()) {
variablesToUse.put(entry.getKey(), applyStrictEncoding(entry.getValue()));
}
return builder.build().expand(encodedUriVars);
return builder.build().expand(variablesToUse);
}
}

View File

@ -49,6 +49,22 @@ public class DefaultUriTemplateHandlerTests {
assertEquals("http://localhost:8080/context/myapiresource", actual.toString());
}
@Test // SPR-14147
public void defaultUriVariables() throws Exception {
Map<String, String> defaultVars = new HashMap<>(2);
defaultVars.put("host", "api.example.com");
defaultVars.put("port", "443");
this.handler.setDefaultUriVariables(defaultVars);
Map<String, Object> vars = new HashMap<>(1);
vars.put("id", 123L);
String template = "https://{host}:{port}/v42/customers/{id}";
URI actual = this.handler.expand(template, vars);
assertEquals("https://api.example.com:443/v42/customers/123", actual.toString());
}
@Test
public void parsePathIsOff() throws Exception {
this.handler.setParsePath(false);
@ -114,4 +130,20 @@ public class DefaultUriTemplateHandlerTests {
assertEquals("http://www.example.com/user/john%3Bdoe/dashboard", actual.toString());
}
@Test // SPR-14147
public void strictEncodingAndDefaultUriVariables() throws Exception {
Map<String, String> defaultVars = new HashMap<>(1);
defaultVars.put("host", "www.example.com");
this.handler.setDefaultUriVariables(defaultVars);
this.handler.setStrictEncoding(true);
Map<String, Object> vars = new HashMap<>(1);
vars.put("userId", "john;doe");
String template = "http://{host}/user/{userId}/dashboard";
URI actual = this.handler.expand(template, vars);
assertEquals("http://www.example.com/user/john%3Bdoe/dashboard", actual.toString());
}
}