Re-order methods and polishing
In StatusHandler and DefaultConvertibleClientHttpResponse. See gh-35391
This commit is contained in:
parent
a585beac49
commit
21e6d7392d
|
@ -775,7 +775,7 @@ final class DefaultRestClient implements RestClient {
|
|||
DefaultResponseSpec(RequestHeadersSpec<?> requestHeadersSpec) {
|
||||
this.requestHeadersSpec = requestHeadersSpec;
|
||||
this.statusHandlers.addAll(DefaultRestClient.this.defaultStatusHandlers);
|
||||
this.statusHandlers.add(StatusHandler.defaultHandler(DefaultRestClient.this.messageConverters));
|
||||
this.statusHandlers.add(StatusHandler.createDefaultStatusHandler(DefaultRestClient.this.messageConverters));
|
||||
this.defaultStatusHandlerCount = this.statusHandlers.size();
|
||||
}
|
||||
|
||||
|
@ -886,7 +886,10 @@ final class DefaultRestClient implements RestClient {
|
|||
return this.requestHeadersSpec.exchange(exchangeFunction);
|
||||
}
|
||||
|
||||
private <T> @Nullable T readBody(HttpRequest request, ClientHttpResponse response, Type bodyType, Class<T> bodyClass, @Nullable Map<String, Object> hints) {
|
||||
private <T> @Nullable T readBody(
|
||||
HttpRequest request, ClientHttpResponse response, Type bodyType, Class<T> bodyClass,
|
||||
@Nullable Map<String, Object> hints) {
|
||||
|
||||
return DefaultRestClient.this.readWithMessageConverters(
|
||||
response, () -> applyStatusHandlers(request, response), bodyType, bodyClass, hints);
|
||||
|
||||
|
@ -922,28 +925,6 @@ final class DefaultRestClient implements RestClient {
|
|||
this.hints = hints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T bodyTo(Class<T> bodyType) {
|
||||
return readWithMessageConverters(this.delegate, () -> {} , bodyType, bodyType, this.hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T bodyTo(ParameterizedTypeReference<T> bodyType) {
|
||||
Type type = bodyType.getType();
|
||||
Class<T> bodyClass = bodyClass(type);
|
||||
return readWithMessageConverters(this.delegate, () -> {}, type, bodyClass, this.hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.delegate.getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return this.delegate.getHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatusCode getStatusCode() throws IOException {
|
||||
return this.delegate.getStatusCode();
|
||||
|
@ -954,10 +935,32 @@ final class DefaultRestClient implements RestClient {
|
|||
return this.delegate.getStatusText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return this.delegate.getHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.delegate.getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.delegate.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T bodyTo(Class<T> bodyType) {
|
||||
return readWithMessageConverters(this.delegate, () -> {} , bodyType, bodyType, this.hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T bodyTo(ParameterizedTypeReference<T> bodyType) {
|
||||
Type type = bodyType.getType();
|
||||
Class<T> bodyClass = bodyClass(type);
|
||||
return readWithMessageConverters(this.delegate, () -> {}, type, bodyClass, this.hints);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,68 +39,122 @@ import org.springframework.util.CollectionUtils;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Used by {@link DefaultRestClient} and {@link DefaultRestClientBuilder}.
|
||||
* Simple container for an error response Predicate and an error response handler
|
||||
* to support the status handling mechanism of {@link RestClient.ResponseSpec}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 6.1
|
||||
*/
|
||||
final class StatusHandler {
|
||||
|
||||
private final ResponsePredicate predicate;
|
||||
|
||||
private final RestClient.ResponseSpec.ErrorHandler errorHandler;
|
||||
private final RestClient.ResponseSpec.ErrorHandler handler;
|
||||
|
||||
|
||||
private StatusHandler(ResponsePredicate predicate, RestClient.ResponseSpec.ErrorHandler errorHandler) {
|
||||
private StatusHandler(ResponsePredicate predicate, RestClient.ResponseSpec.ErrorHandler handler) {
|
||||
this.predicate = predicate;
|
||||
this.errorHandler = errorHandler;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
|
||||
public static StatusHandler of(Predicate<HttpStatusCode> predicate,
|
||||
RestClient.ResponseSpec.ErrorHandler errorHandler) {
|
||||
/**
|
||||
* Test whether the response has any errors.
|
||||
*/
|
||||
public boolean test(ClientHttpResponse response) throws IOException {
|
||||
return this.predicate.test(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the error in the given response.
|
||||
* <p>This method is only called when {@link #test(ClientHttpResponse)}
|
||||
* has returned {@code true}.
|
||||
ß */
|
||||
public void handle(HttpRequest request, ClientHttpResponse response) throws IOException {
|
||||
this.handler.handle(request, response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a StatusHandler from a RestClient {@link RestClient.ResponseSpec.ErrorHandler}.
|
||||
*/
|
||||
public static StatusHandler of(
|
||||
Predicate<HttpStatusCode> predicate, RestClient.ResponseSpec.ErrorHandler errorHandler) {
|
||||
|
||||
Assert.notNull(predicate, "Predicate must not be null");
|
||||
Assert.notNull(errorHandler, "ErrorHandler must not be null");
|
||||
|
||||
return new StatusHandler(response -> predicate.test(response.getStatusCode()), errorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a StatusHandler from a {@link ResponseErrorHandler}.
|
||||
*/
|
||||
public static StatusHandler fromErrorHandler(ResponseErrorHandler errorHandler) {
|
||||
Assert.notNull(errorHandler, "ResponseErrorHandler must not be null");
|
||||
|
||||
return new StatusHandler(errorHandler::hasError, (request, response) ->
|
||||
errorHandler.handleError(request.getURI(), request.getMethod(), response));
|
||||
return new StatusHandler(errorHandler::hasError,
|
||||
(request, response) -> errorHandler.handleError(request.getURI(), request.getMethod(), response));
|
||||
}
|
||||
|
||||
public static StatusHandler defaultHandler(List<HttpMessageConverter<?>> messageConverters) {
|
||||
/**
|
||||
* Create a StatusHandler for default error response handling.
|
||||
*/
|
||||
public static StatusHandler createDefaultStatusHandler(List<HttpMessageConverter<?>> converters) {
|
||||
return new StatusHandler(response -> response.getStatusCode().isError(),
|
||||
(request, response) -> {
|
||||
HttpStatusCode statusCode = response.getStatusCode();
|
||||
String statusText = response.getStatusText();
|
||||
HttpHeaders headers = response.getHeaders();
|
||||
byte[] body = RestClientUtils.getBody(response);
|
||||
Charset charset = RestClientUtils.getCharset(response);
|
||||
String message = getErrorMessage(statusCode.value(), statusText, body, charset);
|
||||
RestClientResponseException ex;
|
||||
|
||||
if (statusCode.is4xxClientError()) {
|
||||
ex = HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
|
||||
}
|
||||
else if (statusCode.is5xxServerError()) {
|
||||
ex = HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
|
||||
}
|
||||
else {
|
||||
ex = new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(messageConverters)) {
|
||||
ex.setBodyConvertFunction(initBodyConvertFunction(response, body, messageConverters));
|
||||
}
|
||||
throw ex;
|
||||
throw createException(response, converters);
|
||||
});
|
||||
}
|
||||
|
||||
private static RestClientResponseException createException(
|
||||
ClientHttpResponse response, List<HttpMessageConverter<?>> converters) throws IOException {
|
||||
|
||||
HttpStatusCode statusCode = response.getStatusCode();
|
||||
String statusText = response.getStatusText();
|
||||
HttpHeaders headers = response.getHeaders();
|
||||
byte[] body = RestClientUtils.getBody(response);
|
||||
Charset charset = RestClientUtils.getCharset(response);
|
||||
String message = getErrorMessage(statusCode.value(), statusText, body, charset);
|
||||
RestClientResponseException ex;
|
||||
|
||||
if (statusCode.is4xxClientError()) {
|
||||
ex = HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
|
||||
}
|
||||
else if (statusCode.is5xxServerError()) {
|
||||
ex = HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
|
||||
}
|
||||
else {
|
||||
ex = new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(converters)) {
|
||||
ex.setBodyConvertFunction(initBodyConvertFunction(response, body, converters));
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
private static String getErrorMessage(
|
||||
int rawStatusCode, String statusText, byte @Nullable [] responseBody, @Nullable Charset charset) {
|
||||
|
||||
String preface = rawStatusCode + " " + statusText + ": ";
|
||||
|
||||
if (ObjectUtils.isEmpty(responseBody)) {
|
||||
return preface + "[no body]";
|
||||
}
|
||||
|
||||
charset = (charset != null ? charset : StandardCharsets.UTF_8);
|
||||
|
||||
String bodyText = new String(responseBody, charset);
|
||||
bodyText = LogFormatUtils.formatValue(bodyText, -1, true);
|
||||
|
||||
return preface + bodyText;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private static Function<ResolvableType, ? extends @Nullable Object> initBodyConvertFunction(ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
|
||||
private static Function<ResolvableType, ? extends @Nullable Object> initBodyConvertFunction(
|
||||
ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
|
||||
|
||||
Assert.state(!CollectionUtils.isEmpty(messageConverters), "Expected message converters");
|
||||
return resolvableType -> {
|
||||
try {
|
||||
|
@ -121,34 +175,6 @@ final class StatusHandler {
|
|||
}
|
||||
|
||||
|
||||
private static String getErrorMessage(int rawStatusCode, String statusText, byte @Nullable [] responseBody,
|
||||
@Nullable Charset charset) {
|
||||
|
||||
String preface = rawStatusCode + " " + statusText + ": ";
|
||||
|
||||
if (ObjectUtils.isEmpty(responseBody)) {
|
||||
return preface + "[no body]";
|
||||
}
|
||||
|
||||
charset = (charset != null ? charset : StandardCharsets.UTF_8);
|
||||
|
||||
String bodyText = new String(responseBody, charset);
|
||||
bodyText = LogFormatUtils.formatValue(bodyText, -1, true);
|
||||
|
||||
return preface + bodyText;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean test(ClientHttpResponse response) throws IOException {
|
||||
return this.predicate.test(response);
|
||||
}
|
||||
|
||||
public void handle(HttpRequest request, ClientHttpResponse response) throws IOException {
|
||||
this.errorHandler.handle(request, response);
|
||||
}
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ResponsePredicate {
|
||||
|
||||
|
|
Loading…
Reference in New Issue