Introduced ResponseEntity, for access to the response status code

This commit is contained in:
Arjen Poutsma 2010-04-01 10:08:51 +00:00
parent 636e2f0f4c
commit 689e7b7af2
13 changed files with 438 additions and 360 deletions

View File

@ -61,12 +61,14 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.ExtendedModelMap;
@ -895,6 +897,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
} }
HttpInputMessage inputMessage = createHttpInputMessage(webRequest); HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest);
if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) {
((ServerHttpResponse)outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode());
}
HttpHeaders entityHeaders = responseEntity.getHeaders(); HttpHeaders entityHeaders = responseEntity.getHeaders();
if (!entityHeaders.isEmpty()) { if (!entityHeaders.isEmpty()) {
outputMessage.getHeaders().putAll(entityHeaders); outputMessage.getHeaders().putAll(entityHeaders);

View File

@ -75,6 +75,7 @@ import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
@ -1201,7 +1202,7 @@ public class ServletAnnotationControllerTests {
request.addHeader("MyRequestHeader", "MyValue"); request.addHeader("MyRequestHeader", "MyValue");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response); servlet.service(request, response);
assertEquals(200, response.getStatus()); assertEquals(201, response.getStatus());
assertEquals(requestBody, response.getContentAsString()); assertEquals(requestBody, response.getContentAsString());
assertEquals("MyValue", response.getHeader("MyResponseHeader")); assertEquals("MyValue", response.getHeader("MyResponseHeader"));
} }
@ -2598,7 +2599,7 @@ public class ServletAnnotationControllerTests {
public static class HttpEntityController { public static class HttpEntityController {
@RequestMapping("/handle") @RequestMapping("/handle")
public HttpEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException { public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
assertNotNull(requestEntity); assertNotNull(requestEntity);
assertEquals("MyValue", requestEntity.getHeaders().getFirst("MyRequestHeader")); assertEquals("MyValue", requestEntity.getHeaders().getFirst("MyRequestHeader"));
String requestBody = new String(requestEntity.getBody(), "UTF-8"); String requestBody = new String(requestEntity.getBody(), "UTF-8");
@ -2606,7 +2607,7 @@ public class ServletAnnotationControllerTests {
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue"); responseHeaders.set("MyResponseHeader", "MyValue");
return new HttpEntity<String>(requestBody, responseHeaders); return new ResponseEntity<String>(requestBody, responseHeaders, HttpStatus.CREATED);
} }
} }

View File

@ -16,9 +16,6 @@
package org.springframework.http; package org.springframework.http;
import java.util.Map;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
/** /**
@ -35,6 +32,15 @@ import org.springframework.util.MultiValueMap;
* String body = entity.getBody(); * String body = entity.getBody();
* MediaType contentType = entity.getHeaders().getContentType(); * MediaType contentType = entity.getHeaders().getContentType();
* </pre> * </pre>
* Can also be used in Spring MVC, as a return value from a @Controller method:
* <pre>
* &#64;RequestMapping("/handle")
* public HttpEntity&ltString&gt handle() {
* HttpHeaders responseHeaders = new HttpHeaders();
* responseHeaders.set("MyResponseHeader", "MyValue");
* return new HttpEntity<String>("Hello World", responseHeaders);
* }
* </pre>
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.0.2 * @since 3.0.2
@ -59,7 +65,7 @@ public class HttpEntity<T> {
* Create a new, empty {@code HttpEntity}. * Create a new, empty {@code HttpEntity}.
*/ */
private HttpEntity() { private HttpEntity() {
this(null, (MultiValueMap<String, String>) null); this(null, null);
} }
/** /**
@ -67,15 +73,7 @@ public class HttpEntity<T> {
* @param body the entity body * @param body the entity body
*/ */
public HttpEntity(T body) { public HttpEntity(T body) {
this(body, (MultiValueMap<String, String>) null); this(body, null);
}
/**
* Create a new {@code HttpEntity} with the given headers and no body.
* @param headers the entity headers
*/
public HttpEntity(Map<String, String> headers) {
this(null, toMultiValueMap(headers));
} }
/** /**
@ -86,24 +84,6 @@ public class HttpEntity<T> {
this(null, headers); this(null, headers);
} }
/**
* Create a new {@code HttpEntity} with the given body and {@code Content-Type} header value.
* @param body the entity body
* @param contentType the value of the {@code Content-Type header}
*/
public HttpEntity(T body, MediaType contentType) {
this(body, toMultiValueMap(contentType));
}
/**
* Create a new {@code HttpEntity} with the given body and headers.
* @param body the entity body
* @param headers the entity headers
*/
public HttpEntity(T body, Map<String, String> headers) {
this(body, toMultiValueMap(headers));
}
/** /**
* Create a new {@code HttpEntity} with the given body and headers. * Create a new {@code HttpEntity} with the given body and headers.
* @param body the entity body * @param body the entity body
@ -140,27 +120,4 @@ public class HttpEntity<T> {
return (this.body != null); return (this.body != null);
} }
private static MultiValueMap<String, String> toMultiValueMap(Map<String, String> map) {
if (map == null) {
return null;
}
else {
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(map.size());
result.setAll(map);
return result;
}
}
private static MultiValueMap<String, String> toMultiValueMap(MediaType contentType) {
if (contentType == null) {
return null;
}
else {
HttpHeaders result = new HttpHeaders();
result.setContentType(contentType);
return result;
}
}
} }

View File

@ -0,0 +1,70 @@
/*
* Copyright 2002-2010 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.http;
import org.springframework.util.MultiValueMap;
/**
* Extension of {@link HttpEntity} that adds a {@link HttpStatus} status code.
*
* @author Arjen Poutsma
* @since 3.0.2
* @see #getStatusCode()
*/
public class ResponseEntity<T> extends HttpEntity<T> {
private final HttpStatus statusCode;
/**
* Create a new {@code ResponseEntity} with the given body and status code, and no headers.
* @param body the entity body
* @param statusCode the status code
*/
public ResponseEntity(T body, HttpStatus statusCode) {
super(body);
this.statusCode = statusCode;
}
/**
* Create a new {@code HttpEntity} with the given headers and status code, and no body.
* @param headers the entity headers
* @param statusCode the status code
*/
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus statusCode) {
super(headers);
this.statusCode = statusCode;
}
/**
* Create a new {@code HttpEntity} with the given body, headers, and status code.
* @param body the entity body
* @param headers the entity headers
* @param statusCode the status code
*/
public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus statusCode) {
super(body, headers);
this.statusCode = statusCode;
}
/**
* Return the HTTP status code of the response.
* @return the HTTP status as an HttpStatus enum value
*/
public HttpStatus getStatusCode() {
return statusCode;
}
}

