SPR-5836 - RestTemplate - postForObject() method

This commit is contained in:
Arjen Poutsma
2009-06-19 07:50:06 +00:00
parent 4ea373b7dd
commit ddcd9f4905
4 changed files with 252 additions and 134 deletions

View File

@@ -24,176 +24,203 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
/**
* Interface specifying a basic set of RESTful operations.
* Implemented by {@link RestTemplate}. Not often used directly, but a useful
* option to enhance testability, as it can easily be mocked or stubbed.
* Interface specifying a basic set of RESTful operations. Implemented by {@link RestTemplate}. Not often used directly,
* but a useful option to enhance testability, as it can easily be mocked or stubbed.
*
* @author Arjen Poutsma
* @since 3.0
* @see RestTemplate
* @since 3.0
*/
public interface RestOperations {
// GET
/**
* Retrieve a representation by doing a GET on the specified URL.
* Retrieve a representation by doing a GET on the specified URL. The response (if any) is converted and returned.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
*
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the variables to expand the template
* @return the converted object
*/
<T> T getForObject(String uri, Class<T> responseType, String... uriVariables) throws RestClientException;
<T> T getForObject(String url, Class<T> responseType, String... uriVariables) throws RestClientException;
/**
* Retrieve a representation by doing a GET on the URI template.
* Retrieve a representation by doing a GET on the URI template. The response (if any) is converted and returned.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
*
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the map containing variables for the URI template
* @return the converted object
*/
<T> T getForObject(String uri, Class<T> responseType, Map<String, String> uriVariables) throws RestClientException;
<T> T getForObject(String url, Class<T> responseType, Map<String, String> uriVariables) throws RestClientException;
// HEAD
/**
* Retrieve all headers of the resource specified by the URI template.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* Retrieve all headers of the resource specified by the URI template. <p>URI Template variables are expanded using the
* given URI variables, if any.
*
* @param url the URL
* @param uriVariables the variables to expand the template
* @return all HTTP headers of that resource
*/
HttpHeaders headForHeaders(String uri, String... uriVariables) throws RestClientException;
HttpHeaders headForHeaders(String url, String... uriVariables) throws RestClientException;
/**
* Retrieve all headers of the resource specified by the URI template.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
* Retrieve all headers of the resource specified by the URI template. <p>URI Template variables are expanded using the
* given map.
*
* @param url the URL
* @param uriVariables the map containing variables for the URI template
* @return all HTTP headers of that resource
*/
HttpHeaders headForHeaders(String uri, Map<String, String> uriVariables) throws RestClientException;
HttpHeaders headForHeaders(String url, Map<String, String> uriVariables) throws RestClientException;
// POST
/**
* Create a new resource by POSTing the given object to the URI template. The value of the <code>Location</code>
* header, indicating where the new resource is stored, is returned.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* Create a new resource by POSTing the given object to the URI template, and returns the value of the
* <code>Location</code> header. This header typically indicates where the new resource is stored. <p>URI Template
* variables are expanded using the given URI variables, if any.
*
* @param url the URL
* @param request the Object to be POSTed, may be <code>null</code>
* @return the value for the <code>Location</code> header
*/
URI postForLocation(String uri, Object request, String... uriVariables) throws RestClientException;
URI postForLocation(String url, Object request, String... uriVariables) throws RestClientException;
/**
* Create a new resource by POSTing the given object to URI template. The value of the <code>Location</code> header,
* indicating where the new resource is stored, is returned.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
* @param request the Object to be POSTed, may be <code>null</code>
* Create a new resource by POSTing the given object to the URI template, and returns the value of the
* <code>Location</code> header. This header typically indicates where the new resource is stored. <p>URI Template
* variables are expanded using the given map.
*
* @param url the URL
* @param request the Object to be POSTed, may be <code>null</code>
* @param uriVariables the variables to expand the template
* @return the value for the <code>Location</code> header
*/
URI postForLocation(String uri, Object request, Map<String, String> uriVariables) throws RestClientException;
URI postForLocation(String url, Object request, Map<String, String> uriVariables) throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URI template, and returns the converted representation
* found in the response. <p>URI Template variables are expanded using the given URI variables, if any.
*
* @param url the URL
* @param request the Object to be POSTed, may be <code>null</code>
* @return the converted object
*/
<T> T postForObject(String url, Object request, Class<T> responseType, String... uriVariables)
throws RestClientException;
/**
* Create a new resource by POSTing the given object to the URI template, and returns the converted representation
* found in the response. <p>URI Template variables are expanded using the given map.
*
* @param url the URL
* @param request the Object to be POSTed, may be <code>null</code>
* @return the converted object
*/
<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, String> uriVariables)
throws RestClientException;
// PUT
/**
* Create or update a resource by PUTting the given object to the URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* @param request the Object to be PUT, may be <code>null</code>
* Create or update a resource by PUTting the given object to the URI. <p>URI Template variables are expanded using the
* given URI variables, if any.
*
* @param url the URL
* @param request the Object to be PUT, may be <code>null</code>
* @param uriVariables the variables to expand the template
*/
void put(String uri, Object request, String... uriVariables) throws RestClientException;
void put(String url, Object request, String... uriVariables) throws RestClientException;
/**
* Creates a new resource by PUTting the given object to URI template.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
* @param request the Object to be PUT, may be <code>null</code>
* Creates a new resource by PUTting the given object to URI template. <p>URI Template variables are expanded using the
* given map.
*
* @param url the URL
* @param request the Object to be PUT, may be <code>null</code>
* @param uriVariables the variables to expand the template
*/
void put(String uri, Object request, Map<String, String> uriVariables) throws RestClientException;
void put(String url, Object request, Map<String, String> uriVariables) throws RestClientException;
// DELETE
/**
* Delete the resources at the specified URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* Delete the resources at the specified URI. <p>URI Template variables are expanded using the given URI variables, if
* any.
*
* @param url the URL
* @param uriVariables the variables to expand in the template
*/
void delete(String uri, String... uriVariables) throws RestClientException;
void delete(String url, String... uriVariables) throws RestClientException;
/**
* Delete the resources at the specified URI.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
* Delete the resources at the specified URI. <p>URI Template variables are expanded using the given map.
*
* @param url the URL
* @param uriVariables the variables to expand the template
*/
void delete(String uri, Map<String, String> uriVariables) throws RestClientException;
void delete(String url, Map<String, String> uriVariables) throws RestClientException;
// OPTIONS
/**
* Return the value of the Allow header for the given URI.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* Return the value of the Allow header for the given URI. <p>URI Template variables are expanded using the given URI
* variables, if any.
*
* @param url the URL
* @param uriVariables the variables to expand in the template
* @return the value of the allow header
*/
Set<HttpMethod> optionsForAllow(String uri, String... uriVariables) throws RestClientException;
Set<HttpMethod> optionsForAllow(String url, String... uriVariables) throws RestClientException;
/**
* Return the value of the Allow header for the given URI.
* <p>URI Template variables are expanded using the given map.
* @param uri the URI
* Return the value of the Allow header for the given URI. <p>URI Template variables are expanded using the given map.
*
* @param url the URL
* @param uriVariables the variables to expand in the template
* @return the value of the allow header
*/
Set<HttpMethod> optionsForAllow(String uri, Map<String, String> uriVariables) throws RestClientException;
Set<HttpMethod> optionsForAllow(String url, Map<String, String> uriVariables) throws RestClientException;
// general execution
/**
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback},
* and reading the response with a {@link ResponseExtractor}.
* <p>URI Template variables are expanded using the given URI variables, if any.
* @param uri the URI
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback}, and reading the
* response with a {@link ResponseExtractor}. <p>URI Template variables are expanded using the given URI variables, if
* any.
*
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* @param responseExtractor object that extracts the return value from the response
* @param uriVariables the variables to expand in the template
* @param uriVariables the variables to expand in the template
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
<T> T execute(String uri,
<T> T execute(String url,
HttpMethod method,
RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor,
String... uriVariables) throws RestClientException;
/**
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback},
* and reading the response with a {@link ResponseExtractor}.
* <p>URI Template variables are expanded using the given URI variables map.
* @param uri the URI
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* Execute the HTTP methods to the given URI, preparing the request with the {@link RequestCallback}, and reading the
* response with a {@link ResponseExtractor}. <p>URI Template variables are expanded using the given URI variables
* map.
*
* @param url the URL
* @param method the HTTP method (GET, POST, etc)
* @param requestCallback object that prepares the request
* @param responseExtractor object that extracts the return value from the response
* @param uriVariables the variables to expand in the template
* @param uriVariables the variables to expand in the template
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
<T> T execute(String uri,
<T> T execute(String url,
HttpMethod method,
RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor,

View File

@@ -45,27 +45,22 @@ import org.springframework.web.util.UriTemplate;
* enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs (with possible
* template variables) and extract results.
*
* <p>The main entry points of this template are the methods named after the six main HTTP methods:
* <table>
* <tr><th>HTTP method</th><th>RestTemplate methods</th></tr>
* <tr><td>DELETE</td><td>{@link #delete}</td></tr>
* <tr><td>GET</td><td>{@link #getForObject}</td></tr>
* <tr><td>HEAD</td><td>{@link #headForHeaders}</td></tr>
* <tr><td>OPTIONS</td><td>{@link #optionsForAllow}</td></tr>
* <tr><td>POST</td><td>{@link #postForLocation}</td></tr>
* <tr><td>PUT</td><td>{@link #put}</td></tr>
* <tr><td>any</td><td>{@link #execute}</td></tr>
* </table>
* <p>The main entry points of this template are the methods named after the six main HTTP methods: <table> <tr><th>HTTP
* method</th><th>RestTemplate methods</th></tr> <tr><td>DELETE</td><td>{@link #delete}</td></tr>
* <tr><td>GET</td><td>{@link #getForObject}</td></tr> <tr><td>HEAD</td><td>{@link #headForHeaders}</td></tr>
* <tr><td>OPTIONS</td><td>{@link #optionsForAllow}</td></tr> <tr><td>POST</td><td>{@link #postForLocation}</td></tr>
* <tr><td>PUT</td><td>{@link #put}</td></tr> <tr><td>any</td><td>{@link #execute}</td></tr> </table>
*
* <p>Each of these methods takes {@linkplain UriTemplate uri template} arguments in two forms: as a {@code String}
* variable arguments array, or as a {@code Map<String, String>}. The string varargs variant expands the given template
* variables in order, so that
* <pre>
* String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42", "21");
* String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42",
* "21");
* </pre>
* will perform a GET on {@code http://example.com/hotels/42/bookings/21}. The map variant expands the template
* based on variable name, and is therefore more useful when using many variables, or when a single variable is used
* multiple times. For example:
* will perform a GET on {@code http://example.com/hotels/42/bookings/21}. The map variant expands the template based on
* variable name, and is therefore more useful when using many variables, or when a single variable is used multiple
* times. For example:
* <pre>
* Map&lt;String, String&gt; vars = Collections.singletonMap("hotel", "42");
* String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
@@ -78,9 +73,9 @@ import org.springframework.web.util.UriTemplate;
* bean property.
*
* <p>This template uses a {@link org.springframework.http.client.SimpleClientHttpRequestFactory} and a {@link
* DefaultResponseErrorHandler} as default strategies for creating HTTP connections or handling HTTP errors, respectively.
* These defaults can be overridden through the {@link #setRequestFactory(ClientHttpRequestFactory) requestFactory} and
* {@link #setErrorHandler(ResponseErrorHandler) errorHandler} bean properties.
* DefaultResponseErrorHandler} as default strategies for creating HTTP connections or handling HTTP errors,
* respectively. These defaults can be overridden through the {@link #setRequestFactory(ClientHttpRequestFactory)
* requestFactory} and {@link #setErrorHandler(ResponseErrorHandler) errorHandler} bean properties.
*
* @author Arjen Poutsma
* @see HttpMessageConverter
@@ -116,18 +111,15 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
}
/**
* Set the message body converters to use. These converters are used to convert
* from and to HTTP requests and responses.
* Set the message body converters to use. These converters are used to convert from and to HTTP requests and
* responses.
*/
public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
this.messageConverters = messageConverters;
}
/**
* Returns the message body converters. These converters are used to convert
* from and to HTTP requests and responses.
*/
/** Returns the message body converters. These converters are used to convert from and to HTTP requests and responses. */
public HttpMessageConverter<?>[] getMessageConverters() {
return this.messageConverters;
}
@@ -167,7 +159,7 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
checkForSupportedMessageConverter(responseType);
List<HttpMessageConverter<T>> supportedMessageConverters = getSupportedMessageConverters(responseType);
return execute(url, HttpMethod.GET, new GetCallback<T>(supportedMessageConverters),
return execute(url, HttpMethod.GET, new AcceptHeaderRequestCallback<T>(supportedMessageConverters),
new HttpMessageConverterExtractor<T>(responseType, supportedMessageConverters), urlVariables);
}
@@ -176,7 +168,7 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
checkForSupportedMessageConverter(responseType);
List<HttpMessageConverter<T>> supportedMessageConverters = getSupportedMessageConverters(responseType);
return execute(url, HttpMethod.GET, new GetCallback<T>(supportedMessageConverters),
return execute(url, HttpMethod.GET, new AcceptHeaderRequestCallback<T>(supportedMessageConverters),
new HttpMessageConverterExtractor<T>(responseType, supportedMessageConverters), urlVariables);
}
@@ -211,6 +203,28 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
return headers.getLocation();
}
public <T> T postForObject(String url, Object request, Class<T> responseType, String... uriVariables)
throws RestClientException {
if (request != null) {
checkForSupportedMessageConverter(request.getClass());
}
checkForSupportedMessageConverter(responseType);
List<HttpMessageConverter<T>> responseMessageConverters = getSupportedMessageConverters(responseType);
return execute(url, HttpMethod.POST, new PostPutCallback<T>(request, responseMessageConverters),
new HttpMessageConverterExtractor<T>(responseType, responseMessageConverters), uriVariables);
}
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, String> uriVariables)
throws RestClientException {
if (request != null) {
checkForSupportedMessageConverter(request.getClass());
}
checkForSupportedMessageConverter(responseType);
List<HttpMessageConverter<T>> responseMessageConverters = getSupportedMessageConverters(responseType);
return execute(url, HttpMethod.POST, new PostPutCallback<T>(request, responseMessageConverters),
new HttpMessageConverterExtractor<T>(responseType, responseMessageConverters), uriVariables);
}
// PUT
public void put(String url, Object request, String... urlVariables) throws RestClientException {
@@ -337,11 +351,11 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
}
/** Request callback implementation that prepares the request's accept headers. */
private class GetCallback<T> implements RequestCallback {
private class AcceptHeaderRequestCallback<T> implements RequestCallback {
private final List<HttpMessageConverter<T>> messageConverters;
private GetCallback(List<HttpMessageConverter<T>> messageConverters) {
private AcceptHeaderRequestCallback(List<HttpMessageConverter<T>> messageConverters) {
this.messageConverters = messageConverters;
}
@@ -357,22 +371,32 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
allSupportedMediaTypes.add(supportedMediaType);
}
}
Collections.sort(allSupportedMediaTypes);
request.getHeaders().setAccept(allSupportedMediaTypes);
if (!allSupportedMediaTypes.isEmpty()) {
Collections.sort(allSupportedMediaTypes);
request.getHeaders().setAccept(allSupportedMediaTypes);
}
}
}
/** Request callback implementation that writes the given object to the request stream. */
private class PostPutCallback implements RequestCallback {
private class PostPutCallback<T> extends AcceptHeaderRequestCallback<T> {
private final Object request;
private PostPutCallback(Object request) {
private PostPutCallback(Object request, List<HttpMessageConverter<T>> responseMessageConverters) {
super(responseMessageConverters);
this.request = request;
}
private PostPutCallback(Object request) {
super(Collections.<HttpMessageConverter<T>>emptyList());
this.request = request;
}
@Override
@SuppressWarnings("unchecked")
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
super.doWithRequest(httpRequest);
if (request != null) {
HttpMessageConverter entityConverter = getSupportedMessageConverters(this.request.getClass()).get(0);
entityConverter.write(this.request, httpRequest);