diff --git a/org.springframework.web/src/main/java/org/springframework/web/client/RestOperations.java b/org.springframework.web/src/main/java/org/springframework/web/client/RestOperations.java index a5d14bd9f5a..001bb1adfe9 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/client/RestOperations.java +++ b/org.springframework.web/src/main/java/org/springframework/web/client/RestOperations.java @@ -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. *

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 getForObject(String uri, Class responseType, String... uriVariables) throws RestClientException; + T getForObject(String url, Class 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. *

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 getForObject(String uri, Class responseType, Map uriVariables) throws RestClientException; - + T getForObject(String url, Class responseType, Map uriVariables) throws RestClientException; // HEAD /** - * Retrieve all headers of the resource specified by the URI template. - *

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.

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. - *

URI Template variables are expanded using the given map. - * @param uri the URI + * Retrieve all headers of the resource specified by the URI template.

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 uriVariables) throws RestClientException; - + HttpHeaders headForHeaders(String url, Map uriVariables) throws RestClientException; // POST /** - * Create a new resource by POSTing the given object to the URI template. The value of the Location - * header, indicating where the new resource is stored, is returned. - *

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 + * Location header. This header typically indicates where the new resource is stored.

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 null * @return the value for the Location 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 Location header, - * indicating where the new resource is stored, is returned. - *

URI Template variables are expanded using the given map. - * @param uri the URI - * @param request the Object to be POSTed, may be null + * Create a new resource by POSTing the given object to the URI template, and returns the value of the + * Location header. This header typically indicates where the new resource is stored.