View File

@ -151,7 +151,8 @@ import java.lang.annotation.Target;
* to the response stream using * to the response stream using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message * {@linkplain org.springframework.http.converter.HttpMessageConverter message
* converters}. * converters}.
* <li>A {@link org.springframework.http.HttpEntity HttpEntity&lt;?&gt;} object * <li>A {@link org.springframework.http.HttpEntity HttpEntity&lt;?&gt;} or
* {@link org.springframework.http.ResponseEntity ResponseEntity&lt;?&gt;} object
* to access to the Servlet reponse HTTP headers and contents. The entity body will * to access to the Servlet reponse HTTP headers and contents. The entity body will
* be converted to the response stream using * be converted to the response stream using
* {@linkplain org.springframework.http.converter.HttpMessageConverter message * {@linkplain org.springframework.http.converter.HttpMessageConverter message

View File

@ -23,6 +23,7 @@ import java.util.Set;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
/** /**
* Interface specifying a basic set of RESTful operations. Implemented by {@link RestTemplate}. * Interface specifying a basic set of RESTful operations. Implemented by {@link RestTemplate}.
@ -71,7 +72,7 @@ public interface RestOperations {
/** /**
* Retrieve an entity by doing a GET on the specified URL. * Retrieve an entity by doing a GET on the specified URL.
* The response is converted and stored in an {@link HttpEntity}. * The response is converted and stored in an {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any. * <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL * @param url the URL
* @param responseType the type of the return value * @param responseType the type of the return value
@ -79,11 +80,11 @@ public interface RestOperations {
* @return the entity * @return the entity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException; <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... 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 is converted and stored in an {@link HttpEntity}. * The response is converted and stored in an {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given map. * <p>URI Template variables are expanded using the given map.
* @param url the URL * @param url the URL
* @param responseType the type of the return value * @param responseType the type of the return value
@ -91,17 +92,17 @@ public interface RestOperations {
* @return the converted object * @return the converted object
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
/** /**
* Retrieve a representation by doing a GET on the URL . * Retrieve a representation by doing a GET on the URL .
* The response is converted and stored in an {@link HttpEntity}. * The response is converted and stored in an {@link ResponseEntity}.
* @param url the URL * @param url the URL
* @param responseType the type of the return value * @param responseType the type of the return value
* @return the converted object * @return the converted object
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException; <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
// HEAD // HEAD
@ -219,7 +220,7 @@ public interface RestOperations {
/** /**
* Create a new resource by POSTing the given object to the URI template, * Create a new resource by POSTing the given object to the URI template,
* and returns the response as {@link HttpEntity}. * and returns the response as {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any. * <p>URI Template variables are expanded using the given URI variables, if any.
* <p>The {@code request} parameter can be a {@link HttpEntity} in order to * <p>The {@code request} parameter can be a {@link HttpEntity} in order to
* add additional HTTP headers to the request. * add additional HTTP headers to the request.
@ -230,7 +231,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables) <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException; throws RestClientException;
/** /**
@ -251,7 +252,7 @@ public interface RestOperations {
/** /**
* Create a new resource by POSTing the given object to the URL, * Create a new resource by POSTing the given object to the URL,
* and returns the response as {@link HttpEntity}. * and returns the response as {@link ResponseEntity}.
* <p>The {@code request} parameter can be a {@link HttpEntity} in order to * <p>The {@code request} parameter can be a {@link HttpEntity} in order to
* add additional HTTP headers to the request. * add additional HTTP headers to the request.
* @param url the URL * @param url the URL
@ -260,7 +261,7 @@ public interface RestOperations {
* @see HttpEntity * @see HttpEntity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException; <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;
// PUT // PUT
@ -354,7 +355,7 @@ public interface RestOperations {
/** /**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, and * Execute the HTTP method to the given URI template, writing the given request entity to the request, and
* returns the response as {@link HttpEntity}. * returns the response as {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any. * <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL * @param url the URL
* @param method the HTTP method (GET, POST, etc) * @param method the HTTP method (GET, POST, etc)
@ -364,12 +365,12 @@ public interface RestOperations {
* @return the response as entity * @return the response as entity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType, Object... uriVariables) throws RestClientException; Class<T> responseType, Object... uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, and * Execute the HTTP method to the given URI template, writing the given request entity to the request, and
* returns the response as {@link HttpEntity}. * returns the response as {@link ResponseEntity}.
* <p>URI Template variables are expanded using the given URI variables, if any. * <p>URI Template variables are expanded using the given URI variables, if any.
* @param url the URL * @param url the URL
* @param method the HTTP method (GET, POST, etc) * @param method the HTTP method (GET, POST, etc)
@ -379,12 +380,12 @@ public interface RestOperations {
* @return the response as entity * @return the response as entity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
/** /**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, and * Execute the HTTP method to the given URI template, writing the given request entity to the request, and
* returns the response as {@link HttpEntity}. * returns the response as {@link ResponseEntity}.
* @param url the URL * @param url the URL
* @param method the HTTP method (GET, POST, etc) * @param method the HTTP method (GET, POST, etc)
* @param requestEntity the entity (headers and/or body) to write to the request, may be {@code null} * @param requestEntity the entity (headers and/or body) to write to the request, may be {@code null}
@ -392,7 +393,7 @@ public interface RestOperations {
* @return the response as entity * @return the response as entity
* @since 3.0.2 * @since 3.0.2
*/ */
<T> HttpEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException; Class<T> responseType) throws RestClientException;
// general execution // general execution

View File

@ -29,6 +29,7 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
@ -212,26 +213,26 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
return execute(url, HttpMethod.GET, requestCallback, responseExtractor); return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
} }
public <T> HttpEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables) public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables)
throws RestClientException { throws RestClientException {
AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType); AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
} }
public <T> HttpEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables) public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables)
throws RestClientException { throws RestClientException {
AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType); AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
} }
public <T> HttpEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException { public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType); AcceptHeaderRequestCallback requestCallback = new AcceptHeaderRequestCallback(responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor); return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
} }
@ -293,11 +294,11 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
return execute(url, HttpMethod.POST, requestCallback, responseExtractor); return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
} }
public <T> HttpEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables) public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException { throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
} }
@ -307,15 +308,15 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
Map<String, ?> uriVariables) Map<String, ?> uriVariables)
throws RestClientException { throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
} }
public <T> HttpEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException { public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(request, responseType);
HttpEntityResponseExtractor<T> responseExtractor = ResponseEntityResponseExtractor<T> responseExtractor =
new HttpEntityResponseExtractor<T>(responseType); new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor); return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
} }
@ -369,24 +370,24 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
// exchange // exchange
public <T> HttpEntity<T> exchange(String url, HttpMethod method, public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException { HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType);
HttpEntityResponseExtractor<T> responseExtractor = new HttpEntityResponseExtractor<T>(responseType); ResponseEntityResponseExtractor<T> responseExtractor = new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables); return execute(url, method, requestCallback, responseExtractor, uriVariables);
} }
public <T> HttpEntity<T> exchange(String url, HttpMethod method, public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType);
HttpEntityResponseExtractor<T> responseExtractor = new HttpEntityResponseExtractor<T>(responseType); ResponseEntityResponseExtractor<T> responseExtractor = new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables); return execute(url, method, requestCallback, responseExtractor, uriVariables);
} }
public <T> HttpEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException { Class<T> responseType) throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType); HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType);
HttpEntityResponseExtractor<T> responseExtractor = new HttpEntityResponseExtractor<T>(responseType); ResponseEntityResponseExtractor<T> responseExtractor = new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, method, requestCallback, responseExtractor); return execute(url, method, requestCallback, responseExtractor);
} }
@ -601,11 +602,11 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
/** /**
* Response extractor for {@link HttpEntity}. * Response extractor for {@link HttpEntity}.
*/ */
private class HttpEntityResponseExtractor<T> implements ResponseExtractor<HttpEntity<T>> { private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
private final HttpMessageConverterExtractor<T> delegate; private final HttpMessageConverterExtractor<T> delegate;
public HttpEntityResponseExtractor(Class<T> responseType) { public ResponseEntityResponseExtractor(Class<T> responseType) {
if (responseType != null) { if (responseType != null) {
this.delegate = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); this.delegate = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
} else { } else {
@ -613,13 +614,13 @@ public class RestTemplate extends HttpAccessor implements RestOperations {
} }
} }
public HttpEntity<T> extractData(ClientHttpResponse response) throws IOException { public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
if (delegate != null) { if (delegate != null) {
T body = delegate.extractData(response); T body = delegate.extractData(response);
return new HttpEntity<T>(body, response.getHeaders()); return new ResponseEntity<T>(body, response.getHeaders(), response.getStatusCode());
} }
else { else {
return new HttpEntity<T>(response.getHeaders()); return new ResponseEntity<T>(response.getHeaders(), response.getStatusCode());
} }
} }
} }

