/* * Copyright 2002-2017 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.client; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Set; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonView; import org.hamcrest.Matchers; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.Netty4ClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import static org.junit.Assert.*; /** * @author Arjen Poutsma * @author Brian Clozel */ @RunWith(Parameterized.class) public class RestTemplateIntegrationTests extends AbstractMockWebServerTestCase { private RestTemplate template; @Parameter public ClientHttpRequestFactory clientHttpRequestFactory; @SuppressWarnings("deprecation") @Parameters public static Iterable<? extends ClientHttpRequestFactory> data() { return Arrays.asList( new SimpleClientHttpRequestFactory(), new HttpComponentsClientHttpRequestFactory(), new Netty4ClientHttpRequestFactory(), new OkHttp3ClientHttpRequestFactory() ); } @Before public void setupClient() { this.template = new RestTemplate(this.clientHttpRequestFactory); } @Test public void getString() { String s = template.getForObject(baseUrl + "/{method}", String.class, "get"); assertEquals("Invalid content", helloWorld, s); } @Test public void getEntity() { ResponseEntity<String> entity = template.getForEntity(baseUrl + "/{method}", String.class, "get"); assertEquals("Invalid content", helloWorld, entity.getBody()); assertFalse("No headers", entity.getHeaders().isEmpty()); assertEquals("Invalid content-type", textContentType, entity.getHeaders().getContentType()); assertEquals("Invalid status code", HttpStatus.OK, entity.getStatusCode()); } @Test public void getNoResponse() { String s = template.getForObject(baseUrl + "/get/nothing", String.class); assertNull("Invalid content", s); } @Test public void getNoContentTypeHeader() throws UnsupportedEncodingException { byte[] bytes = template.getForObject(baseUrl + "/get/nocontenttype", byte[].class); assertArrayEquals("Invalid content", helloWorld.getBytes("UTF-8"), bytes); } @Test public void getNoContent() { String s = template.getForObject(baseUrl + "/status/nocontent", String.class); assertNull("Invalid content", s); ResponseEntity<String> entity = template.getForEntity(baseUrl + "/status/nocontent", String.class); assertEquals("Invalid response code", HttpStatus.NO_CONTENT, entity.getStatusCode()); assertNull("Invalid content", entity.getBody()); } @Test public void getNotModified() { String s = template.getForObject(baseUrl + "/status/notmodified", String.class); assertNull("Invalid content", s); ResponseEntity<String> entity = template.getForEntity(baseUrl + "/status/notmodified", String.class); assertEquals("Invalid response code", HttpStatus.NOT_MODIFIED, entity.getStatusCode()); assertNull("Invalid content", entity.getBody()); } @Test public void postForLocation() throws URISyntaxException { URI location = template.postForLocation(baseUrl + "/{method}", helloWorld, "post"); assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location); } @Test public void postForLocationEntity() throws URISyntaxException { HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.setContentType(new MediaType("text", "plain", StandardCharsets.ISO_8859_1)); HttpEntity<String> entity = new HttpEntity<>(helloWorld, entityHeaders); URI location = template.postForLocation(baseUrl + "/{method}", entity, "post"); assertEquals("Invalid location", new URI(baseUrl + "/post/1"), location); } @Test public void postForObject() throws URISyntaxException { String s = template.postForObject(baseUrl + "/{method}", helloWorld, String.class, "post"); assertEquals("Invalid content", helloWorld, s); } @Test public void patchForObject() throws URISyntaxException { // JDK client does not support the PATCH method Assume.assumeThat(this.clientHttpRequestFactory, Matchers.not(Matchers.instanceOf(SimpleClientHttpRequestFactory.class))); String s = template.patchForObject(baseUrl + "/{method}", helloWorld, String.class, "patch"); assertEquals("Invalid content", helloWorld, s); } @Test public void notFound() { try { template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null); fail("HttpClientErrorException expected"); } catch (HttpClientErrorException ex) { assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode()); assertNotNull(ex.getStatusText()); assertNotNull(ex.getResponseBodyAsString()); } } @Test public void serverError() { try { template.execute(baseUrl + "/status/server", HttpMethod.GET, null, null); fail("HttpServerErrorException expected"); } catch (HttpServerErrorException ex) { assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatusCode()); assertNotNull(ex.getStatusText()); assertNotNull(ex.getResponseBodyAsString()); } } @Test public void optionsForAllow() throws URISyntaxException { Set<HttpMethod> allowed = template.optionsForAllow(new URI(baseUrl + "/get")); assertEquals("Invalid response", EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS, HttpMethod.HEAD, HttpMethod.TRACE), allowed); } @Test public void uri() throws InterruptedException, URISyntaxException { String result = template.getForObject(baseUrl + "/uri/{query}", String.class, "Z\u00fcrich"); assertEquals("Invalid request URI", "/uri/Z%C3%BCrich", result); result = template.getForObject(baseUrl + "/uri/query={query}", String.class, "foo@bar"); assertEquals("Invalid request URI", "/uri/query=foo@bar", result); result = template.getForObject(baseUrl + "/uri/query={query}", String.class, "T\u014dky\u014d"); assertEquals("Invalid request URI", "/uri/query=T%C5%8Dky%C5%8D", result); } @Test public void multipart() throws UnsupportedEncodingException { MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>(); parts.add("name 1", "value 1"); parts.add("name 2", "value 2+1"); parts.add("name 2", "value 2+2"); Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg"); parts.add("logo", logo); template.postForLocation(baseUrl + "/multipart", parts); } @Test public void form() throws UnsupportedEncodingException { MultiValueMap<String, String> form = new LinkedMultiValueMap<>(); form.add("name 1", "value 1"); form.add("name 2", "value 2+1"); form.add("name 2", "value 2+2"); template.postForLocation(baseUrl + "/form", form); } @Test public void exchangeGet() throws Exception { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyHeader", "MyValue"); HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders); ResponseEntity<String> response = template.exchange(baseUrl + "/{method}", HttpMethod.GET, requestEntity, String.class, "get"); assertEquals("Invalid content", helloWorld, response.getBody()); } @Test public void exchangePost() throws Exception { HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("MyHeader", "MyValue"); requestHeaders.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> requestEntity = new HttpEntity<>(helloWorld, requestHeaders); HttpEntity<Void> result = template.exchange(baseUrl + "/{method}", HttpMethod.POST, requestEntity, Void.class, "post"); assertEquals("Invalid location", new URI(baseUrl + "/post/1"), result.getHeaders().getLocation()); assertFalse(result.hasBody()); } @Test public void jsonPostForObject() throws URISyntaxException { HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8)); MySampleBean bean = new MySampleBean(); bean.setWith1("with"); bean.setWith2("with"); bean.setWithout("without"); HttpEntity<MySampleBean> entity = new HttpEntity<>(bean, entityHeaders); String s = template.postForObject(baseUrl + "/jsonpost", entity, String.class); assertTrue(s.contains("\"with1\":\"with\"")); assertTrue(s.contains("\"with2\":\"with\"")); assertTrue(s.contains("\"without\":\"without\"")); } @Test public void jsonPostForObjectWithJacksonView() throws URISyntaxException { HttpHeaders entityHeaders = new HttpHeaders(); entityHeaders.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8)); MySampleBean bean = new MySampleBean("with", "with", "without"); MappingJacksonValue jacksonValue = new MappingJacksonValue(bean); jacksonValue.setSerializationView(MyJacksonView1.class); HttpEntity<MappingJacksonValue> entity = new HttpEntity<>(jacksonValue, entityHeaders); String s = template.postForObject(baseUrl + "/jsonpost", entity, String.class); assertTrue(s.contains("\"with1\":\"with\"")); assertFalse(s.contains("\"with2\":\"with\"")); assertFalse(s.contains("\"without\":\"without\"")); } @Test // SPR-12123 public void serverPort() { String s = template.getForObject("http://localhost:{port}/get", String.class, port); assertEquals("Invalid content", helloWorld, s); } @Test // SPR-13154 public void jsonPostForObjectWithJacksonTypeInfoList() throws URISyntaxException { List<ParentClass> list = new ArrayList<>(); list.add(new Foo("foo")); list.add(new Bar("bar")); ParameterizedTypeReference<?> typeReference = new ParameterizedTypeReference<List<ParentClass>>() {}; RequestEntity<List<ParentClass>> entity = RequestEntity .post(new URI(baseUrl + "/jsonpost")) .contentType(new MediaType("application", "json", StandardCharsets.UTF_8)) .body(list, typeReference.getType()); String content = template.exchange(entity, String.class).getBody(); assertTrue(content.contains("\"type\":\"foo\"")); assertTrue(content.contains("\"type\":\"bar\"")); } @Test // SPR-15015 public void postWithoutBody() throws Exception { assertNull(template.postForObject(baseUrl + "/jsonpost", null, String.class)); } public interface MyJacksonView1 {} public interface MyJacksonView2 {} public static class MySampleBean { @JsonView(MyJacksonView1.class) private String with1; @JsonView(MyJacksonView2.class) private String with2; private String without; private MySampleBean() { } private MySampleBean(String with1, String with2, String without) { this.with1 = with1; this.with2 = with2; this.without = without; } public String getWith1() { return with1; } public void setWith1(String with1) { this.with1 = with1; } public String getWith2() { return with2; } public void setWith2(String with2) { this.with2 = with2; } public String getWithout() { return without; } public void setWithout(String without) { this.without = without; } } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") public static class ParentClass { private String parentProperty; public ParentClass() { } public ParentClass(String parentProperty) { this.parentProperty = parentProperty; } public String getParentProperty() { return parentProperty; } public void setParentProperty(String parentProperty) { this.parentProperty = parentProperty; } } @JsonTypeName("foo") public static class Foo extends ParentClass { public Foo() { } public Foo(String parentProperty) { super(parentProperty); } } @JsonTypeName("bar") public static class Bar extends ParentClass { public Bar() { } public Bar(String parentProperty) { super(parentProperty); } } }