diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index 2bc17bb2c7c..052c1f3408c 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -16,10 +16,15 @@ package org.springframework.http; +import java.io.Serializable; + import java.net.URI; + import java.nio.charset.Charset; + import java.text.ParseException; import java.text.SimpleDateFormat; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -54,7 +59,9 @@ import org.springframework.util.StringUtils; * @author Arjen Poutsma * @since 3.0 */ -public class HttpHeaders implements MultiValueMap { +public class HttpHeaders implements MultiValueMap, Serializable { + + private static final long serialVersionUID = -8578554704772377436L; private static final String ACCEPT = "Accept"; diff --git a/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java b/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java index 0615f7a823a..50b291cf4ec 100644 --- a/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java +++ b/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; @@ -28,10 +29,11 @@ import org.springframework.util.FileCopyUtils; /** * Default implementation of the {@link ResponseErrorHandler} interface. * - *

This error handler checks for the status code on the {@link ClientHttpResponse}: any code with series - * {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR} or - * {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR} is considered to be an error. - * This behavior can be changed by overriding the {@link #hasError(HttpStatus)} method. + *

This error handler checks for the status code on the {@link ClientHttpResponse}: any + * code with series {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR} or + * {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR} is considered to be an + * error. This behavior can be changed by overriding the {@link #hasError(HttpStatus)} + * method. * * @author Arjen Poutsma * @since 3.0 @@ -68,14 +70,15 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler { */ public void handleError(ClientHttpResponse response) throws IOException { HttpStatus statusCode = response.getStatusCode(); - MediaType contentType = response.getHeaders().getContentType(); + HttpHeaders headers = response.getHeaders(); + MediaType contentType = headers.getContentType(); Charset charset = contentType != null ? contentType.getCharSet() : null; byte[] body = getResponseBody(response); switch (statusCode.series()) { case CLIENT_ERROR: - throw new HttpClientErrorException(statusCode, response.getStatusText(), body, charset); + throw new HttpClientErrorException(statusCode, response.getStatusText(), headers, body, charset); case SERVER_ERROR: - throw new HttpServerErrorException(statusCode, response.getStatusText(), body, charset); + throw new HttpServerErrorException(statusCode, response.getStatusText(), headers, body, charset); default: throw new RestClientException("Unknown status code [" + statusCode + "]"); } @@ -83,15 +86,15 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler { private byte[] getResponseBody(ClientHttpResponse response) { try { - InputStream responseBody = response.getBody(); - if (responseBody != null) { - return FileCopyUtils.copyToByteArray(responseBody); - } + InputStream responseBody = response.getBody(); + if (responseBody != null) { + return FileCopyUtils.copyToByteArray(responseBody); + } } catch (IOException ex) { - // ignore + // ignore } - return new byte[0]; + return new byte[0]; } } diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java b/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java index 99de72b1607..5d5ef0b40e3 100644 --- a/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java +++ b/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java @@ -18,6 +18,7 @@ package org.springframework.web.client; import java.nio.charset.Charset; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; /** @@ -29,10 +30,12 @@ import org.springframework.http.HttpStatus; */ public class HttpClientErrorException extends HttpStatusCodeException { - private static final long serialVersionUID = 6777393766937023392L; + private static final long serialVersionUID = 5177019431887513952L; + /** - * Construct a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus}. + * Construct a new instance of {@code HttpClientErrorException} based on an + * {@link HttpStatus}. * @param statusCode the status code */ public HttpClientErrorException(HttpStatus statusCode) { @@ -40,7 +43,8 @@ public class HttpClientErrorException extends HttpStatusCodeException { } /** - * Construct a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus} and status text. + * Construct a new instance of {@code HttpClientErrorException} based on an + * {@link HttpStatus} and status text. * @param statusCode the status code * @param statusText the status text */ @@ -49,18 +53,31 @@ public class HttpClientErrorException extends HttpStatusCodeException { } /** - * Construct a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus}, status text, and - * response body content. - * - * @param statusCode the status code - * @param statusText the status text - * @param responseBody the response body content, may be {@code null} + * Construct a new instance of {@code HttpClientErrorException} based on an + * {@link HttpStatus}, status text, and response body content. + * @param statusCode the status code + * @param statusText the status text + * @param responseBody the response body content, may be {@code null} * @param responseCharset the response body charset, may be {@code null} */ - public HttpClientErrorException(HttpStatus statusCode, - String statusText, - byte[] responseBody, - Charset responseCharset) { + public HttpClientErrorException(HttpStatus statusCode, String statusText, + byte[] responseBody, Charset responseCharset) { super(statusCode, statusText, responseBody, responseCharset); } + + /** + * Construct a new instance of {@code HttpClientErrorException} based on an + * {@link HttpStatus}, status text, and response body content. + * @param statusCode the status code + * @param statusText the status text + * @param responseHeaders the response headers, may be {@code null} + * @param responseBody the response body content, may be {@code null} + * @param responseCharset the response body charset, may be {@code null} + * @since 3.2 + */ + public HttpClientErrorException(HttpStatus statusCode, String statusText, + HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(statusCode, statusText, responseHeaders, responseBody, responseCharset); + } + } diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java b/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java index 9549dcbd0e5..07bd013a52d 100644 --- a/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java +++ b/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java @@ -18,6 +18,7 @@ package org.springframework.web.client; import java.nio.charset.Charset; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; /** @@ -29,11 +30,12 @@ import org.springframework.http.HttpStatus; */ public class HttpServerErrorException extends HttpStatusCodeException { - private static final long serialVersionUID = -2565832100451369997L; + private static final long serialVersionUID = -2915754006618138282L; + /** - * Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}. - * + * Construct a new instance of {@code HttpServerErrorException} based on an + * {@link HttpStatus}. * @param statusCode the status code */ public HttpServerErrorException(HttpStatus statusCode) { @@ -41,8 +43,8 @@ public class HttpServerErrorException extends HttpStatusCodeException { } /** - * Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus} and status text. - * + * Construct a new instance of {@code HttpServerErrorException} based on an + * {@link HttpStatus} and status text. * @param statusCode the status code * @param statusText the status text */ @@ -51,19 +53,31 @@ public class HttpServerErrorException extends HttpStatusCodeException { } /** - * Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}, status text, and - * response body content. - * + * Construct a new instance of {@code HttpServerErrorException} based on an + * {@link HttpStatus}, status text, and response body content. * @param statusCode the status code * @param statusText the status text * @param responseBody the response body content, may be {@code null} * @param responseCharset the response body charset, may be {@code null} * @since 3.0.5 */ - public HttpServerErrorException(HttpStatus statusCode, - String statusText, - byte[] responseBody, - Charset responseCharset) { + public HttpServerErrorException(HttpStatus statusCode, String statusText, + byte[] responseBody, Charset responseCharset) { super(statusCode, statusText, responseBody, responseCharset); } + + /** + * Construct a new instance of {@code HttpServerErrorException} based on a + * {@link HttpStatus}, status text, and response body content. + * @param statusCode the status code + * @param statusText the status text + * @param responseHeaders the response headers, may be {@code null} + * @param responseBody the response body content, may be {@code null} + * @param responseCharset the response body charset, may be {@code null} + * @since 3.2 + */ + public HttpServerErrorException(HttpStatus statusCode, String statusText, + HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(statusCode, statusText, responseHeaders, responseBody, responseCharset); + } } diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java b/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java index e2396e0683d..106ec761d65 100644 --- a/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java +++ b/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java @@ -19,6 +19,7 @@ package org.springframework.web.client; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; /** @@ -30,7 +31,7 @@ import org.springframework.http.HttpStatus; */ public abstract class HttpStatusCodeException extends RestClientException { - private static final long serialVersionUID = 1549626836533638803L; + private static final long serialVersionUID = -5807494703720513267L; private static final String DEFAULT_CHARSET = "ISO-8859-1"; @@ -40,34 +41,36 @@ public abstract class HttpStatusCodeException extends RestClientException { private final byte[] responseBody; + private final HttpHeaders responseHeaders; + private final String responseCharset; + /** - * Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}. - * + * Construct a new instance of {@code HttpStatusCodeException} based on an + * {@link HttpStatus}. * @param statusCode the status code */ protected HttpStatusCodeException(HttpStatus statusCode) { - this(statusCode, statusCode.name(), null, null); + this(statusCode, statusCode.name(), null, null, null); } /** - * Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus} and status text. - * + * Construct a new instance of {@code HttpStatusCodeException} based on an + * {@link HttpStatus} and status text. * @param statusCode the status code * @param statusText the status text */ protected HttpStatusCodeException(HttpStatus statusCode, String statusText) { - this(statusCode, statusText, null, null); + this(statusCode, statusText, null, null, null); } /** - * Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}, status text, and - * response body content. - * - * @param statusCode the status code - * @param statusText the status text - * @param responseBody the response body content, may be {@code null} + * Construct a new instance of {@code HttpStatusCodeException} based on an + * {@link HttpStatus}, status text, and response body content. + * @param statusCode the status code + * @param statusText the status text + * @param responseBody the response body content, may be {@code null} * @param responseCharset the response body charset, may be {@code null} * @since 3.0.5 */ @@ -75,29 +78,54 @@ public abstract class HttpStatusCodeException extends RestClientException { String statusText, byte[] responseBody, Charset responseCharset) { + this(statusCode, statusText, null, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpStatusCodeException} based on an + * {@link HttpStatus}, status text, and response body content. + * @param statusCode the status code + * @param statusText the status text + * @param responseHeaders the response headers, may be {@code null} + * @param responseBody the response body content, may be {@code null} + * @param responseCharset the response body charset, may be {@code null} + * @since 3.2 + */ + protected HttpStatusCodeException(HttpStatus statusCode, String statusText, + HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { super(statusCode.value() + " " + statusText); this.statusCode = statusCode; this.statusText = statusText; + this.responseHeaders = responseHeaders; this.responseBody = responseBody != null ? responseBody : new byte[0]; this.responseCharset = responseCharset != null ? responseCharset.name() : DEFAULT_CHARSET; } + /** - * Returns the HTTP status code. + * Return the HTTP status code. */ public HttpStatus getStatusCode() { return this.statusCode; } /** - * Returns the HTTP status text. + * Return the HTTP status text. */ public String getStatusText() { return this.statusText; } /** - * Returns the response body as a byte array. + * Return the HTTP response headers. + * @since 3.2 + */ + public HttpHeaders getResponseHeaders() { + return this.responseHeaders; + } + + /** + * Return the response body as a byte array. * * @since 3.0.5 */ @@ -106,8 +134,7 @@ public abstract class HttpStatusCodeException extends RestClientException { } /** - * Returns the response body as a string. - * + * Return the response body as a string. * @since 3.0.5 */ public String getResponseBodyAsString() { @@ -119,4 +146,5 @@ public abstract class HttpStatusCodeException extends RestClientException { throw new InternalError(ex.getMessage()); } } + } diff --git a/spring-web/src/main/java/org/springframework/web/client/ResourceAccessException.java b/spring-web/src/main/java/org/springframework/web/client/ResourceAccessException.java index 8ef27842520..3472b82d599 100644 --- a/spring-web/src/main/java/org/springframework/web/client/ResourceAccessException.java +++ b/spring-web/src/main/java/org/springframework/web/client/ResourceAccessException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 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. @@ -26,6 +26,9 @@ import java.io.IOException; */ public class ResourceAccessException extends RestClientException { + private static final long serialVersionUID = -8513182514355844870L; + + /** * Construct a new {@code HttpIOException} with the given message. * @param msg the message diff --git a/spring-web/src/main/java/org/springframework/web/client/RestClientException.java b/spring-web/src/main/java/org/springframework/web/client/RestClientException.java index f772ada851d..a741e663a51 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestClientException.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestClientException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 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. @@ -19,13 +19,17 @@ package org.springframework.web.client; import org.springframework.core.NestedRuntimeException; /** - * Base class for exceptions thrown by {@link RestTemplate} whenever it encounters client-side HTTP errors. + * Base class for exceptions thrown by {@link RestTemplate} whenever it encounters + * client-side HTTP errors. * * @author Arjen Poutsma * @since 3.0 */ public class RestClientException extends NestedRuntimeException { + private static final long serialVersionUID = -4084444984163796577L; + + /** * Construct a new instance of {@code HttpClientException} with the given message. * @param msg the message @@ -35,7 +39,8 @@ public class RestClientException extends NestedRuntimeException { } /** - * Construct a new instance of {@code HttpClientException} with the given message and exception. + * Construct a new instance of {@code HttpClientException} with the given message and + * exception. * @param msg the message * @param ex the exception */ diff --git a/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java b/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java index 0c9866c19be..13231a431a5 100644 --- a/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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. @@ -19,19 +19,23 @@ package org.springframework.web.client; import java.io.ByteArrayInputStream; import java.io.IOException; +import org.junit.Before; +import org.junit.Test; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; -import org.junit.Before; -import org.junit.Test; - import static org.easymock.EasyMock.*; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -/** @author Arjen Poutsma */ +import static org.junit.Assert.*; + +/** + * Unit tests for {@link DefaultResponseErrorHandler}. + * + * @author Arjen Poutsma + */ public class DefaultResponseErrorHandlerTests { private DefaultResponseErrorHandler handler; @@ -64,7 +68,7 @@ public class DefaultResponseErrorHandlerTests { verify(response); } - @Test(expected = HttpClientErrorException.class) + @Test public void handleError() throws Exception { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); @@ -76,7 +80,13 @@ public class DefaultResponseErrorHandlerTests { replay(response); - handler.handleError(response); + try { + handler.handleError(response); + fail("expected HttpClientErrorException"); + } + catch (HttpClientErrorException e) { + assertSame(headers, e.getResponseHeaders()); + } verify(response); }