View File

@ -16,9 +16,6 @@
package org.springframework.http; package org.springframework.http;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
@ -39,10 +36,13 @@ public class HttpEntityTests {
} }
@Test @Test
public void contentType() { public void httpHeaders() {
MediaType contentType = MediaType.TEXT_PLAIN; HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>("foo", contentType); headers.setContentType(MediaType.TEXT_PLAIN);
assertEquals(contentType, entity.getHeaders().getContentType()); String body = "foo";
HttpEntity<String> entity = new HttpEntity<String>(body, headers);
assertEquals(body, entity.getBody());
assertEquals(MediaType.TEXT_PLAIN, entity.getHeaders().getContentType());
assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type")); assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type"));
} }
@ -50,18 +50,24 @@ public class HttpEntityTests {
public void multiValueMap() { public void multiValueMap() {
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(); MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.set("Content-Type", "text/plain"); map.set("Content-Type", "text/plain");
HttpEntity<String> entity = new HttpEntity<String>("foo", map); String body = "foo";
HttpEntity<String> entity = new HttpEntity<String>(body, map);
assertEquals(body, entity.getBody());
assertEquals(MediaType.TEXT_PLAIN, entity.getHeaders().getContentType()); assertEquals(MediaType.TEXT_PLAIN, entity.getHeaders().getContentType());
assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type")); assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type"));
} }
@Test @Test
public void map() { public void responseEntity() {
Map<String, String> map = new LinkedHashMap<String, String>(); HttpHeaders headers = new HttpHeaders();
map.put("Content-Type", "text/plain"); headers.setContentType(MediaType.TEXT_PLAIN);
HttpEntity<String> entity = new HttpEntity<String>("foo", map); String body = "foo";
ResponseEntity<String> entity = new ResponseEntity<String>(body, headers, HttpStatus.OK);
assertEquals(body, entity.getBody());
assertEquals(MediaType.TEXT_PLAIN, entity.getHeaders().getContentType()); assertEquals(MediaType.TEXT_PLAIN, entity.getHeaders().getContentType());
assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type")); assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type"));
assertEquals("text/plain", entity.getHeaders().getFirst("Content-Type"));
} }
} }