URI Template + * variables are expanded using the given map. + * + * @param url the URL + * @param request the Object to be POSTed, may be null * @param uriVariables the variables to expand the template * @return the value for the Location header */ - URI postForLocation(String uri, Object request, Map uriVariables) throws RestClientException; + URI postForLocation(String url, Object request, Map 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.

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 null + * @return the converted object + */ + T postForObject(String url, Object request, Class 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.

URI Template variables are expanded using the given map. + * + * @param url the URL + * @param request the Object to be POSTed, may be null + * @return the converted object + */ + T postForObject(String url, Object request, Class responseType, Map uriVariables) + throws RestClientException; // PUT /** - * Create or update a resource by PUTting the given object to the URI. - *

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 null + * Create or update a resource by PUTting the given object to the URI.

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 null * @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. - *

URI Template variables are expanded using the given map. - * @param uri the URI - * @param request the Object to be PUT, may be null + * Creates a new resource by PUTting the given object to URI template.

URI Template variables are expanded using the + * given map. + * + * @param url the URL + * @param request the Object to be PUT, may be null * @param uriVariables the variables to expand the template */ - void put(String uri, Object request, Map uriVariables) throws RestClientException; - + void put(String url, Object request, Map uriVariables) throws RestClientException; // DELETE /** - * Delete the resources at the specified URI. - *

URI Template variables are expanded using the given URI variables, if any. - * @param uri the URI + * Delete the resources at the specified URI.

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. - *

URI Template variables are expanded using the given map. - * @param uri the URI + * Delete the resources at the specified URI.

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 uriVariables) throws RestClientException; - + void delete(String url, Map uriVariables) throws RestClientException; // OPTIONS /** - * Return the value of the Allow header for the given URI. - *

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.

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 optionsForAllow(String uri, String... uriVariables) throws RestClientException; + Set optionsForAllow(String url, String... uriVariables) throws RestClientException; /** - * Return the value of the Allow header for the given URI. - *

URI Template variables are expanded using the given map. - * @param uri the URI + * Return the value of the Allow header for the given URI.

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 optionsForAllow(String uri, Map uriVariables) throws RestClientException; - + Set optionsForAllow(String url, Map 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}. - *

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}.

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 execute(String uri, + T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor 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}. - *

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}.

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 execute(String uri, + T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, diff --git a/org.springframework.web/src/main/java/org/springframework/web/client/RestTemplate.java b/org.springframework.web/src/main/java/org/springframework/web/client/RestTemplate.java index 8345b48d87c..33d38a6d09c 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/org.springframework.web/src/main/java/org/springframework/web/client/RestTemplate.java @@ -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. * - *

The main entry points of this template are the methods named after the six main HTTP methods: - * - * - * - * - * - * - * - * - * - *
HTTP methodRestTemplate methods
DELETE{@link #delete}
GET{@link #getForObject}
HEAD{@link #headForHeaders}
OPTIONS{@link #optionsForAllow}
POST{@link #postForLocation}
PUT{@link #put}
any{@link #execute}
+ *

The main entry points of this template are the methods named after the six main HTTP methods: + * + * + *
HTTP + * methodRestTemplate methods
DELETE{@link #delete}
GET{@link #getForObject}
HEAD{@link #headForHeaders}
OPTIONS{@link #optionsForAllow}
POST{@link #postForLocation}
PUT{@link #put}
any{@link #execute}
* *

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}. 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");
+ * 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: + * 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);
@@ -78,9 +73,9 @@ import org.springframework.web.util.UriTemplate;
  * bean property.
  *
  * 

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> supportedMessageConverters = getSupportedMessageConverters(responseType); - return execute(url, HttpMethod.GET, new GetCallback(supportedMessageConverters), + return execute(url, HttpMethod.GET, new AcceptHeaderRequestCallback(supportedMessageConverters), new HttpMessageConverterExtractor(responseType, supportedMessageConverters), urlVariables); } @@ -176,7 +168,7 @@ public class RestTemplate extends HttpAccessor implements RestOperations { checkForSupportedMessageConverter(responseType); List> supportedMessageConverters = getSupportedMessageConverters(responseType); - return execute(url, HttpMethod.GET, new GetCallback(supportedMessageConverters), + return execute(url, HttpMethod.GET, new AcceptHeaderRequestCallback(supportedMessageConverters), new HttpMessageConverterExtractor(responseType, supportedMessageConverters), urlVariables); } @@ -211,6 +203,28 @@ public class RestTemplate extends HttpAccessor implements RestOperations { return headers.getLocation(); } + public T postForObject(String url, Object request, Class responseType, String... uriVariables) + throws RestClientException { + if (request != null) { + checkForSupportedMessageConverter(request.getClass()); + } + checkForSupportedMessageConverter(responseType); + List> responseMessageConverters = getSupportedMessageConverters(responseType); + return execute(url, HttpMethod.POST, new PostPutCallback(request, responseMessageConverters), + new HttpMessageConverterExtractor(responseType, responseMessageConverters), uriVariables); + } + + public T postForObject(String url, Object request, Class responseType, Map uriVariables) + throws RestClientException { + if (request != null) { + checkForSupportedMessageConverter(request.getClass()); + } + checkForSupportedMessageConverter(responseType); + List> responseMessageConverters = getSupportedMessageConverters(responseType); + return execute(url, HttpMethod.POST, new PostPutCallback(request, responseMessageConverters), + new HttpMessageConverterExtractor(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 implements RequestCallback { + private class AcceptHeaderRequestCallback implements RequestCallback { private final List> messageConverters; - private GetCallback(List> messageConverters) { + private AcceptHeaderRequestCallback(List> 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 extends AcceptHeaderRequestCallback { private final Object request; - private PostPutCallback(Object request) { + private PostPutCallback(Object request, List> responseMessageConverters) { + super(responseMessageConverters); this.request = request; } + private PostPutCallback(Object request) { + super(Collections.>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); diff --git a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java index 89f14f52e3c..b4817898739 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java @@ -42,24 +42,26 @@ import org.springframework.http.HttpMethod; import org.springframework.http.client.CommonsClientHttpRequestFactory; import org.springframework.util.FileCopyUtils; -/** - * @author Arjen Poutsma - */ +/** @author Arjen Poutsma */ public class RestTemplateIntegrationTests { private RestTemplate template; private static Server jettyServer; + private static String helloWorld = "H\u00e9llo W\u00f6rld"; + @BeforeClass public static void startJettyServer() throws Exception { jettyServer = new Server(8889); Context jettyContext = new Context(jettyServer, "/"); - String s = "H\u00e9llo W\u00f6rld"; - byte[] bytes = s.getBytes("UTF-8"); - jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, "text/plain;charset=utf-8")), "/get"); - jettyContext - .addServlet(new ServletHolder(new PostServlet(s, new URI("http://localhost:8889/post/1"))), "/post"); + byte[] bytes = helloWorld.getBytes("UTF-8"); + String contentType = "text/plain;charset=utf-8"; + jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get"); + jettyContext.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing"); + jettyContext.addServlet( + new ServletHolder(new PostServlet(helloWorld, "http://localhost:8889/post/1", bytes, contentType)), + "/post"); jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound"); jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server"); jettyServer.start(); @@ -67,7 +69,6 @@ public class RestTemplateIntegrationTests { @Before public void createTemplate() { -// template = new RestTemplate(); template = new RestTemplate(new CommonsClientHttpRequestFactory()); } @@ -81,15 +82,27 @@ public class RestTemplateIntegrationTests { @Test public void getString() { String s = template.getForObject("http://localhost:8889/{method}", String.class, "get"); - assertEquals("Invalid content", "H\u00e9llo W\u00f6rld", s); + assertEquals("Invalid content", helloWorld, s); } @Test - public void postString() throws URISyntaxException { - URI location = template.postForLocation("http://localhost:8889/{method}", "H\u00e9llo W\u00f6rld", "post"); + public void getNoResponse() { + String s = template.getForObject("http://localhost:8889/get/nothing", String.class); + assertEquals("Invalid content", "", s); + } + + @Test + public void postForLocation() throws URISyntaxException { + URI location = template.postForLocation("http://localhost:8889/{method}", helloWorld, "post"); assertEquals("Invalid location", new URI("http://localhost:8889/post/1"), location); } + @Test + public void postForObject() throws URISyntaxException { + String s = template.postForObject("http://localhost:8889/{method}", helloWorld, String.class, "post"); + assertEquals("Invalid content", helloWorld, s); + } + @Test(expected = HttpClientErrorException.class) public void notFound() { template.execute("http://localhost:8889/errors/notfound", HttpMethod.GET, null, null); @@ -107,10 +120,7 @@ public class RestTemplateIntegrationTests { EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed); } - - /** - * Servlet that returns and error message for a given status code. - */ + /** Servlet that returns and error message for a given status code. */ private static class ErrorServlet extends GenericServlet { private final int sc; @@ -125,7 +135,6 @@ public class RestTemplateIntegrationTests { } } - private static class GetServlet extends HttpServlet { private final byte[] buf; @@ -140,22 +149,27 @@ public class RestTemplateIntegrationTests { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - response.setContentLength(buf.length); response.setContentType(contentType); + response.setContentLength(buf.length); FileCopyUtils.copy(buf, response.getOutputStream()); } } - private static class PostServlet extends HttpServlet { private final String s; - private final URI location; + private final String location; - private PostServlet(String s, URI location) { + private final byte[] buf; + + private final String contentType; + + private PostServlet(String s, String location, byte[] buf, String contentType) { this.s = s; this.location = location; + this.buf = buf; + this.contentType = contentType; } @Override @@ -166,7 +180,10 @@ public class RestTemplateIntegrationTests { String body = FileCopyUtils.copyToString(request.getReader()); assertEquals("Invalid request body", s, body); response.setStatus(HttpServletResponse.SC_CREATED); - response.setHeader("Location", location.toASCIIString()); + response.setHeader("Location", location); + response.setContentLength(buf.length); + response.setContentType(contentType); + FileCopyUtils.copy(buf, response.getOutputStream()); } } diff --git a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateTests.java b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateTests.java index 68b034cd330..4aa0ee0595f 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateTests.java @@ -40,9 +40,7 @@ import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; -/** - * @author Arjen Poutsma - */ +/** @author Arjen Poutsma */ @SuppressWarnings("unchecked") public class RestTemplateTests { @@ -265,7 +263,7 @@ public class RestTemplateTests { } @Test - public void postNull() throws Exception { + public void postForLocationNull() throws Exception { expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request); HttpHeaders requestHeaders = new HttpHeaders(); expect(request.getHeaders()).andReturn(requestHeaders); @@ -282,6 +280,58 @@ public class RestTemplateTests { verifyMocks(); } + @Test + public void postForObject() throws Exception { + expect(converter.supports(String.class)).andReturn(true).times(2); + expect(converter.supports(Integer.class)).andReturn(true).times(2); + MediaType textPlain = new MediaType("text", "plain"); + expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(textPlain)).times(2); + expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(this.request); + HttpHeaders requestHeaders = new HttpHeaders(); + expect(this.request.getHeaders()).andReturn(requestHeaders); + String request = "Hello World"; + converter.write(request, this.request); + expect(this.request.execute()).andReturn(response); + expect(errorHandler.hasError(response)).andReturn(false); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentType(textPlain); + expect(response.getHeaders()).andReturn(responseHeaders); + Integer expected = 42; + expect(converter.read(Integer.class, response)).andReturn(expected); + response.close(); + + replayMocks(); + + Integer result = template.postForObject("http://example.com", request, Integer.class); + assertEquals("Invalid POST result", expected, result); + assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); + + verifyMocks(); + } + + @Test + public void postForObjectNull() throws Exception { + expect(converter.supports(Integer.class)).andReturn(true).times(2); + MediaType textPlain = new MediaType("text", "plain"); + expect(converter.getSupportedMediaTypes()).andReturn(Collections.singletonList(textPlain)).times(2); + expect(requestFactory.createRequest(new URI("http://example.com"), HttpMethod.POST)).andReturn(request); + HttpHeaders requestHeaders = new HttpHeaders(); + expect(request.getHeaders()).andReturn(requestHeaders).times(2); + expect(request.execute()).andReturn(response); + expect(errorHandler.hasError(response)).andReturn(false); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentType(textPlain); + expect(response.getHeaders()).andReturn(responseHeaders); + expect(converter.read(Integer.class, response)).andReturn(null); + response.close(); + + replayMocks(); + template.postForObject("http://example.com", null, Integer.class); + assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); + + verifyMocks(); + } + @Test public void put() throws Exception { expect(converter.supports(String.class)).andReturn(true).times(2);