Browse Source

Optimize WebClientUtils

Use constant Predicate for exception wrapping.
Use ResponseEntity constructor instead of builder.

See gh-26069
pull/26087/head
Rossen Stoyanchev 4 years ago
parent
commit
ba9325446c
  1. 15
      spring-web/src/main/java/org/springframework/http/ResponseEntity.java
  2. 30
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java
  3. 2
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunctions.java
  4. 27
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClientUtils.java

15
spring-web/src/main/java/org/springframework/http/ResponseEntity.java

@ -113,9 +113,18 @@ public class ResponseEntity<T> extends HttpEntity<T> { @@ -113,9 +113,18 @@ public class ResponseEntity<T> extends HttpEntity<T> {
* @param status the status code
*/
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.status = status;
this(body, headers, (Object) status);
}
/**
* Create a new {@code HttpEntity} with the given body, headers, and status code.
* @param body the entity body
* @param headers the entity headers
* @param rawStatus the status code value
* @since 5.3.2
*/
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, int rawStatus) {
this(body, headers, (Object) rawStatus);
}
/**

30
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java

@ -543,16 +543,10 @@ class DefaultWebClient implements WebClient { @@ -543,16 +543,10 @@ class DefaultWebClient implements WebClient {
return this.responseMono.flatMap(response -> handleBodyMono(response, response.bodyToMono(elementTypeRef)));
}
private <T> Mono<T> handleBodyMono(ClientResponse response, Mono<T> bodyPublisher) {
private <T> Mono<T> handleBodyMono(ClientResponse response, Mono<T> body) {
body = body.onErrorResume(WebClientUtils.WRAP_EXCEPTION_PREDICATE, exceptionWrappingFunction(response));
Mono<T> result = statusHandlers(response);
Mono<T> wrappedExceptions = bodyPublisher.onErrorResume(WebClientUtils::shouldWrapException,
t -> wrapException(t, response));
if (result != null) {
return result.switchIfEmpty(wrappedExceptions);
}
else {
return wrappedExceptions;
}
return (result != null ? result.switchIfEmpty(body) : body);
}
@Override
@ -567,16 +561,10 @@ class DefaultWebClient implements WebClient { @@ -567,16 +561,10 @@ class DefaultWebClient implements WebClient {
return this.responseMono.flatMapMany(response -> handleBodyFlux(response, response.bodyToFlux(elementTypeRef)));
}
private <T> Publisher<T> handleBodyFlux(ClientResponse response, Flux<T> bodyPublisher) {
private <T> Publisher<T> handleBodyFlux(ClientResponse response, Flux<T> body) {
body = body.onErrorResume(WebClientUtils.WRAP_EXCEPTION_PREDICATE, exceptionWrappingFunction(response));
Mono<T> result = statusHandlers(response);
Flux<T> wrappedExceptions = bodyPublisher.onErrorResume(WebClientUtils::shouldWrapException,
t -> wrapException(t, response));
if (result != null) {
return result.flux().switchIfEmpty(wrappedExceptions);
}
else {
return wrappedExceptions;
}
return (result != null ? result.flux().switchIfEmpty(body) : body);
}
@Nullable
@ -608,10 +596,8 @@ class DefaultWebClient implements WebClient { @@ -608,10 +596,8 @@ class DefaultWebClient implements WebClient {
return result.checkpoint(description);
}
private <T> Mono<T> wrapException(Throwable throwable, ClientResponse response) {
return response.createException()
.map(responseException -> responseException.initCause(throwable))
.flatMap(Mono::error);
private <T> Function<Throwable, Mono<? extends T>> exceptionWrappingFunction(ClientResponse response) {
return t -> response.createException().flatMap(ex -> Mono.error(ex.initCause(t)));
}
@Override

2
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ExchangeFunctions.java

@ -104,7 +104,7 @@ public abstract class ExchangeFunctions { @@ -104,7 +104,7 @@ public abstract class ExchangeFunctions {
.connect(httpMethod, url, httpRequest -> clientRequest.writeTo(httpRequest, this.strategies))
.doOnRequest(n -> logRequest(clientRequest))
.doOnCancel(() -> logger.debug(logPrefix + "Cancel signal (to close connection)"))
.onErrorResume(WebClientUtils::shouldWrapException, t -> wrapException(t, clientRequest))
.onErrorResume(WebClientUtils.WRAP_EXCEPTION_PREDICATE, t -> wrapException(t, clientRequest))
.map(httpResponse -> {
logResponse(httpResponse, logPrefix);
return new DefaultClientResponse(

27
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClientUtils.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.web.reactive.function.client;
import java.util.List;
import java.util.function.Predicate;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@ -26,7 +27,8 @@ import org.springframework.core.codec.CodecException; @@ -26,7 +27,8 @@ import org.springframework.core.codec.CodecException;
import org.springframework.http.ResponseEntity;
/**
* Internal methods shared between {@link DefaultWebClient} and {@link DefaultClientResponse}.
* Internal methods shared between {@link DefaultWebClient} and
* {@link DefaultClientResponse}.
*
* @author Arjen Poutsma
* @since 5.2
@ -35,6 +37,12 @@ abstract class WebClientUtils { @@ -35,6 +37,12 @@ abstract class WebClientUtils {
private static final String VALUE_NONE = "\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n";
/**
* Predicate that returns true if an exception should be wrapped.
*/
public final static Predicate<? super Throwable> WRAP_EXCEPTION_PREDICATE =
t -> !(t instanceof WebClientException) && !(t instanceof CodecException);
/**
* Map the given response to a single value {@code ResponseEntity<T>}.
@ -42,9 +50,10 @@ abstract class WebClientUtils { @@ -42,9 +50,10 @@ abstract class WebClientUtils {
@SuppressWarnings("unchecked")
public static <T> Mono<ResponseEntity<T>> mapToEntity(ClientResponse response, Mono<T> bodyMono) {
return ((Mono<Object>) bodyMono).defaultIfEmpty(VALUE_NONE).map(body ->
ResponseEntity.status(response.rawStatusCode())
.headers(response.headers().asHttpHeaders())
.body(body != VALUE_NONE ? (T) body : null));
new ResponseEntity<>(
body != VALUE_NONE ? (T) body : null,
response.headers().asHttpHeaders(),
response.rawStatusCode()));
}
/**
@ -52,15 +61,7 @@ abstract class WebClientUtils { @@ -52,15 +61,7 @@ abstract class WebClientUtils {
*/
public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse response, Publisher<T> body) {
return Flux.from(body).collectList().map(list ->
ResponseEntity.status(response.rawStatusCode())
.headers(response.headers().asHttpHeaders())
.body(list));
new ResponseEntity<>(list, response.headers().asHttpHeaders(), response.rawStatusCode()));
}
/**
* Indicates whether the given exception should be wrapped.
*/
public static boolean shouldWrapException(Throwable t) {
return !(t instanceof WebClientException) && !(t instanceof CodecException);
}
}

Loading…
Cancel
Save