View File

@ -37,6 +37,7 @@ import org.junit.Test;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.MockHttpInputMessage; import org.springframework.http.MockHttpInputMessage;
import org.springframework.http.MockHttpOutputMessage; import org.springframework.http.MockHttpOutputMessage;
@ -109,7 +110,9 @@ public class FormHttpMessageConverterTests {
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg"); Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
parts.add("logo", logo); parts.add("logo", logo);
Source xml = new StreamSource(new StringReader("<root><child/></root>")); Source xml = new StreamSource(new StringReader("<root><child/></root>"));
HttpEntity<Source> entity = new HttpEntity<Source>(xml, MediaType.TEXT_XML); HttpHeaders entityHeaders = new HttpHeaders();
entityHeaders.setContentType(MediaType.TEXT_XML);
HttpEntity<Source> entity = new HttpEntity<Source>(xml, entityHeaders);
parts.add("xml", entity); parts.add("xml", entity);
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();

View File

@ -52,7 +52,9 @@ import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.CommonsClientHttpRequestFactory; import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
@ -109,10 +111,11 @@ public class RestTemplateIntegrationTests {
@Test @Test
public void getEntity() { public void getEntity() {
HttpEntity<String> entity = template.getForEntity(URI + "/{method}", String.class, "get"); ResponseEntity<String> entity = template.getForEntity(URI + "/{method}", String.class, "get");
assertEquals("Invalid content", helloWorld, entity.getBody()); assertEquals("Invalid content", helloWorld, entity.getBody());
assertFalse("No headers", entity.getHeaders().isEmpty()); assertFalse("No headers", entity.getHeaders().isEmpty());
assertEquals("Invalid content-type", contentType, entity.getHeaders().getContentType()); assertEquals("Invalid content-type", contentType, entity.getHeaders().getContentType());
assertEquals("Invalid status code", HttpStatus.OK, entity.getStatusCode());
} }
@Test @Test
@ -129,7 +132,9 @@ public class RestTemplateIntegrationTests {
@Test @Test
public void postForLocationEntity() throws URISyntaxException { public void postForLocationEntity() throws URISyntaxException {
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, new MediaType("text", "plain", Charset.forName("ISO-8859-15"))); HttpHeaders entityHeaders = new HttpHeaders();
entityHeaders.setContentType(new MediaType("text", "plain", Charset.forName("ISO-8859-15")));
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, entityHeaders);
URI location = template.postForLocation(URI + "/{method}", entity, "post"); URI location = template.postForLocation(URI + "/{method}", entity, "post");
assertEquals("Invalid location", new URI(URI + "/post/1"), location); assertEquals("Invalid location", new URI(URI + "/post/1"), location);
} }
@ -183,7 +188,7 @@ public class RestTemplateIntegrationTests {
HttpHeaders requestHeaders = new HttpHeaders(); HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyHeader", "MyValue"); requestHeaders.set("MyHeader", "MyValue");
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders); HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);
HttpEntity<String> response = ResponseEntity<String> response =
template.exchange(URI + "/{method}", HttpMethod.GET, requestEntity, String.class, "get"); template.exchange(URI + "/{method}", HttpMethod.GET, requestEntity, String.class, "get");
assertEquals("Invalid content", helloWorld, response.getBody()); assertEquals("Invalid content", helloWorld, response.getBody());
} }

View File

@ -33,6 +33,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
@ -194,14 +195,16 @@ public class RestTemplateTests {
expect(converter.canRead(String.class, textPlain)).andReturn(true); expect(converter.canRead(String.class, textPlain)).andReturn(true);
String expected = "Hello World"; String expected = "Hello World";
expect(converter.read(String.class, response)).andReturn(expected); expect(converter.read(String.class, response)).andReturn(expected);
expect(response.getStatusCode()).andReturn(HttpStatus.OK);
response.close(); response.close();
replayMocks(); replayMocks();
HttpEntity<String> result = template.getForEntity("http://example.com", String.class); ResponseEntity<String> result = template.getForEntity("http://example.com", String.class);
assertEquals("Invalid GET result", expected, result.getBody()); assertEquals("Invalid GET result", expected, result.getBody());
assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept"));
assertEquals("Invalid Content-Type header", textPlain, result.getHeaders().getContentType()); assertEquals("Invalid Content-Type header", textPlain, result.getHeaders().getContentType());
assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode());
verifyMocks(); verifyMocks();
} }
@ -265,7 +268,9 @@ public class RestTemplateTests {
replayMocks(); replayMocks();
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, contentType); HttpHeaders entityHeaders = new HttpHeaders();
entityHeaders.setContentType(contentType);
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, entityHeaders);
URI result = template.postForLocation("http://example.com", entity); URI result = template.postForLocation("http://example.com", entity);
assertEquals("Invalid POST result", expected, result); assertEquals("Invalid POST result", expected, result);
@ -291,7 +296,9 @@ public class RestTemplateTests {
replayMocks(); replayMocks();
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, Collections.singletonMap("MyHeader", "MyValue")); HttpHeaders entityHeaders = new HttpHeaders();
entityHeaders.set("MyHeader", "MyValue");
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, entityHeaders);
URI result = template.postForLocation("http://example.com", entity); URI result = template.postForLocation("http://example.com", entity);
assertEquals("Invalid POST result", expected, result); assertEquals("Invalid POST result", expected, result);
@ -387,14 +394,16 @@ public class RestTemplateTests {
Integer expected = 42; Integer expected = 42;
expect(converter.canRead(Integer.class, textPlain)).andReturn(true); expect(converter.canRead(Integer.class, textPlain)).andReturn(true);
expect(converter.read(Integer.class, response)).andReturn(expected); expect(converter.read(Integer.class, response)).andReturn(expected);
expect(response.getStatusCode()).andReturn(HttpStatus.OK);
response.close(); response.close();
replayMocks(); replayMocks();
HttpEntity<Integer> result = template.postForEntity("http://example.com", request, Integer.class); ResponseEntity<Integer> result = template.postForEntity("http://example.com", request, Integer.class);
assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid POST result", expected, result.getBody());
assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType()); assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType());
assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept"));
assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode());
verifyMocks(); verifyMocks();
} }
@ -439,13 +448,15 @@ public class RestTemplateTests {
expect(response.getHeaders()).andReturn(responseHeaders).times(2); expect(response.getHeaders()).andReturn(responseHeaders).times(2);
expect(converter.canRead(Integer.class, textPlain)).andReturn(true); expect(converter.canRead(Integer.class, textPlain)).andReturn(true);
expect(converter.read(Integer.class, response)).andReturn(null); expect(converter.read(Integer.class, response)).andReturn(null);
expect(response.getStatusCode()).andReturn(HttpStatus.OK);
response.close(); response.close();
replayMocks(); replayMocks();
HttpEntity<Integer> result = template.postForEntity("http://example.com", null, Integer.class); ResponseEntity<Integer> result = template.postForEntity("http://example.com", null, Integer.class);
assertFalse("Invalid POST result", result.hasBody()); assertFalse("Invalid POST result", result.hasBody());
assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType()); assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType());
assertEquals("Invalid content length", 0, requestHeaders.getContentLength()); assertEquals("Invalid content length", 0, requestHeaders.getContentLength());
assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode());
verifyMocks(); verifyMocks();
} }
@ -557,16 +568,20 @@ public class RestTemplateTests {
Integer expected = 42; Integer expected = 42;
expect(converter.canRead(Integer.class, textPlain)).andReturn(true); expect(converter.canRead(Integer.class, textPlain)).andReturn(true);
expect(converter.read(Integer.class, response)).andReturn(expected); expect(converter.read(Integer.class, response)).andReturn(expected);
expect(response.getStatusCode()).andReturn(HttpStatus.OK);
response.close(); response.close();
replayMocks(); replayMocks();
HttpEntity<String> requestEntity = new HttpEntity<String>(body, Collections.singletonMap("MyHeader", "MyValue")); HttpHeaders entityHeaders = new HttpHeaders();
HttpEntity<Integer> result = template.exchange("http://example.com", HttpMethod.POST, requestEntity, Integer.class); entityHeaders.set("MyHeader", "MyValue");
HttpEntity<String> requestEntity = new HttpEntity<String>(body, entityHeaders);
ResponseEntity<Integer> result = template.exchange("http://example.com", HttpMethod.POST, requestEntity, Integer.class);
assertEquals("Invalid POST result", expected, result.getBody()); assertEquals("Invalid POST result", expected, result.getBody());
assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType()); assertEquals("Invalid Content-Type", textPlain, result.getHeaders().getContentType());
assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept")); assertEquals("Invalid Accept header", textPlain.toString(), requestHeaders.getFirst("Accept"));
assertEquals("Invalid custom header", "MyValue", requestHeaders.getFirst("MyHeader")); assertEquals("Invalid custom header", "MyValue", requestHeaders.getFirst("MyHeader"));
assertEquals("Invalid status code", HttpStatus.OK, result.getStatusCode());
verifyMocks(); verifyMocks();
} }

