Browse Source

Consistent check for Void.class in DefaultClientResponse

Issue: SPR-16636
pull/2028/head
Juergen Hoeller 7 years ago
parent
commit
e28a995ab7
  1. 43
      spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java
  2. 34
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java

43
spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java

@ -50,13 +50,14 @@ public abstract class BodyExtractors {
private static final ResolvableType FORM_MAP_TYPE = private static final ResolvableType FORM_MAP_TYPE =
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class); ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class);
private static final ResolvableType MULTIPART_MAP_TYPE = ResolvableType.forClassWithGenerics( private static final ResolvableType MULTIPART_MAP_TYPE =
MultiValueMap.class, String.class, Part.class); ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
private static final ResolvableType PART_TYPE = ResolvableType.forClass(Part.class); private static final ResolvableType PART_TYPE = ResolvableType.forClass(Part.class);
private static final ResolvableType VOID_TYPE = ResolvableType.forClass(Void.class); private static final ResolvableType VOID_TYPE = ResolvableType.forClass(Void.class);
/** /**
* Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}. * Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}.
* @param elementClass the class of element in the {@code Mono} * @param elementClass the class of element in the {@code Mono}
@ -69,8 +70,9 @@ public abstract class BodyExtractors {
/** /**
* Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}. * Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}.
* The given {@link ParameterizedTypeReference} is used to pass generic type information, for * The given {@link ParameterizedTypeReference} is used to pass generic type
* instance when using the {@link org.springframework.web.reactive.function.client.WebClient WebClient} * information, for instance when using the
* {@link org.springframework.web.reactive.function.client.WebClient WebClient}:
* <pre class="code"> * <pre class="code">
* Mono&lt;Map&lt;String, String&gt;&gt; body = this.webClient * Mono&lt;Map&lt;String, String&gt;&gt; body = this.webClient
* .get() * .get()
@ -118,8 +120,9 @@ public abstract class BodyExtractors {
/** /**
* Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}. * Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}.
* The given {@link ParameterizedTypeReference} is used to pass generic type information, for * <p>The given {@link ParameterizedTypeReference} is used to pass generic type
* instance when using the {@link org.springframework.web.reactive.function.client.WebClient WebClient} * information, for instance when using the
* {@link org.springframework.web.reactive.function.client.WebClient WebClient}:
* <pre class="code"> * <pre class="code">
* Flux&lt;ServerSentEvent&lt;String&gt;&gt; body = this.webClient * Flux&lt;ServerSentEvent&lt;String&gt;&gt; body = this.webClient
* .get() * .get()
@ -167,9 +170,7 @@ public abstract class BodyExtractors {
* Return a {@code BodyExtractor} that reads form data into a {@link MultiValueMap}. * Return a {@code BodyExtractor} that reads form data into a {@link MultiValueMap}.
* @return a {@code BodyExtractor} that reads form data * @return a {@code BodyExtractor} that reads form data
*/ */
// Note that the returned BodyExtractor is parameterized to ServerHttpRequest, not // Parameterized for server-side use
// ReactiveHttpInputMessage like other methods, since reading form data only typically happens on
// the server-side
public static BodyExtractor<Mono<MultiValueMap<String, String>>, ServerHttpRequest> toFormData() { public static BodyExtractor<Mono<MultiValueMap<String, String>>, ServerHttpRequest> toFormData() {
return (request, context) -> { return (request, context) -> {
ResolvableType type = FORM_MAP_TYPE; ResolvableType type = FORM_MAP_TYPE;
@ -182,13 +183,11 @@ public abstract class BodyExtractors {
} }
/** /**
* Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data into a * Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data
* {@link MultiValueMap}. * into a {@link MultiValueMap}.
* @return a {@code BodyExtractor} that reads multipart data * @return a {@code BodyExtractor} that reads multipart data
*/ */
// Note that the returned BodyExtractor is parameterized to ServerHttpRequest, not // Parameterized for server-side use
// ReactiveHttpInputMessage like other methods, since reading form data only typically happens on
// the server-side
public static BodyExtractor<Mono<MultiValueMap<String, Part>>, ServerHttpRequest> toMultipartData() { public static BodyExtractor<Mono<MultiValueMap<String, Part>>, ServerHttpRequest> toMultipartData() {
return (serverRequest, context) -> { return (serverRequest, context) -> {
ResolvableType type = MULTIPART_MAP_TYPE; ResolvableType type = MULTIPART_MAP_TYPE;
@ -201,13 +200,11 @@ public abstract class BodyExtractors {
} }
/** /**
* Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data into a * Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data
* {@link MultiValueMap}. * into a {@link MultiValueMap}.
* @return a {@code BodyExtractor} that reads multipart data * @return a {@code BodyExtractor} that reads multipart data
*/ */
// Note that the returned BodyExtractor is parameterized to ServerHttpRequest, not // Parameterized for server-side use
// ReactiveHttpInputMessage like other methods, since reading form data only typically happens on
// the server-side
public static BodyExtractor<Flux<Part>, ServerHttpRequest> toParts() { public static BodyExtractor<Flux<Part>, ServerHttpRequest> toParts() {
return (serverRequest, context) -> { return (serverRequest, context) -> {
ResolvableType type = PART_TYPE; ResolvableType type = PART_TYPE;
@ -219,10 +216,10 @@ public abstract class BodyExtractors {
} }
/** /**
* Return a {@code BodyExtractor} that returns the body of the message as a {@link Flux} of * Return a {@code BodyExtractor} that returns the body of the message as a {@link Flux}
* {@link DataBuffer}s. * of {@link DataBuffer}s.
* <p><strong>Note</strong> that the returned buffers should be released after usage by calling * <p><strong>Note</strong> that the returned buffers should be released after usage by
* {@link org.springframework.core.io.buffer.DataBufferUtils#release(DataBuffer)} * calling {@link org.springframework.core.io.buffer.DataBufferUtils#release(DataBuffer)}.
* @return a {@code BodyExtractor} that returns the body * @return a {@code BodyExtractor} that returns the body
* @see ReactiveHttpInputMessage#getBody() * @see ReactiveHttpInputMessage#getBody()
*/ */

34
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java

@ -102,7 +102,7 @@ class DefaultClientResponse implements ClientResponse {
@Override @Override
public <T> Mono<T> bodyToMono(Class<? extends T> elementClass) { public <T> Mono<T> bodyToMono(Class<? extends T> elementClass) {
if (Void.class.isAssignableFrom(elementClass)) { if (Void.class == elementClass) {
return consumeAndCancel(); return consumeAndCancel();
} }
else { else {
@ -110,20 +110,9 @@ class DefaultClientResponse implements ClientResponse {
} }
} }
@SuppressWarnings("unchecked")
private <T> Mono<T> consumeAndCancel() {
return (Mono<T>) this.response.getBody()
.map(buffer -> {
DataBufferUtils.release(buffer);
throw new ReadCancellationException();
})
.onErrorResume(ReadCancellationException.class, ex -> Mono.empty())
.then();
}
@Override @Override
public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) { public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) {
if (Void.class.isAssignableFrom(typeReference.getType().getClass())) { if (Void.class == typeReference.getType()) {
return consumeAndCancel(); return consumeAndCancel();
} }
else { else {
@ -133,7 +122,7 @@ class DefaultClientResponse implements ClientResponse {
@Override @Override
public <T> Flux<T> bodyToFlux(Class<? extends T> elementClass) { public <T> Flux<T> bodyToFlux(Class<? extends T> elementClass) {
if (Void.class.isAssignableFrom(elementClass)) { if (Void.class == elementClass) {
return Flux.from(consumeAndCancel()); return Flux.from(consumeAndCancel());
} }
else { else {
@ -143,7 +132,7 @@ class DefaultClientResponse implements ClientResponse {
@Override @Override
public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) { public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) {
if (Void.class.isAssignableFrom(typeReference.getType().getClass())) { if (Void.class == typeReference.getType()) {
return Flux.from(consumeAndCancel()); return Flux.from(consumeAndCancel());
} }
else { else {
@ -153,7 +142,7 @@ class DefaultClientResponse implements ClientResponse {
@Override @Override
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) { public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
if (Void.class.isAssignableFrom(bodyType)) { if (Void.class == bodyType) {
return toEntityInternal(consumeAndCancel()); return toEntityInternal(consumeAndCancel());
} }
else { else {
@ -163,7 +152,7 @@ class DefaultClientResponse implements ClientResponse {
@Override @Override
public <T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> typeReference) { public <T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> typeReference) {
if (Void.class.isAssignableFrom(typeReference.getType().getClass())) { if (Void.class == typeReference.getType()) {
return toEntityInternal(consumeAndCancel()); return toEntityInternal(consumeAndCancel());
} }
else { else {
@ -171,6 +160,17 @@ class DefaultClientResponse implements ClientResponse {
} }
} }
@SuppressWarnings("unchecked")
private <T> Mono<T> consumeAndCancel() {
return (Mono<T>) this.response.getBody()
.map(buffer -> {
DataBufferUtils.release(buffer);
throw new ReadCancellationException();
})
.onErrorResume(ReadCancellationException.class, ex -> Mono.empty())
.then();
}
private <T> Mono<ResponseEntity<T>> toEntityInternal(Mono<T> bodyMono) { private <T> Mono<ResponseEntity<T>> toEntityInternal(Mono<T> bodyMono) {
HttpHeaders headers = headers().asHttpHeaders(); HttpHeaders headers = headers().asHttpHeaders();
HttpStatus statusCode = statusCode(); HttpStatus statusCode = statusCode();

Loading…
Cancel
Save