From 69e3fde295d4c04e3b5de9d0c7d747f021cbd9aa Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 12 Apr 2018 21:56:44 +0200 Subject: [PATCH] Avoid duplicate Accept header values in RestTemplate Prior to this commit, the various `HttpMessageConverter` instances configured for a given `RestTemplate` instance could all contribute `MediaType` values to the "Accept:" request header. This could lead to duplicate media types in that request header, cluttering for the HTTP request for no reason. This commit ensures that only distinct values are added to the request. Issue: SPR-16690 --- .../web/client/RestTemplate.java | 68 +- .../web/client/RestTemplateTests.java | 587 +++++++----------- 2 files changed, 250 insertions(+), 405 deletions(-) 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 18b41589a6..abaa231784 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 @@ -25,6 +25,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; @@ -836,45 +838,43 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat @Override public void doWithRequest(ClientHttpRequest request) throws IOException { if (this.responseType != null) { - Class responseClass = null; - if (this.responseType instanceof Class) { - responseClass = (Class) this.responseType; - } - List allSupportedMediaTypes = new ArrayList<>(); - for (HttpMessageConverter converter : getMessageConverters()) { - if (responseClass != null) { - if (converter.canRead(responseClass, null)) { - allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); - } - } - else if (converter instanceof GenericHttpMessageConverter) { - GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; - if (genericConverter.canRead(this.responseType, null, null)) { - allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter)); - } - } - } - if (!allSupportedMediaTypes.isEmpty()) { - MediaType.sortBySpecificity(allSupportedMediaTypes); - if (logger.isDebugEnabled()) { - logger.debug("Setting request Accept header to " + allSupportedMediaTypes); - } - request.getHeaders().setAccept(allSupportedMediaTypes); + final Class responseClass = (this.responseType instanceof Class) ? + (Class) this.responseType : null; + final List allSupportedMediaTypes = getMessageConverters().stream() + .filter(converter -> canReadResponse(responseClass, converter)) + .flatMap(this::getSupportedMediaTypes) + .distinct() + .sorted(MediaType.SPECIFICITY_COMPARATOR) + .collect(Collectors.toList()); + if (logger.isDebugEnabled()) { + logger.debug("Setting request Accept header to " + allSupportedMediaTypes); } + request.getHeaders().setAccept(allSupportedMediaTypes); } } - private List getSupportedMediaTypes(HttpMessageConverter messageConverter) { - List supportedMediaTypes = messageConverter.getSupportedMediaTypes(); - List result = new ArrayList<>(supportedMediaTypes.size()); - for (MediaType supportedMediaType : supportedMediaTypes) { - if (supportedMediaType.getCharset() != null) { - supportedMediaType = - new MediaType(supportedMediaType.getType(), supportedMediaType.getSubtype()); - } - result.add(supportedMediaType); + private boolean canReadResponse(@Nullable Class responseClass, HttpMessageConverter converter) { + if (responseClass != null) { + return converter.canRead(responseClass, null); } - return result; + else if (converter instanceof GenericHttpMessageConverter) { + GenericHttpMessageConverter genericConverter = + (GenericHttpMessageConverter) converter; + return genericConverter + .canRead(this.responseType, null, null); + } + return false; + } + + private Stream getSupportedMediaTypes(HttpMessageConverter messageConverter) { + return messageConverter.getSupportedMediaTypes() + .stream() + .map(mediaType -> { + if (mediaType.getCharset() != null) { + return new MediaType(mediaType.getType(), mediaType.getSubtype()); + } + return mediaType; + }); } } 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 d425502c4f..d5ced4203f 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 @@ -19,6 +19,7 @@ package org.springframework.web.client; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -48,14 +49,30 @@ import org.springframework.web.util.DefaultUriBuilderFactory; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.*; -import static org.mockito.BDDMockito.*; -import static org.springframework.http.HttpMethod.*; -import static org.springframework.http.MediaType.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.mock; +import static org.mockito.BDDMockito.verify; +import static org.mockito.BDDMockito.willThrow; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.HEAD; +import static org.springframework.http.HttpMethod.OPTIONS; +import static org.springframework.http.HttpMethod.PATCH; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.MediaType.parseMediaType; /** * @author Arjen Poutsma * @author Rossen Stoyanchev + * @author Brian Clozel */ @SuppressWarnings("unchecked") public class RestTemplateTests { @@ -89,29 +106,19 @@ public class RestTemplateTests { @Test public void varArgsTemplateVariables() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/21"), GET)) - .willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(GET, "http://example.com/hotels/42/bookings/21"); + mockResponseStatus(HttpStatus.OK); - template.execute("http://example.com/hotels/{hotel}/bookings/{booking}", GET, null, null, "42", - "21"); + template.execute("http://example.com/hotels/{hotel}/bookings/{booking}", GET, + null, null, "42", "21"); verify(response).close(); } @Test public void varArgsNullTemplateVariable() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com/-foo"), GET)) - .willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(GET, "http://example.com/-foo"); + mockResponseStatus(HttpStatus.OK); template.execute("http://example.com/{first}-{last}", GET, null, null, null, "foo"); @@ -120,13 +127,8 @@ public class RestTemplateTests { @Test public void mapTemplateVariables() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com/hotels/42/bookings/42"), GET)) - .willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(GET, "http://example.com/hotels/42/bookings/42"); + mockResponseStatus(HttpStatus.OK); Map vars = Collections.singletonMap("hotel", "42"); template.execute("http://example.com/hotels/{hotel}/bookings/{hotel}", GET, null, null, vars); @@ -136,13 +138,8 @@ public class RestTemplateTests { @Test public void mapNullTemplateVariable() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com/-foo"), GET)) - .willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(GET, "http://example.com/-foo"); + mockResponseStatus(HttpStatus.OK); Map vars = new HashMap<>(2); vars.put("first", null); @@ -155,12 +152,8 @@ public class RestTemplateTests { @Test // SPR-15201 public void uriTemplateWithTrailingSlash() throws Exception { String url = "http://example.com/spring/"; - given(requestFactory.createRequest(new URI(url), GET)).willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(GET, url); + mockResponseStatus(HttpStatus.OK); template.execute(url, GET, null, null); @@ -169,17 +162,14 @@ public class RestTemplateTests { @Test public void errorHandling() throws Exception { - URI uri = new URI("http://example.com"); - given(requestFactory.createRequest(uri, GET)).willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(true); - given(response.getStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR); - given(response.getStatusText()).willReturn("Internal Server Error"); + String url = "http://example.com"; + mockSentRequest(GET, url); + mockResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR); willThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR)) - .given(errorHandler).handleError(uri, GET, response); + .given(errorHandler).handleError(new URI(url), GET, response); try { - template.execute("http://example.com", GET, null, null); + template.execute(url, GET, null, null); fail("HttpServerErrorException expected"); } catch (HttpServerErrorException ex) { @@ -191,55 +181,33 @@ public class RestTemplateTests { @Test public void getForObject() throws Exception { - given(converter.canRead(String.class, null)).willReturn(true); - MediaType textPlain = new MediaType("text", "plain"); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), GET)).willReturn(request); - HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); String expected = "Hello World"; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); - responseHeaders.setContentLength(10); - given(response.getStatusCode()).willReturn(HttpStatus.OK); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes())); - given(converter.canRead(String.class, textPlain)).willReturn(true); - given(converter.read(eq(String.class), any(HttpInputMessage.class))).willReturn(expected); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockTextPlainHttpMessageConverter(); + HttpHeaders requestHeaders = new HttpHeaders(); + mockSentRequest(GET, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); + mockTextResponseBody("Hello World"); String result = template.getForObject("http://example.com", String.class); assertEquals("Invalid GET result", expected, result); - assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); + assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, + requestHeaders.getFirst("Accept")); verify(response).close(); } @Test public void getUnsupportedMediaType() throws Exception { + mockSentRequest(GET, "http://example.com/resource"); + mockResponseStatus(HttpStatus.OK); + given(converter.canRead(String.class, null)).willReturn(true); MediaType supportedMediaType = new MediaType("foo", "bar"); given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(supportedMediaType)); - given(requestFactory.createRequest(new URI("http://example.com/resource"), GET)).willReturn(request); - HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpHeaders responseHeaders = new HttpHeaders(); - MediaType contentType = new MediaType("bar", "baz"); - responseHeaders.setContentType(contentType); - responseHeaders.setContentLength(10); - given(response.getStatusCode()).willReturn(HttpStatus.OK); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream("Foo".getBytes())); - given(converter.canRead(String.class, contentType)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + + MediaType barBaz = new MediaType("bar", "baz"); + mockResponseBody("Foo", new MediaType("bar", "baz")); + given(converter.canRead(String.class, barBaz)).willReturn(false); try { template.getForObject("http://example.com/{p}", String.class, "resource"); @@ -252,32 +220,42 @@ public class RestTemplateTests { verify(response).close(); } + @Test + public void requestAvoidsDuplicateAcceptHeaderValues() throws Exception { + HttpMessageConverter firstConverter = mock(HttpMessageConverter.class); + given(firstConverter.canRead(any(), any())).willReturn(true); + given(firstConverter.getSupportedMediaTypes()) + .willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); + HttpMessageConverter secondConverter = mock(HttpMessageConverter.class); + given(secondConverter.canRead(any(), any())).willReturn(true); + given(secondConverter.getSupportedMediaTypes()) + .willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); + + HttpHeaders requestHeaders = new HttpHeaders(); + mockSentRequest(GET, "http://example.com/", requestHeaders); + mockResponseStatus(HttpStatus.OK); + mockTextResponseBody("Hello World"); + + template.setMessageConverters(Arrays.asList(firstConverter, secondConverter)); + template.getForObject("http://example.com/", String.class); + + assertEquals("Sent duplicate Accept header values", 1, + requestHeaders.getAccept().size()); + } @Test public void getForEntity() throws Exception { - given(converter.canRead(String.class, null)).willReturn(true); - MediaType textPlain = new MediaType("text", "plain"); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), GET)).willReturn(request); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(GET, "http://example.com", requestHeaders); + mockTextPlainHttpMessageConverter(); + mockResponseStatus(HttpStatus.OK); String expected = "Hello World"; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); - responseHeaders.setContentLength(10); - given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); - given(response.getStatusText()).willReturn(HttpStatus.OK.getReasonPhrase()); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.getBytes())); - given(converter.canRead(String.class, textPlain)).willReturn(true); - given(converter.read(eq(String.class), any(HttpInputMessage.class))).willReturn(expected); + mockTextResponseBody(expected); ResponseEntity result = template.getForEntity("http://example.com", String.class); assertEquals("Invalid GET result", expected, result.getBody()); - assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); - assertEquals("Invalid Content-Type header", textPlain, result.getHeaders().getContentType()); + assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); + assertEquals("Invalid Content-Type header", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode()); verify(response).close(); @@ -287,15 +265,8 @@ public class RestTemplateTests { public void getForObjectWithCustomUriTemplateHandler() throws Exception { DefaultUriBuilderFactory uriTemplateHandler = new DefaultUriBuilderFactory(); template.setUriTemplateHandler(uriTemplateHandler); - - URI expectedUri = new URI("http://example.com/hotels/1/pic/pics%2Flogo.png/size/150x150"); - given(requestFactory.createRequest(expectedUri, GET)).willReturn(request); - - given(request.getHeaders()).willReturn(new HttpHeaders()); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - - given(response.getStatusCode()).willReturn(HttpStatus.OK); + mockSentRequest(GET, "http://example.com/hotels/1/pic/pics%2Flogo.png/size/150x150"); + mockResponseStatus(HttpStatus.OK); given(response.getHeaders()).willReturn(new HttpHeaders()); given(response.getBody()).willReturn(StreamUtils.emptyInput()); @@ -312,14 +283,10 @@ public class RestTemplateTests { @Test public void headForHeaders() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), HEAD)).willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(HEAD, "http://example.com"); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); HttpHeaders result = template.headForHeaders("http://example.com"); @@ -330,19 +297,14 @@ public class RestTemplateTests { @Test public void postForLocation() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); + mockSentRequest(POST, "http://example.com"); + mockTextPlainHttpMessageConverter(); + mockResponseStatus(HttpStatus.OK); String helloWorld = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); - converter.write(helloWorld, null, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); HttpHeaders responseHeaders = new HttpHeaders(); URI expected = new URI("http://example.com/hotels"); responseHeaders.setLocation(expected); given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); URI result = template.postForLocation("http://example.com", helloWorld); assertEquals("Invalid POST result", expected, result); @@ -352,25 +314,18 @@ public class RestTemplateTests { @Test public void postForLocationEntityContentType() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); + mockSentRequest(POST, "http://example.com"); + mockTextPlainHttpMessageConverter(); + mockResponseStatus(HttpStatus.OK); + String helloWorld = "Hello World"; - MediaType contentType = MediaType.TEXT_PLAIN; - given(converter.canWrite(String.class, contentType)).willReturn(true); - HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - converter.write(helloWorld, contentType, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); HttpHeaders responseHeaders = new HttpHeaders(); URI expected = new URI("http://example.com/hotels"); responseHeaders.setLocation(expected); given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); HttpHeaders entityHeaders = new HttpHeaders(); - entityHeaders.setContentType(contentType); + entityHeaders.setContentType(MediaType.TEXT_PLAIN); HttpEntity entity = new HttpEntity<>(helloWorld, entityHeaders); URI result = template.postForLocation("http://example.com", entity); @@ -381,25 +336,18 @@ public class RestTemplateTests { @Test public void postForLocationEntityCustomHeader() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); - String helloWorld = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - converter.write(helloWorld, null, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockTextPlainHttpMessageConverter(); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); URI expected = new URI("http://example.com/hotels"); responseHeaders.setLocation(expected); given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.set("MyHeader", "MyValue"); - HttpEntity entity = new HttpEntity<>(helloWorld, entityHeaders); + HttpEntity entity = new HttpEntity<>("Hello World", entityHeaders); URI result = template.postForLocation("http://example.com", entity); assertEquals("Invalid POST result", expected, result); @@ -410,19 +358,11 @@ public class RestTemplateTests { @Test public void postForLocationNoLocation() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); - String helloWorld = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); - converter.write(helloWorld, null, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpHeaders responseHeaders = new HttpHeaders(); - given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(POST, "http://example.com"); + mockTextPlainHttpMessageConverter(); + mockResponseStatus(HttpStatus.OK); - URI result = template.postForLocation("http://example.com", helloWorld); + URI result = template.postForLocation("http://example.com", "Hello World"); assertNull("Invalid POST result", result); verify(response).close(); @@ -430,16 +370,9 @@ public class RestTemplateTests { @Test public void postForLocationNull() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpHeaders responseHeaders = new HttpHeaders(); - given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); template.postForLocation("http://example.com", null); assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); @@ -449,65 +382,33 @@ public class RestTemplateTests { @Test public void postForObject() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(this.request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(this.request.getHeaders()).willReturn(requestHeaders); - String request = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); - converter.write(request, null, this.request); - given(this.request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - Integer expected = 42; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); - responseHeaders.setContentLength(10); - given(response.getStatusCode()).willReturn(HttpStatus.OK); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.toString().getBytes())); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(eq(Integer.class), any(HttpInputMessage.class))).willReturn(expected); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); + String expected = "42"; + mockResponseBody(expected, MediaType.TEXT_PLAIN); - Integer result = template.postForObject("http://example.com", request, Integer.class); + String result = template.postForObject("http://example.com", "Hello World", String.class); assertEquals("Invalid POST result", expected, result); - assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); + assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); verify(response).close(); } @Test public void postForEntity() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(this.request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(this.request.getHeaders()).willReturn(requestHeaders); - String request = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); - converter.write(request, null, this.request); - given(this.request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - Integer expected = 42; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); - responseHeaders.setContentLength(10); - given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); - given(response.getStatusText()).willReturn(HttpStatus.OK.getReasonPhrase()); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.toString().getBytes())); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(eq(Integer.class), any(HttpInputMessage.class))).willReturn(expected); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); + String expected = "42"; + mockResponseBody(expected, MediaType.TEXT_PLAIN); - ResponseEntity result = template.postForEntity("http://example.com", request, Integer.class); + ResponseEntity result = template.postForEntity("http://example.com", "Hello World", String.class); assertEquals("Invalid POST result", expected, result.getBody()); - assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType()); - assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); + assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); + assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode()); verify(response).close(); @@ -515,27 +416,18 @@ public class RestTemplateTests { @Test public void postForObjectNull() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); + responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); given(response.getHeaders()).willReturn(responseHeaders); - given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getBody()).willReturn(StreamUtils.emptyInput()); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(Integer.class, response)).willReturn(null); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + given(converter.read(String.class, response)).willReturn(null); - Integer result = template.postForObject("http://example.com", null, Integer.class); + String result = template.postForObject("http://example.com", null, String.class); assertNull("Invalid POST result", result); assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); @@ -544,27 +436,20 @@ public class RestTemplateTests { @Test public void postForEntityNull() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); + responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); given(response.getHeaders()).willReturn(responseHeaders); - given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); - given(response.getStatusText()).willReturn(HttpStatus.OK.getReasonPhrase()); given(response.getBody()).willReturn(StreamUtils.emptyInput()); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(Integer.class, response)).willReturn(null); + given(converter.read(String.class, response)).willReturn(null); - ResponseEntity result = template.postForEntity("http://example.com", null, Integer.class); + ResponseEntity result = template.postForEntity("http://example.com", null, String.class); assertFalse("Invalid POST result", result.hasBody()); - assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType()); + assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode()); @@ -573,31 +458,20 @@ public class RestTemplateTests { @Test public void put() throws Exception { - given(converter.canWrite(String.class, null)).willReturn(true); - given(requestFactory.createRequest(new URI("http://example.com"), PUT)).willReturn(request); - String helloWorld = "Hello World"; - converter.write(helloWorld, null, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockTextPlainHttpMessageConverter(); + mockSentRequest(PUT, "http://example.com"); + mockResponseStatus(HttpStatus.OK); - template.put("http://example.com", helloWorld); + template.put("http://example.com", "Hello World"); verify(response).close(); } @Test public void putNull() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), PUT)).willReturn(request); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(PUT, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); template.put("http://example.com", null); assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); @@ -607,60 +481,33 @@ public class RestTemplateTests { @Test public void patchForObject() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), PATCH)).willReturn(this.request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(this.request.getHeaders()).willReturn(requestHeaders); - String request = "Hello World"; - given(converter.canWrite(String.class, null)).willReturn(true); - converter.write(request, null, this.request); - given(this.request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - Integer expected = 42; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); - responseHeaders.setContentLength(10); - given(response.getStatusCode()).willReturn(HttpStatus.OK); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.toString().getBytes())); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(eq(Integer.class), any(HttpInputMessage.class))).willReturn(expected); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(PATCH, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); + String expected = "42"; + mockResponseBody("42", MediaType.TEXT_PLAIN); - Integer result = template.patchForObject("http://example.com", request, Integer.class); + String result = template.patchForObject("http://example.com", "Hello World", String.class); assertEquals("Invalid POST result", expected, result); - assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); + assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); verify(response).close(); } @Test public void patchForObjectNull() throws Exception { - MediaType textPlain = new MediaType("text", "plain"); - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(textPlain)); - given(requestFactory.createRequest(new URI("http://example.com"), PATCH)).willReturn(request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(PATCH, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(textPlain); + responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); given(response.getHeaders()).willReturn(responseHeaders); - given(response.getStatusCode()).willReturn(HttpStatus.OK); given(response.getBody()).willReturn(StreamUtils.emptyInput()); - given(converter.canRead(Integer.class, textPlain)).willReturn(true); - given(converter.read(Integer.class, response)).willReturn(null); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); - Integer result = template.patchForObject("http://example.com", null, Integer.class); + String result = template.patchForObject("http://example.com", null, String.class); assertNull("Invalid POST result", result); assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); @@ -668,15 +515,10 @@ public class RestTemplateTests { } - @Test public void delete() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), DELETE)).willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(DELETE, "http://example.com"); + mockResponseStatus(HttpStatus.OK); template.delete("http://example.com"); @@ -685,16 +527,12 @@ public class RestTemplateTests { @Test public void optionsForAllow() throws Exception { - given(requestFactory.createRequest(new URI("http://example.com"), OPTIONS)).willReturn(request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + mockSentRequest(OPTIONS, "http://example.com"); + mockResponseStatus(HttpStatus.OK); HttpHeaders responseHeaders = new HttpHeaders(); EnumSet expected = EnumSet.of(GET, POST); responseHeaders.setAllow(expected); given(response.getHeaders()).willReturn(responseHeaders); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); Set result = template.optionsForAllow("http://example.com"); assertEquals("Invalid OPTIONS result", expected, result); @@ -705,12 +543,8 @@ public class RestTemplateTests { @Test // SPR-9325, SPR-13860 public void ioException() throws Exception { String url = "http://example.com/resource?access_token=123"; - - given(converter.canRead(String.class, null)).willReturn(true); - MediaType mediaType = new MediaType("foo", "bar"); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(mediaType)); - given(requestFactory.createRequest(new URI(url), GET)).willReturn(request); - given(request.getHeaders()).willReturn(new HttpHeaders()); + mockSentRequest(GET, url); + mockHttpMessageConverter(new MediaType("foo", "bar"), String.class); given(request.execute()).willThrow(new IOException("Socket failure")); try { @@ -719,7 +553,7 @@ public class RestTemplateTests { } catch (ResourceAccessException ex) { assertEquals("I/O error on GET request for \"http://example.com/resource\": " + - "Socket failure; nested exception is java.io.IOException: Socket failure", + "Socket failure; nested exception is java.io.IOException: Socket failure", ex.getMessage()); } } @@ -749,32 +583,17 @@ public class RestTemplateTests { @Test public void exchange() throws Exception { - given(converter.canRead(Integer.class, null)).willReturn(true); - given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(this.request); + mockTextPlainHttpMessageConverter(); HttpHeaders requestHeaders = new HttpHeaders(); - given(this.request.getHeaders()).willReturn(requestHeaders); - given(converter.canWrite(String.class, null)).willReturn(true); - String body = "Hello World"; - converter.write(body, null, this.request); - given(this.request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - Integer expected = 42; - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentType(MediaType.TEXT_PLAIN); - responseHeaders.setContentLength(10); - given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); - given(response.getStatusText()).willReturn(HttpStatus.OK.getReasonPhrase()); - given(response.getHeaders()).willReturn(responseHeaders); - given(response.getBody()).willReturn(new ByteArrayInputStream(expected.toString().getBytes())); - given(converter.canRead(Integer.class, MediaType.TEXT_PLAIN)).willReturn(true); - given(converter.read(Integer.class, response)).willReturn(expected); - given(converter.read(eq(Integer.class), any(HttpInputMessage.class))).willReturn(expected); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); + String expected = "42"; + mockResponseBody(expected, MediaType.TEXT_PLAIN); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.set("MyHeader", "MyValue"); - HttpEntity entity = new HttpEntity<>(body, entityHeaders); - ResponseEntity result = template.exchange("http://example.com", POST, entity, Integer.class); + HttpEntity entity = new HttpEntity<>("Hello World", entityHeaders); + ResponseEntity result = template.exchange("http://example.com", POST, entity, String.class); assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); assertEquals("Invalid Accept header", MediaType.TEXT_PLAIN_VALUE, requestHeaders.getFirst("Accept")); @@ -789,24 +608,18 @@ public class RestTemplateTests { public void exchangeParameterizedType() throws Exception { GenericHttpMessageConverter converter = mock(GenericHttpMessageConverter.class); template.setMessageConverters(Collections.>singletonList(converter)); - ParameterizedTypeReference> intList = new ParameterizedTypeReference>() {}; given(converter.canRead(intList.getType(), null, null)).willReturn(true); given(converter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(this.request); - HttpHeaders requestHeaders = new HttpHeaders(); - given(this.request.getHeaders()).willReturn(requestHeaders); given(converter.canWrite(String.class, String.class, null)).willReturn(true); - String requestBody = "Hello World"; - converter.write(requestBody, String.class, null, this.request); - given(this.request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); + + HttpHeaders requestHeaders = new HttpHeaders(); + mockSentRequest(POST, "http://example.com", requestHeaders); List expected = Collections.singletonList(42); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentType(MediaType.TEXT_PLAIN); responseHeaders.setContentLength(10); - given(response.getRawStatusCode()).willReturn(HttpStatus.OK.value()); - given(response.getStatusText()).willReturn(HttpStatus.OK.getReasonPhrase()); + mockResponseStatus(HttpStatus.OK); given(response.getHeaders()).willReturn(responseHeaders); given(response.getBody()).willReturn(new ByteArrayInputStream(Integer.toString(42).getBytes())); given(converter.canRead(intList.getType(), null, MediaType.TEXT_PLAIN)).willReturn(true); @@ -814,7 +627,7 @@ public class RestTemplateTests { HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.set("MyHeader", "MyValue"); - HttpEntity requestEntity = new HttpEntity<>(requestBody, entityHeaders); + HttpEntity requestEntity = new HttpEntity<>("Hello World", entityHeaders); ResponseEntity> result = template.exchange("http://example.com", POST, requestEntity, intList); assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid Content-Type", MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); @@ -833,14 +646,9 @@ public class RestTemplateTests { }; template.setInterceptors(Collections.singletonList(interceptor)); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.add("MyHeader", "MyEntityValue"); @@ -861,25 +669,62 @@ public class RestTemplateTests { MediaType contentType = MediaType.TEXT_PLAIN; given(converter.canWrite(String.class, contentType)).willReturn(true); - given(requestFactory.createRequest(new URI("http://example.com"), POST)).willReturn(request); - String helloWorld = "Hello World"; HttpHeaders requestHeaders = new HttpHeaders(); - given(request.getHeaders()).willReturn(requestHeaders); - converter.write(helloWorld, contentType, request); - given(request.execute()).willReturn(response); - given(errorHandler.hasError(response)).willReturn(false); - HttpStatus status = HttpStatus.OK; - given(response.getStatusCode()).willReturn(status); - given(response.getStatusText()).willReturn(status.getReasonPhrase()); + mockSentRequest(POST, "http://example.com", requestHeaders); + mockResponseStatus(HttpStatus.OK); HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.setContentType(contentType); entityHeaders.add("MyHeader", "MyEntityValue"); - HttpEntity entity = new HttpEntity<>(helloWorld, entityHeaders); + HttpEntity entity = new HttpEntity<>("Hello World", entityHeaders); template.exchange("http://example.com", POST, entity, Void.class); assertThat(requestHeaders.get("MyHeader"), contains("MyEntityValue", "MyInterceptorValue")); verify(response).close(); } + private void mockSentRequest(HttpMethod method, String uri) throws Exception { + mockSentRequest(method, uri, new HttpHeaders()); + } + + private void mockSentRequest(HttpMethod method, String uri, HttpHeaders requestHeaders) throws Exception { + given(requestFactory.createRequest(new URI(uri), method)).willReturn(request); + given(request.getHeaders()).willReturn(requestHeaders); + } + + private void mockResponseStatus(HttpStatus responseStatus) throws Exception { + given(request.execute()).willReturn(response); + given(errorHandler.hasError(response)).willReturn(responseStatus.isError()); + given(response.getStatusCode()).willReturn(responseStatus); + given(response.getRawStatusCode()).willReturn(responseStatus.value()); + given(response.getStatusText()).willReturn(responseStatus.getReasonPhrase()); + } + + private void mockTextPlainHttpMessageConverter() { + mockHttpMessageConverter(MediaType.TEXT_PLAIN, String.class); + } + + private void mockHttpMessageConverter(MediaType mediaType, Class type) { + given(converter.canRead(type, null)).willReturn(true); + given(converter.canRead(type, mediaType)).willReturn(true); + given(converter.getSupportedMediaTypes()) + .willReturn(Collections.singletonList(mediaType)); + given(converter.canRead(type, mediaType)).willReturn(true); + given(converter.canWrite(type, null)).willReturn(true); + given(converter.canWrite(type, mediaType)).willReturn(true); + } + + private void mockTextResponseBody(String expectedBody) throws Exception { + mockResponseBody(expectedBody, MediaType.TEXT_PLAIN); + } + + private void mockResponseBody(String expectedBody, MediaType mediaType) throws Exception { + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentType(mediaType); + responseHeaders.setContentLength(expectedBody.length()); + given(response.getHeaders()).willReturn(responseHeaders); + given(response.getBody()).willReturn(new ByteArrayInputStream(expectedBody.getBytes())); + given(converter.read(eq(String.class), any(HttpInputMessage.class))).willReturn(expectedBody); + } + }