Optimize WebClientUtils
Use constant Predicate for exception wrapping. Use ResponseEntity constructor instead of builder. See gh-26069
This commit is contained in:
		
							parent
							
								
									5338d8b5e9
								
							
						
					
					
						commit
						ba9325446c
					
				|  | @ -113,9 +113,18 @@ public class ResponseEntity<T> extends HttpEntity<T> { | ||||||
| 	 * @param status the status code | 	 * @param status the status code | ||||||
| 	 */ | 	 */ | ||||||
| 	public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) { | 	public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) { | ||||||
| 		super(body, headers); | 		this(body, headers, (Object) status); | ||||||
| 		Assert.notNull(status, "HttpStatus must not be null"); | 	} | ||||||
| 		this.status = 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); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
|  | @ -543,16 +543,10 @@ class DefaultWebClient implements WebClient { | ||||||
| 			return this.responseMono.flatMap(response -> handleBodyMono(response, response.bodyToMono(elementTypeRef))); | 			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> result = statusHandlers(response); | ||||||
| 			Mono<T> wrappedExceptions = bodyPublisher.onErrorResume(WebClientUtils::shouldWrapException, | 			return (result != null ? result.switchIfEmpty(body) : body); | ||||||
| 							t -> wrapException(t, response)); |  | ||||||
| 			if (result != null) { |  | ||||||
| 				return result.switchIfEmpty(wrappedExceptions); |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				return wrappedExceptions; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
|  | @ -567,16 +561,10 @@ class DefaultWebClient implements WebClient { | ||||||
| 			return this.responseMono.flatMapMany(response -> handleBodyFlux(response, response.bodyToFlux(elementTypeRef))); | 			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); | 			Mono<T> result = statusHandlers(response); | ||||||
| 			Flux<T> wrappedExceptions = bodyPublisher.onErrorResume(WebClientUtils::shouldWrapException, | 			return (result != null ? result.flux().switchIfEmpty(body) : body); | ||||||
| 					t -> wrapException(t, response)); |  | ||||||
| 			if (result != null) { |  | ||||||
| 				return result.flux().switchIfEmpty(wrappedExceptions); |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				return wrappedExceptions; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Nullable | 		@Nullable | ||||||
|  | @ -608,10 +596,8 @@ class DefaultWebClient implements WebClient { | ||||||
| 			return result.checkpoint(description); | 			return result.checkpoint(description); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		private <T> Mono<T> wrapException(Throwable throwable, ClientResponse response) { | 		private <T> Function<Throwable, Mono<? extends T>> exceptionWrappingFunction(ClientResponse response) { | ||||||
| 			return response.createException() | 			return t -> response.createException().flatMap(ex -> Mono.error(ex.initCause(t))); | ||||||
| 					.map(responseException -> responseException.initCause(throwable)) |  | ||||||
| 					.flatMap(Mono::error); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
|  |  | ||||||
|  | @ -104,7 +104,7 @@ public abstract class ExchangeFunctions { | ||||||
| 					.connect(httpMethod, url, httpRequest -> clientRequest.writeTo(httpRequest, this.strategies)) | 					.connect(httpMethod, url, httpRequest -> clientRequest.writeTo(httpRequest, this.strategies)) | ||||||
| 					.doOnRequest(n -> logRequest(clientRequest)) | 					.doOnRequest(n -> logRequest(clientRequest)) | ||||||
| 					.doOnCancel(() -> logger.debug(logPrefix + "Cancel signal (to close connection)")) | 					.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 -> { | 					.map(httpResponse -> { | ||||||
| 						logResponse(httpResponse, logPrefix); | 						logResponse(httpResponse, logPrefix); | ||||||
| 						return new DefaultClientResponse( | 						return new DefaultClientResponse( | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| package org.springframework.web.reactive.function.client; | package org.springframework.web.reactive.function.client; | ||||||
| 
 | 
 | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.function.Predicate; | ||||||
| 
 | 
 | ||||||
| import org.reactivestreams.Publisher; | import org.reactivestreams.Publisher; | ||||||
| import reactor.core.publisher.Flux; | import reactor.core.publisher.Flux; | ||||||
|  | @ -26,7 +27,8 @@ import org.springframework.core.codec.CodecException; | ||||||
| import org.springframework.http.ResponseEntity; | 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 |  * @author Arjen Poutsma | ||||||
|  * @since 5.2 |  * @since 5.2 | ||||||
|  | @ -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"; | 	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>}. | 	 * Map the given response to a single value {@code ResponseEntity<T>}. | ||||||
|  | @ -42,9 +50,10 @@ abstract class WebClientUtils { | ||||||
| 	@SuppressWarnings("unchecked") | 	@SuppressWarnings("unchecked") | ||||||
| 	public static <T> Mono<ResponseEntity<T>> mapToEntity(ClientResponse response, Mono<T> bodyMono) { | 	public static <T> Mono<ResponseEntity<T>> mapToEntity(ClientResponse response, Mono<T> bodyMono) { | ||||||
| 		return ((Mono<Object>) bodyMono).defaultIfEmpty(VALUE_NONE).map(body -> | 		return ((Mono<Object>) bodyMono).defaultIfEmpty(VALUE_NONE).map(body -> | ||||||
| 				ResponseEntity.status(response.rawStatusCode()) | 				new ResponseEntity<>( | ||||||
| 						.headers(response.headers().asHttpHeaders()) | 						body != VALUE_NONE ? (T) body : null, | ||||||
| 						.body(body != VALUE_NONE ? (T) body : null)); | 						response.headers().asHttpHeaders(), | ||||||
|  | 						response.rawStatusCode())); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -52,15 +61,7 @@ abstract class WebClientUtils { | ||||||
| 	 */ | 	 */ | ||||||
| 	public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse response, Publisher<T> body) { | 	public static <T> Mono<ResponseEntity<List<T>>> mapToEntityList(ClientResponse response, Publisher<T> body) { | ||||||
| 		return Flux.from(body).collectList().map(list -> | 		return Flux.from(body).collectList().map(list -> | ||||||
| 				ResponseEntity.status(response.rawStatusCode()) | 				new ResponseEntity<>(list, response.headers().asHttpHeaders(), response.rawStatusCode())); | ||||||
| 						.headers(response.headers().asHttpHeaders()) |  | ||||||
| 						.body(list)); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Indicates whether the given exception should be wrapped. |  | ||||||
| 	 */ |  | ||||||
| 	public static boolean shouldWrapException(Throwable t) { |  | ||||||
| 		return !(t instanceof WebClientException) && !(t instanceof CodecException); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue