Hierarchy under WebClientResponseException

Issue: SPR-17145
This commit is contained in:
Rossen Stoyanchev 2018-08-08 14:07:01 +03:00
parent c90ab5fb0a
commit a0dfdfcac3
3 changed files with 267 additions and 16 deletions

View File

@ -463,9 +463,7 @@ class DefaultWebClient implements WebClient {
.map(MimeType::getCharset)
.orElse(StandardCharsets.ISO_8859_1);
if (HttpStatus.resolve(response.rawStatusCode()) != null) {
String msg = String.format("ClientResponse has erroneous status code: %d %s",
response.statusCode().value(), response.statusCode().getReasonPhrase());
return new WebClientResponseException(msg,
return WebClientResponseException.create(
response.statusCode().value(),
response.statusCode().getReasonPhrase(),
response.headers().asHttpHeaders(),

View File

@ -46,25 +46,28 @@ public class WebClientResponseException extends WebClientException {
/**
* Construct a new instance of with the given response data.
* @param message the exception message
* @param statusCode the raw status code value
* @param statusText the status text
* @param headers 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})
* Constructor with response data only, and a default message.
* @since 5.1
*/
public WebClientResponseException(int statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) {
this(statusCode + " " + statusText, statusCode, statusText, headers, body, charset);
}
/**
* Constructor with a prepared message.
*/
public WebClientResponseException(String message, int statusCode, String statusText,
@Nullable HttpHeaders headers, @Nullable byte[] responseBody,
@Nullable Charset responseCharset) {
@Nullable HttpHeaders headers, @Nullable byte[] responsebody, @Nullable Charset charset) {
super(message);
this.statusCode = statusCode;
this.statusText = statusText;
this.headers = (headers != null ? headers : HttpHeaders.EMPTY);
this.responseBody = (responseBody != null ? responseBody : new byte[0]);
this.responseCharset = (responseCharset != null ? responseCharset : StandardCharsets.ISO_8859_1);
this.responseBody = (responsebody != null ? responsebody : new byte[0]);
this.responseCharset = (charset != null ? charset : StandardCharsets.ISO_8859_1);
}
@ -111,4 +114,252 @@ public class WebClientResponseException extends WebClientException {
return new String(this.responseBody, this.responseCharset);
}
/**
* Create {@code WebClientResponseException} or an HTTP status specific sub-class.
* @since 5.1
*/
public static WebClientResponseException create(
int statusCode, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
HttpStatus httpStatus = HttpStatus.resolve(statusCode);
if (httpStatus != null) {
switch (httpStatus) {
case BAD_REQUEST:
return new WebClientResponseException.BadRequest(statusText, headers, body, charset);
case UNAUTHORIZED:
return new WebClientResponseException.Unauthorized(statusText, headers, body, charset);
case FORBIDDEN:
return new WebClientResponseException.Forbidden(statusText, headers, body, charset);
case NOT_FOUND:
return new WebClientResponseException.NotFound(statusText, headers, body, charset);
case METHOD_NOT_ALLOWED:
return new WebClientResponseException.MethodNotAllowed(statusText, headers, body, charset);
case NOT_ACCEPTABLE:
return new WebClientResponseException.NotAcceptable(statusText, headers, body, charset);
case CONFLICT:
return new WebClientResponseException.Conflict(statusText, headers, body, charset);
case GONE:
return new WebClientResponseException.Gone(statusText, headers, body, charset);
case UNSUPPORTED_MEDIA_TYPE:
return new WebClientResponseException.UnsupportedMediaType(statusText, headers, body, charset);
case TOO_MANY_REQUESTS:
return new WebClientResponseException.TooManyRequests(statusText, headers, body, charset);
case UNPROCESSABLE_ENTITY:
return new WebClientResponseException.UnprocessableEntity(statusText, headers, body, charset);
case INTERNAL_SERVER_ERROR:
return new WebClientResponseException.InternalServerError(statusText, headers, body, charset);
case NOT_IMPLEMENTED:
return new WebClientResponseException.NotImplemented(statusText, headers, body, charset);
case BAD_GATEWAY:
return new WebClientResponseException.BadGateway(statusText, headers, body, charset);
case SERVICE_UNAVAILABLE:
return new WebClientResponseException.ServiceUnavailable(statusText, headers, body, charset);
case GATEWAY_TIMEOUT:
return new WebClientResponseException.GatewayTimeout(statusText, headers, body, charset);
}
}
return new WebClientResponseException(statusCode, statusText, headers, body, charset);
}
// Sub-classes for specific, client-side, HTTP status codes..
/**
* {@link WebClientResponseException} for status HTTP 400 Bad Request.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class BadRequest extends WebClientResponseException {
BadRequest(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.BAD_REQUEST.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 401 Unauthorized.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class Unauthorized extends WebClientResponseException {
Unauthorized(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNAUTHORIZED.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 403 Forbidden.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class Forbidden extends WebClientResponseException {
Forbidden(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.FORBIDDEN.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 404 Not Found.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class NotFound extends WebClientResponseException {
NotFound(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_FOUND.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 405 Method Not Allowed.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class MethodNotAllowed extends WebClientResponseException {
MethodNotAllowed(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.METHOD_NOT_ALLOWED.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 406 Not Acceptable.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class NotAcceptable extends WebClientResponseException {
NotAcceptable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_ACCEPTABLE.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 409 Conflict.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class Conflict extends WebClientResponseException {
Conflict(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.CONFLICT.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 410 Gone.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class Gone extends WebClientResponseException {
Gone(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.GONE.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 415 Unsupported Media Type.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class UnsupportedMediaType extends WebClientResponseException {
UnsupportedMediaType(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 422 Unprocessable Entity.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class UnprocessableEntity extends WebClientResponseException {
UnprocessableEntity(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNPROCESSABLE_ENTITY.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 429 Too Many Requests.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class TooManyRequests extends WebClientResponseException {
TooManyRequests(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.TOO_MANY_REQUESTS.value(), statusText, headers, body, charset);
}
}
// Sub-classes for specific, server-side, HTTP status codes..
/**
* {@link WebClientResponseException} for status HTTP 500 Internal Server Error.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class InternalServerError extends WebClientResponseException {
InternalServerError(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.INTERNAL_SERVER_ERROR.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 501 Not Implemented.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class NotImplemented extends WebClientResponseException {
NotImplemented(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_IMPLEMENTED.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP HTTP 502 Bad Gateway.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class BadGateway extends WebClientResponseException {
BadGateway(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.BAD_GATEWAY.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 503 Service Unavailable.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class ServiceUnavailable extends WebClientResponseException {
ServiceUnavailable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.SERVICE_UNAVAILABLE.value(), statusText, headers, body, charset);
}
}
/**
* {@link WebClientResponseException} for status HTTP 504 Gateway Timeout.
* @since 5.1
*/
@SuppressWarnings("serial")
public static class GatewayTimeout extends WebClientResponseException {
GatewayTimeout(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.GATEWAY_TIMEOUT.value(), statusText, headers, body, charset);
}
}
}

View File

@ -60,8 +60,10 @@ You can also get a stream of objects decoded from the response:
.bodyToFlux(Quote.class);
----
By default, responses with 4xx or 5xx status codes result in an error of type
`WebClientResponseException` but you can customize that:
By default, responses with 4xx or 5xx status codes result in an
`WebClientResponseException` or one of its HTTP status specific sub-classes such as
`WebClientResponseException.BadRequest`, `WebClientResponseException.NotFound`, and others.
You can also use the `onStatus` method to customize the resulting exception:
[source,java,intent=0]
[subs="verbatim,quotes"]