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 e545f978e4ed8d31f0618efc11e3570b2172b48d..a11baa57b3b4f1f77b9a8d1813d0ea7a6b85ef26 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 @@ -90,13 +90,77 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler { protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException { switch (statusCode.series()) { case CLIENT_ERROR: + handleClientError(response, statusCode); + return; + case SERVER_ERROR: + handleServerError(response, statusCode); + return; + default: + throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + } + } + + private void handleClientError(ClientHttpResponse response, HttpStatus statusCode) throws IOException { + switch (statusCode) { + case BAD_REQUEST: + throw new HttpClientErrorException.BadRequest(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case UNAUTHORIZED: + throw new HttpClientErrorException.Unauthorized(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case FORBIDDEN: + throw new HttpClientErrorException.Forbidden(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case NOT_FOUND: + throw new HttpClientErrorException.NotFound(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case METHOD_NOT_ALLOWED: + throw new HttpClientErrorException.MethodNotAllowed(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case NOT_ACCEPTABLE: + throw new HttpClientErrorException.NotAcceptable(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case CONFLICT: + throw new HttpClientErrorException.Conflict(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case GONE: + throw new HttpClientErrorException.Gone(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case UNSUPPORTED_MEDIA_TYPE: + throw new HttpClientErrorException.UnsupportedMediaType(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case TOO_MANY_REQUESTS: + throw new HttpClientErrorException.TooManyRequests(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case UNPROCESSABLE_ENTITY: + throw new HttpClientErrorException.UnprocessableEntity(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + default: throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response)); - case SERVER_ERROR: - throw new HttpServerErrorException(statusCode, response.getStatusText(), + } + } + + private void handleServerError(ClientHttpResponse response, HttpStatus statusCode) throws IOException { + switch (statusCode) { + case INTERNAL_SERVER_ERROR: + throw new HttpServerErrorException.InternalServerError(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case NOT_IMPLEMENTED: + throw new HttpServerErrorException.NotImplemented(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case BAD_GATEWAY: + throw new HttpServerErrorException.BadGateway(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case SERVICE_UNAVAILABLE: + throw new HttpServerErrorException.ServiceUnavailable(response.getStatusText(), + response.getHeaders(), getResponseBody(response), getCharset(response)); + case GATEWAY_TIMEOUT: + throw new HttpServerErrorException.GatewayTimeout(response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response)); default: - throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), + throw new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response)); } } 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 8e7814d21df0d0df5a2284ffeef00df0944fcda5..c2a86a5a3ec20a2172c04d7d19d38a317e99009e 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 @@ -83,4 +83,554 @@ public class HttpClientErrorException extends HttpStatusCodeException { super(statusCode, statusText, responseHeaders, responseBody, responseCharset); } + /** + * Exception thrown when an HTTP 400 Bad Request is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class BadRequest extends HttpClientErrorException { + + private static final long serialVersionUID = -2064198172908428197L; + + /** + * Construct a new instance of {@code HttpClientErrorException.BadRequest}. + */ + public BadRequest() { + super(HttpStatus.BAD_REQUEST); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.BadRequest} based on status text. + * @param statusText the status text + */ + public BadRequest(String statusText) { + super(HttpStatus.BAD_REQUEST, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.BadRequest} based status text + * and response body content. + * @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 BadRequest(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.BAD_REQUEST, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.BadRequest} based on status text + * and response body content. + * @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}) + */ + public BadRequest(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.BAD_REQUEST, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 401 Unauthorized is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class Unauthorized extends HttpClientErrorException { + + private static final long serialVersionUID = 2770517013134530298L; + + /** + * Construct a new instance of {@code HttpClientErrorException.Unauthorized}. + */ + public Unauthorized() { + super(HttpStatus.UNAUTHORIZED); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Unauthorized} based on status text. + * @param statusText the status text + */ + public Unauthorized(String statusText) { + super(HttpStatus.UNAUTHORIZED, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Unauthorized} based status text + * and response body content. + * @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 Unauthorized(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNAUTHORIZED, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Unauthorized} based on status text + * and response body content. + * @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}) + */ + public Unauthorized(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNAUTHORIZED, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 403 Forbidden is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class Forbidden extends HttpClientErrorException { + + private static final long serialVersionUID = 620402597011417919L; + + /** + * Construct a new instance of {@code HttpClientErrorException.Forbidden}. + */ + public Forbidden() { + super(HttpStatus.FORBIDDEN); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Forbidden} based on status text. + * @param statusText the status text + */ + public Forbidden(String statusText) { + super(HttpStatus.FORBIDDEN, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Forbidden} based status text + * and response body content. + * @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 Forbidden(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.FORBIDDEN, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Forbidden} based on status text + * and response body content. + * @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}) + */ + public Forbidden(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.FORBIDDEN, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 404 Not Found is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class NotFound extends HttpClientErrorException { + + private static final long serialVersionUID = -9150078287238394669L; + + /** + * Construct a new instance of {@code HttpClientErrorException.NotFound}. + */ + public NotFound() { + super(HttpStatus.NOT_FOUND); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotFound} based on status text. + * @param statusText the status text + */ + public NotFound(String statusText) { + super(HttpStatus.NOT_FOUND, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotFound} based status text + * and response body content. + * @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 NotFound(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_FOUND, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotFound} based on status text + * and response body content. + * @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}) + */ + public NotFound(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_FOUND, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 405 Method Not Allowed is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class MethodNotAllowed extends HttpClientErrorException { + + private static final long serialVersionUID = -1485854208191929937L; + + /** + * Construct a new instance of {@code HttpClientErrorException.MethodNotAllowed}. + */ + public MethodNotAllowed() { + super(HttpStatus.METHOD_NOT_ALLOWED); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.MethodNotAllowed} based on status text. + * @param statusText the status text + */ + public MethodNotAllowed(String statusText) { + super(HttpStatus.METHOD_NOT_ALLOWED, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.MethodNotAllowed} based status text + * and response body content. + * @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 MethodNotAllowed(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.METHOD_NOT_ALLOWED, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.MethodNotAllowed} based on status text + * and response body content. + * @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}) + */ + public MethodNotAllowed(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.METHOD_NOT_ALLOWED, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 406 Not Acceptable is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class NotAcceptable extends HttpClientErrorException { + + private static final long serialVersionUID = -1762209525396296759L; + + /** + * Construct a new instance of {@code HttpClientErrorException.NotAcceptable}. + */ + public NotAcceptable() { + super(HttpStatus.NOT_ACCEPTABLE); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotAcceptable} based on status text. + * @param statusText the status text + */ + public NotAcceptable(String statusText) { + super(HttpStatus.NOT_ACCEPTABLE, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotAcceptable} based status text + * and response body content. + * @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 NotAcceptable(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_ACCEPTABLE, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.NotAcceptable} based on status text + * and response body content. + * @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}) + */ + public NotAcceptable(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_ACCEPTABLE, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 409 Conflict is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class Conflict extends HttpClientErrorException { + + private static final long serialVersionUID = -147527825450228693L; + + /** + * Construct a new instance of {@code HttpClientErrorException.Conflict}. + */ + public Conflict() { + super(HttpStatus.CONFLICT); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Conflict} based on status text. + * @param statusText the status text + */ + public Conflict(String statusText) { + super(HttpStatus.CONFLICT, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Conflict} based status text + * and response body content. + * @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 Conflict(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.CONFLICT, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Conflict} based on status text + * and response body content. + * @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}) + */ + public Conflict(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.CONFLICT, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 410 Gone is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class Gone extends HttpClientErrorException { + + private static final long serialVersionUID = -147527825450228693L; + + /** + * Construct a new instance of {@code HttpClientErrorException.Gone}. + */ + public Gone() { + super(HttpStatus.GONE); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Gone} based on status text. + * @param statusText the status text + */ + public Gone(String statusText) { + super(HttpStatus.GONE, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Gone} based status text + * and response body content. + * @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 Gone(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.GONE, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.Gone} based on status text + * and response body content. + * @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}) + */ + public Gone(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.GONE, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 415 Unsupported Media Type is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class UnsupportedMediaType extends HttpClientErrorException { + + private static final long serialVersionUID = -7894170475662610655L; + + /** + * Construct a new instance of {@code HttpClientErrorException.UnsupportedMediaType}. + */ + public UnsupportedMediaType() { + super(HttpStatus.UNSUPPORTED_MEDIA_TYPE); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnsupportedMediaType} based on status text. + * @param statusText the status text + */ + public UnsupportedMediaType(String statusText) { + super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnsupportedMediaType} based status text + * and response body content. + * @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 UnsupportedMediaType(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnsupportedMediaType} based on status text + * and response body content. + * @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}) + */ + public UnsupportedMediaType(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 422 Unprocessable Entity is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class UnprocessableEntity extends HttpClientErrorException { + + private static final long serialVersionUID = 147931406869809016L; + + /** + * Construct a new instance of {@code HttpClientErrorException.UnprocessableEntity}. + */ + public UnprocessableEntity() { + super(HttpStatus.UNPROCESSABLE_ENTITY); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnprocessableEntity} based on status text. + * @param statusText the status text + */ + public UnprocessableEntity(String statusText) { + super(HttpStatus.UNPROCESSABLE_ENTITY, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnprocessableEntity} based status text + * and response body content. + * @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 UnprocessableEntity(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNPROCESSABLE_ENTITY, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.UnprocessableEntity} based on status text + * and response body content. + * @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}) + */ + public UnprocessableEntity(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.UNPROCESSABLE_ENTITY, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 429 Too Many Requests is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class TooManyRequests extends HttpClientErrorException { + + private static final long serialVersionUID = -7180196215964324224L; + + /** + * Construct a new instance of {@code HttpClientErrorException.TooManyRequests}. + */ + public TooManyRequests() { + super(HttpStatus.TOO_MANY_REQUESTS); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.TooManyRequests} based on status text. + * @param statusText the status text + */ + public TooManyRequests(String statusText) { + super(HttpStatus.TOO_MANY_REQUESTS, statusText); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.TooManyRequests} based status text + * and response body content. + * @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 TooManyRequests(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.TOO_MANY_REQUESTS, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpClientErrorException.TooManyRequests} based on status text + * and response body content. + * @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}) + */ + public TooManyRequests(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.TOO_MANY_REQUESTS, 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 128b371621857df35e6d099817dd9597bc6ab9ff..e627f82a78f96cfa31e789e8ed7c8b188b1364c6 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 @@ -84,4 +84,255 @@ public class HttpServerErrorException extends HttpStatusCodeException { super(statusCode, statusText, responseHeaders, responseBody, responseCharset); } + /** + * Exception thrown when an HTTP 500 Internal Server Error is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class InternalServerError extends HttpServerErrorException { + + private static final long serialVersionUID = -9078091996219553426L; + + /** + * Construct a new instance of {@code HttpServerErrorException.InternalServerError}. + */ + public InternalServerError() { + super(HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.InternalServerError} based on status text. + * @param statusText the status text + */ + public InternalServerError(String statusText) { + super(HttpStatus.INTERNAL_SERVER_ERROR, statusText); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.InternalServerError} based status text + * and response body content. + * @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 InternalServerError(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.INTERNAL_SERVER_ERROR, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.InternalServerError} based on status text + * and response body content. + * @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}) + */ + public InternalServerError(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.INTERNAL_SERVER_ERROR, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 501 Not Implemented is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class NotImplemented extends HttpServerErrorException { + + private static final long serialVersionUID = -8858888941453536625L; + + /** + * Construct a new instance of {@code HttpServerErrorException.NotImplemented}. + */ + public NotImplemented() { + super(HttpStatus.NOT_IMPLEMENTED); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.NotImplemented} based on status text. + * @param statusText the status text + */ + public NotImplemented(String statusText) { + super(HttpStatus.NOT_IMPLEMENTED, statusText); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.NotImplemented} based status text + * and response body content. + * @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 NotImplemented(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_IMPLEMENTED, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.NotImplemented} based on status text + * and response body content. + * @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}) + */ + public NotImplemented(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.NOT_IMPLEMENTED, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + + /** + * Exception thrown when an HTTP 502 Bad Gateway is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class BadGateway extends HttpServerErrorException { + + private static final long serialVersionUID = -8989300848677585487L; + + /** + * Construct a new instance of {@code HttpServerErrorException.BadGateway}. + */ + public BadGateway() { + super(HttpStatus.BAD_GATEWAY); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.BadGateway} based on status text. + * @param statusText the status text + */ + public BadGateway(String statusText) { + super(HttpStatus.BAD_GATEWAY, statusText); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.BadGateway} based status text + * and response body content. + * @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 BadGateway(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.BAD_GATEWAY, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.BadGateway} based on status text + * and response body content. + * @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}) + */ + public BadGateway(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.BAD_GATEWAY, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 503 Service Unavailable is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class ServiceUnavailable extends HttpServerErrorException { + + private static final long serialVersionUID = 8777931838369402139L; + + /** + * Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable}. + */ + public ServiceUnavailable() { + super(HttpStatus.SERVICE_UNAVAILABLE); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based on status text. + * @param statusText the status text + */ + public ServiceUnavailable(String statusText) { + super(HttpStatus.SERVICE_UNAVAILABLE, statusText); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based status text + * and response body content. + * @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 ServiceUnavailable(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.SERVICE_UNAVAILABLE, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based on status text + * and response body content. + * @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}) + */ + public ServiceUnavailable(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.SERVICE_UNAVAILABLE, statusText, responseHeaders, responseBody, responseCharset); + } + + } + + /** + * Exception thrown when an HTTP 504 Gateway Timeout is received. + * + * @since 5.1 + * @see DefaultResponseErrorHandler + */ + public static class GatewayTimeout extends HttpServerErrorException { + + private static final long serialVersionUID = -7460116254256085095L; + + /** + * Construct a new instance of {@code HttpServerErrorException.GatewayTimeout}. + */ + public GatewayTimeout() { + super(HttpStatus.GATEWAY_TIMEOUT); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based on status text. + * @param statusText the status text + */ + public GatewayTimeout(String statusText) { + super(HttpStatus.GATEWAY_TIMEOUT, statusText); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based status text + * and response body content. + * @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 GatewayTimeout(String statusText, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.GATEWAY_TIMEOUT, statusText, responseBody, responseCharset); + } + + /** + * Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based on status text + * and response body content. + * @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}) + */ + public GatewayTimeout(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) { + super(HttpStatus.GATEWAY_TIMEOUT, statusText, responseHeaders, responseBody, responseCharset); + } + + } + } diff --git a/spring-web/src/test/java/org/springframework/web/client/AbstractMockWebServerTestCase.java b/spring-web/src/test/java/org/springframework/web/client/AbstractMockWebServerTestCase.java index f756eaf2e3d0c5c522ad72808d745e6dcb059be6..7d73035231cadde831e71eb287c3f838aef09754 100644 --- a/spring-web/src/test/java/org/springframework/web/client/AbstractMockWebServerTestCase.java +++ b/spring-web/src/test/java/org/springframework/web/client/AbstractMockWebServerTestCase.java @@ -241,6 +241,9 @@ public class AbstractMockWebServerTestCase { else if (request.getPath().equals("/status/notfound")) { return new MockResponse().setResponseCode(404); } + else if (request.getPath().equals("/status/badrequest")) { + return new MockResponse().setResponseCode(400); + } else if (request.getPath().equals("/status/server")) { return new MockResponse().setResponseCode(500); } diff --git a/spring-web/src/test/java/org/springframework/web/client/DefaultReponseHanderSpecificErrorsTests.java b/spring-web/src/test/java/org/springframework/web/client/DefaultReponseHanderSpecificErrorsTests.java new file mode 100644 index 0000000000000000000000000000000000000000..73a006e07434f70c8f1ebd30cfb40603a8a86c91 --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/client/DefaultReponseHanderSpecificErrorsTests.java @@ -0,0 +1,77 @@ +package org.springframework.web.client; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpResponse; + +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.mock; +import static org.springframework.http.HttpStatus.*; + +@RunWith(Parameterized.class) +public class DefaultReponseHanderSpecificErrorsTests { + + @Parameters(name = "error: [{0}], exception: [{1}]") + public static Object[][] errorCodes() { + return new Object[][]{ + // 4xx + {BAD_REQUEST, HttpClientErrorException.BadRequest.class}, + {UNAUTHORIZED, HttpClientErrorException.Unauthorized.class}, + {FORBIDDEN, HttpClientErrorException.Forbidden.class}, + {NOT_FOUND, HttpClientErrorException.NotFound.class}, + {METHOD_NOT_ALLOWED, HttpClientErrorException.MethodNotAllowed.class}, + {NOT_ACCEPTABLE, HttpClientErrorException.NotAcceptable.class}, + {CONFLICT, HttpClientErrorException.Conflict.class}, + {TOO_MANY_REQUESTS, HttpClientErrorException.TooManyRequests.class}, + {UNPROCESSABLE_ENTITY, HttpClientErrorException.UnprocessableEntity.class}, + {I_AM_A_TEAPOT, HttpClientErrorException.class}, + // 5xx + {INTERNAL_SERVER_ERROR, HttpServerErrorException.InternalServerError.class}, + {NOT_IMPLEMENTED, HttpServerErrorException.NotImplemented.class}, + {BAD_GATEWAY, HttpServerErrorException.BadGateway.class}, + {SERVICE_UNAVAILABLE, HttpServerErrorException.ServiceUnavailable.class}, + {GATEWAY_TIMEOUT, HttpServerErrorException.GatewayTimeout.class}, + {HTTP_VERSION_NOT_SUPPORTED, HttpServerErrorException.class} + }; + } + + @Parameterized.Parameter + public HttpStatus httpStatus; + + @Parameterized.Parameter(1) + public Class expectedExceptionClass; + + private final DefaultResponseErrorHandler handler = new DefaultResponseErrorHandler(); + + private final ClientHttpResponse response = mock(ClientHttpResponse.class); + + @Test + public void handleErrorIOException() throws Exception { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.TEXT_PLAIN); + + given(response.getRawStatusCode()).willReturn(httpStatus.value()); + given(response.getHeaders()).willReturn(headers); + + try { + handler.handleError(response); + fail("expected " + expectedExceptionClass.getSimpleName()); + } + catch (HttpStatusCodeException ex) { + assertEquals("Expected " + expectedExceptionClass.getSimpleName(), expectedExceptionClass, ex.getClass()); + } + } + + @Test + public void hasErrorTrue() throws Exception { + given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); + assertTrue(handler.hasError(response)); + } + +} diff --git a/spring-web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java b/spring-web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java index ad4c61d98987812ca9590fa8cb91a7b96da2a97d..e81e10f9babdbf1e2fd85a1185844274f7e84e1b 100644 --- a/spring-web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java @@ -180,6 +180,18 @@ public class RestTemplateIntegrationTests extends AbstractMockWebServerTestCase } } + @Test + public void badRequest() { + try { + template.execute(baseUrl + "/status/badrequest", HttpMethod.GET, null, null); + fail("HttpClientErrorException.BadRequest expected"); + } + catch (HttpClientErrorException.BadRequest ex) { + assertEquals(HttpStatus.BAD_REQUEST, ex.getStatusCode()); + assertEquals("400 Client Error", ex.getMessage()); + } + } + @Test public void serverError() { try {