View File

@ -218,6 +218,17 @@
</SOURCES> </SOURCES>
</library> </library>
</orderEntry> </orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/org.apache.commons/com.springsource.org.apache.commons.io/1.4.0/com.springsource.org.apache.commons.io-1.4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/org.apache.commons/com.springsource.org.apache.commons.io/1.4.0/com.springsource.org.apache.commons.io-sources-1.4.0.jar!/" />
</SOURCES>
</library>
</orderEntry>
</component> </component>
<component name="copyright"> <component name="copyright">
<Base> <Base>

View File

@ -1154,7 +1154,8 @@ public class RelativePathUriTemplateController {
</listitem> </listitem>
<listitem> <listitem>
<para>A <classname>HttpEntity&lt;?&gt;</classname>} object <para>A <classname>HttpEntity&lt;?&gt;</classname> or
<classname>ResponseEntity&lt;?&gt;</classname> object
to access to the Servlet reponse HTTP headers and contents. The entity body will to access to the Servlet reponse HTTP headers and contents. The entity body will
be converted to the response stream using be converted to the response stream using
<interfacename>HttpMessageConverter</interfacename>s. See <xref <interfacename>HttpMessageConverter</interfacename>s. See <xref
@ -1328,24 +1329,25 @@ public String helloWorld() {
<para>The <classname>HttpEntity</classname> is similar to <para>The <classname>HttpEntity</classname> is similar to
<interfacename>@RequestBody</interfacename> and <interfacename>@RequestBody</interfacename> and
<interfacename>@ResponseBody</interfacename>. Besides getting <interfacename>@ResponseBody</interfacename>. Besides getting
access to the request and response body, the <classname>HttpEntity</classname> access to the request and response body, <classname>HttpEntity</classname>
(and the response-specific subclass <classname>ResponseEntity</classname>)
also allows access to the request and response headers, like so:</para> also allows access to the request and response headers, like so:</para>
<programlisting language="java">@RequestMapping("/something") <programlisting language="java">@RequestMapping("/something")
public HttpEntity&lt;String&gt; handle(HttpEntity&lt;byte[]&gt; requestEntity) throws UnsupportedEncodingException { public ResponseEntity&lt;String&gt; handle(HttpEntity&lt;byte[]&gt; requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader")); String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));
byte[] requestBody = requestEntity.getBody(); byte[] requestBody = requestEntity.getBody();
// do something with request header and body // do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue"); responseHeaders.set("MyResponseHeader", "MyValue");
return new HttpEntity&lt;String&gt;("Hello World", responseHeaders); return new ResponseEntity&lt;String&gt;("Hello World", responseHeaders, HttpStatus.CREATED);
}</programlisting> }</programlisting>
<para>The above example gets the value of the "MyRequestHeader" request <para>The above example gets the value of the "MyRequestHeader" request
header, and reads the body as a byte array. It adds the "MyResponseHeader" header, and reads the body as a byte array. It adds the "MyResponseHeader"
to the response, and writes <literal>Hello World</literal> to the response to the response, writes <literal>Hello World</literal> to the response
stream.</para> stream, and sets the response status code to 201 (Created).</para>
<para>As with <interfacename>@RequestBody</interfacename> and <para>As with <interfacename>@RequestBody</interfacename> and
<interfacename>@ResponseBody</interfacename>, Spring <interfacename>@ResponseBody</interfacename>, Spring