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 8d02c531ed5..2739e386a56 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import javax.xml.transform.Source; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; @@ -79,14 +80,14 @@ import org.springframework.web.util.UriTemplate; * {@link #getForObject(String, Class, Map)}), and are capable of substituting any {@linkplain UriTemplate URI templates} * in that URL using either a {@code String} variable arguments array, or a {@code Map}. * The string varargs variant expands the given template variables in order, so that - *
+ * 
  * String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42",
  * "21");
  * 
* 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: - *
+ * 
  * Map<String, String> vars = Collections.singletonMap("hotel", "42");
  * String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
  * 
@@ -95,7 +96,7 @@ import org.springframework.web.util.UriTemplate; * expanded URI multiple times. * *

Furthermore, the {@code String}-argument methods assume that the URL String is unencoded. This means that - *

+ * 
  * restTemplate.getForObject("http://example.com/hotel list");
  * 
* will perform a GET on {@code http://example.com/hotel%20list}. As a result, any URL passed that is already encoded @@ -114,6 +115,7 @@ import org.springframework.web.util.UriTemplate; * requestFactory} and {@link #setErrorHandler(ResponseErrorHandler) errorHandler} bean properties. * * @author Arjen Poutsma + * @author Brian Clozel * @since 3.0 * @see HttpMessageConverter * @see RequestCallback @@ -137,21 +139,22 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", RestTemplate.class.getClassLoader()); - private final ResponseExtractor headersExtractor = new HeadersExtractor(); - - private List> messageConverters = new ArrayList>(); + private final List> messageConverters = new ArrayList>(); private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); + private final ResponseExtractor headersExtractor = new HeadersExtractor(); + /** * Create a new instance of the {@link RestTemplate} using default settings. + * Default {@link HttpMessageConverter}s are initialized. */ public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); this.messageConverters.add(new ResourceHttpMessageConverter()); - this.messageConverters.add(new SourceHttpMessageConverter()); + this.messageConverters.add(new SourceHttpMessageConverter()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); if (romePresent) { this.messageConverters.add(new AtomFeedHttpMessageConverter()); @@ -179,6 +182,17 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat setRequestFactory(requestFactory); } + /** + * Create a new instance of the {@link RestTemplate} using the given list of + * {@link HttpMessageConverter} to use + * @param messageConverters the list of {@link HttpMessageConverter} to use + * @since 3.2.7 + */ + public RestTemplate(List> messageConverters) { + Assert.notEmpty(messageConverters, "'messageConverters' must not be empty"); + this.messageConverters.addAll(messageConverters); + } + /** * Set the message body converters to use. @@ -186,7 +200,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat */ public void setMessageConverters(List> messageConverters) { Assert.notEmpty(messageConverters, "'messageConverters' must not be empty"); - this.messageConverters = messageConverters; + this.messageConverters.clear(); + this.messageConverters.addAll(messageConverters); } /** @@ -238,6 +253,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public ResponseEntity getForEntity(String url, Class responseType, Object... urlVariables) throws RestClientException { + AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType); ResponseEntityResponseExtractor responseExtractor = new ResponseEntityResponseExtractor(responseType); @@ -246,6 +262,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public ResponseEntity getForEntity(String url, Class responseType, Map urlVariables) throws RestClientException { + AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType); ResponseEntityResponseExtractor responseExtractor = new ResponseEntityResponseExtractor(responseType); @@ -283,6 +300,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public URI postForLocation(String url, Object request, Map urlVariables) throws RestClientException { + HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request); HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, this.headersExtractor, urlVariables); return headers.getLocation(); @@ -296,6 +314,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public T postForObject(String url, Object request, Class responseType, Object... uriVariables) throws RestClientException { + HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType); HttpMessageConverterExtractor responseExtractor = new HttpMessageConverterExtractor(responseType, getMessageConverters(), logger); @@ -304,6 +323,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public T postForObject(String url, Object request, Class responseType, Map uriVariables) throws RestClientException { + HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType); HttpMessageConverterExtractor responseExtractor = new HttpMessageConverterExtractor(responseType, getMessageConverters(), logger); @@ -466,8 +486,9 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } /** - * Execute the given method on the provided URI. The {@link ClientHttpRequest} is processed using the {@link - * RequestCallback}; the response with the {@link ResponseExtractor}. + * Execute the given method on the provided URI. + *

The {@link ClientHttpRequest} is processed using the {@link RequestCallback}; + * the response with the {@link ResponseExtractor}. * @param url the fully-expanded URL to connect to * @param method the HTTP method to execute (GET, POST, etc.) * @param requestCallback object that prepares the request (can be {@code null}) @@ -501,7 +522,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } catch (IOException ex) { throw new ResourceAccessException("I/O error on " + method.name() + - " request for \"" + url + "\":" + ex.getMessage(), ex); + " request for \"" + url + "\": " + ex.getMessage(), ex); } finally { if (response != null) { @@ -513,9 +534,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) { if (logger.isDebugEnabled()) { try { - logger.debug( - method.name() + " request for \"" + url + "\" resulted in " + response.getStatusCode() + " (" + - response.getStatusText() + ")"); + logger.debug(method.name() + " request for \"" + url + "\" resulted in " + + response.getStatusCode() + " (" + response.getStatusText() + ")"); } catch (IOException e) { // ignore @@ -526,9 +546,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException { if (logger.isWarnEnabled()) { try { - logger.warn( - method.name() + " request for \"" + url + "\" resulted in " + response.getStatusCode() + " (" + - response.getStatusText() + "); invoking error handler"); + logger.warn(method.name() + " request for \"" + url + "\" resulted in " + + response.getStatusCode() + " (" + response.getStatusText() + "); invoking error handler"); } catch (IOException e) { // ignore @@ -554,7 +573,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat if (responseType != null) { Class responseClass = null; if (responseType instanceof Class) { - responseClass = (Class) responseType; + responseClass = (Class) responseType; } List allSupportedMediaTypes = new ArrayList(); @@ -566,7 +585,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } else if (converter instanceof GenericHttpMessageConverter) { - GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; + GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; if (genericConverter.canRead(responseType, null, null)) { allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); } @@ -604,7 +623,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat */ private class HttpEntityRequestCallback extends AcceptHeaderRequestCallback { - private final HttpEntity requestEntity; + private final HttpEntity requestEntity; private HttpEntityRequestCallback(Object requestBody) { this(requestBody, null); @@ -614,10 +633,10 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat private HttpEntityRequestCallback(Object requestBody, Type responseType) { super(responseType); if (requestBody instanceof HttpEntity) { - this.requestEntity = (HttpEntity) requestBody; + this.requestEntity = (HttpEntity) requestBody; } else if (requestBody != null) { - this.requestEntity = new HttpEntity(requestBody); + this.requestEntity = new HttpEntity(requestBody); } else { this.requestEntity = HttpEntity.EMPTY; @@ -643,7 +662,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat Class requestType = requestBody.getClass(); HttpHeaders requestHeaders = requestEntity.getHeaders(); MediaType requestContentType = requestHeaders.getContentType(); - for (HttpMessageConverter messageConverter : getMessageConverters()) { + for (HttpMessageConverter messageConverter : getMessageConverters()) { if (messageConverter.canWrite(requestType, requestContentType)) { if (!requestHeaders.isEmpty()) { httpRequest.getHeaders().putAll(requestHeaders); @@ -658,7 +677,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat } } - messageConverter.write(requestBody, requestContentType, httpRequest); + ((HttpMessageConverter) messageConverter).write( + requestBody, requestContentType, httpRequest); return; } } @@ -683,7 +703,8 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public ResponseEntityResponseExtractor(Type responseType) { if (responseType != null && !Void.class.equals(responseType)) { this.delegate = new HttpMessageConverterExtractor(responseType, getMessageConverters(), logger); - } else { + } + else { this.delegate = null; } } 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 fcfc3407704..63215051978 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -68,9 +68,9 @@ public class RestTemplateTests { response = mock(ClientHttpResponse.class); errorHandler = mock(ResponseErrorHandler.class); converter = mock(HttpMessageConverter.class); - template = new RestTemplate(requestFactory); + template = new RestTemplate(Collections.>singletonList(converter)); + template.setRequestFactory(requestFactory); template.setErrorHandler(errorHandler); - template.setMessageConverters(Collections.>singletonList(converter)); } @Test