From 7794606305da37e5efbfeded67eb421208492339 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 1 Dec 2021 11:10:10 +0100 Subject: [PATCH] Add ClientResponse::createError This commit introduces ClientResponse::createError, returning a Mono that terminates with a WebClientException. Closes gh-27637 --- .../function/client/ClientResponse.java | 12 ++++++++ .../client/DefaultClientResponse.java | 5 ++++ .../client/support/ClientResponseWrapper.java | 5 ++++ .../client/DefaultClientResponseTests.java | 30 +++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java index 90384a6ede..093de96ba6 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java @@ -181,6 +181,18 @@ public interface ClientResponse { */ Mono createException(); + /** + * Create a {@code Mono} that terminates with a + * {@link WebClientResponseException}, containing the response status, + * headers, body, and the originating request. + * @param the reified type + * @return a {@code Mono} that fails with a + * {@link WebClientResponseException}. + * @see #createException() + * @since 6.0 + */ + Mono createError(); + /** * Return a log message prefix to use to correlate messages for this exchange. *

The prefix is based on {@linkplain ClientRequest#logPrefix()}, which diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java index 37f14f34ae..7e768498d2 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java @@ -223,6 +223,11 @@ class DefaultClientResponse implements ClientResponse { }); } + @Override + public Mono createError() { + return createException().flatMap(Mono::error); + } + @Override public String logPrefix() { return this.logPrefix; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/ClientResponseWrapper.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/ClientResponseWrapper.java index 3b558eeee3..e20f6ff8cb 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/ClientResponseWrapper.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/ClientResponseWrapper.java @@ -153,6 +153,11 @@ public class ClientResponseWrapper implements ClientResponse { return this.delegate.createException(); } + @Override + public Mono createError() { + return this.delegate.createError(); + } + @Override public String logPrefix() { return this.delegate.logPrefix(); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientResponseTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientResponseTests.java index f9b626a60c..9143688b17 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientResponseTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultClientResponseTests.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.codec.ByteArrayDecoder; @@ -353,6 +354,35 @@ public class DefaultClientResponseTests { assertThat(exception.getResponseBodyAsByteArray()).isEqualTo(bytes); } + @Test + public void createError() { + byte[] bytes = "foo".getBytes(StandardCharsets.UTF_8); + DefaultDataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(ByteBuffer.wrap(bytes)); + Flux body = Flux.just(dataBuffer); + httpHeaders.setContentType(MediaType.TEXT_PLAIN); + given(mockResponse.getStatusCode()).willReturn(HttpStatus.NOT_FOUND); + given(mockResponse.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value()); + given(mockResponse.getBody()).willReturn(body); + + List> messageReaders = Collections.singletonList( + new DecoderHttpMessageReader<>(new ByteArrayDecoder())); + given(mockExchangeStrategies.messageReaders()).willReturn(messageReaders); + + Mono resultMono = defaultClientResponse.createError(); + StepVerifier.create(resultMono) + .consumeErrorWith(t -> { + assertThat(t).isInstanceOf(WebClientResponseException.class); + WebClientResponseException exception = (WebClientResponseException) t; + assertThat(exception.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + assertThat(exception.getMessage()).isEqualTo("404 Not Found"); + assertThat(exception.getHeaders()).containsExactly(entry("Content-Type", + Collections.singletonList("text/plain"))); + assertThat(exception.getResponseBodyAsByteArray()).isEqualTo(bytes); + + }) + .verify(); + } + private void mockTextPlainResponse(Flux body) { httpHeaders.setContentType(MediaType.TEXT_PLAIN);