From 0b76b6d7e98e3095ecdb00ed8bc81e2aee7272a6 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Sun, 30 Oct 2016 22:07:05 +0200 Subject: [PATCH] Sync semantics for WebExchangeDataBinder factory The createBinder method in BindingContext now returns the binder instance rather than a Mono with the expectation that binder initialization (e.g. @InitBinder) does not require blocking. Issue: SPR-14543 --- .../result/method/BindingContext.java | 25 +++++++++++-------- ...AbstractMessageReaderArgumentResolver.java | 24 ++++++++---------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/BindingContext.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/BindingContext.java index 894665d35dc..fc8ee41cffa 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/BindingContext.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/BindingContext.java @@ -17,8 +17,6 @@ package org.springframework.web.reactive.result.method; import java.lang.reflect.Field; -import reactor.core.publisher.Mono; - import org.springframework.beans.TypeConverter; import org.springframework.beans.TypeMismatchException; import org.springframework.core.MethodParameter; @@ -42,7 +40,7 @@ public class BindingContext implements TypeConverter { private final WebBindingInitializer initializer; - private final WebDataBinder simpleValueDataBinder; + private final TypeConverter simpleValueTypeConverter; public BindingContext() { @@ -51,10 +49,15 @@ public class BindingContext implements TypeConverter { public BindingContext(WebBindingInitializer initializer) { this.initializer = initializer; - this.simpleValueDataBinder = new WebExchangeDataBinder(null); + this.simpleValueTypeConverter = initTypeConverter(initializer); + } + + private static WebExchangeDataBinder initTypeConverter(WebBindingInitializer initializer) { + WebExchangeDataBinder binder = new WebExchangeDataBinder(null); if (initializer != null) { - initializer.initBinder(this.simpleValueDataBinder); + initializer.initBinder(binder); } + return binder; } @@ -73,7 +76,7 @@ public class BindingContext implements TypeConverter { * @param objectName the name of the target object * @return a Mono for the created {@link WebDataBinder} instance */ - public Mono createBinder(ServerWebExchange exchange, Object target, + public WebExchangeDataBinder createBinder(ServerWebExchange exchange, Object target, String objectName) { WebExchangeDataBinder dataBinder = createBinderInstance(target, objectName); @@ -87,24 +90,24 @@ public class BindingContext implements TypeConverter { return new WebExchangeDataBinder(target, objectName); } - protected Mono initBinder(WebExchangeDataBinder binder, ServerWebExchange exchange) { - return Mono.just(binder); + protected WebExchangeDataBinder initBinder(WebExchangeDataBinder binder, ServerWebExchange exchange) { + return binder; } public T convertIfNecessary(Object value, Class requiredType) throws TypeMismatchException { - return this.simpleValueDataBinder.convertIfNecessary(value, requiredType); + return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType); } public T convertIfNecessary(Object value, Class requiredType, MethodParameter methodParam) throws TypeMismatchException { - return this.simpleValueDataBinder.convertIfNecessary(value, requiredType, methodParam); + return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType, methodParam); } public T convertIfNecessary(Object value, Class requiredType, Field field) throws TypeMismatchException { - return this.simpleValueDataBinder.convertIfNecessary(value, requiredType, field); + return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType, field); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java index a6cea58e57f..43e54cddaf2 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java @@ -19,7 +19,6 @@ import java.lang.annotation.Annotation; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.stream.Collectors; import reactor.core.publisher.Flux; @@ -39,6 +38,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.WebExchangeDataBinder; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; @@ -143,7 +143,8 @@ public abstract class AbstractMessageReaderArgumentResolver { } Object[] hints = extractValidationHints(bodyParameter); if (hints != null) { - flux = flux.concatMap(getValidator(hints, bodyParameter, bindingContext, exchange)); + flux = flux.doOnNext(target -> + validate(target, hints, bodyParameter, bindingContext, exchange)); } return Mono.just(adapter.fromPublisher(flux)); } @@ -162,7 +163,8 @@ public abstract class AbstractMessageReaderArgumentResolver { } Object[] hints = extractValidationHints(bodyParameter); if (hints != null) { - mono = mono.then(getValidator(hints, bodyParameter, bindingContext, exchange)); + mono = mono.doOnNext(target -> + validate(target, hints, bodyParameter, bindingContext, exchange)); } if (adapter != null) { return Mono.just(adapter.fromPublisher(mono)); @@ -207,19 +209,15 @@ public abstract class AbstractMessageReaderArgumentResolver { return null; } - protected Function> getValidator(Object[] validationHints, + protected void validate(Object target, Object[] validationHints, MethodParameter param, BindingContext binding, ServerWebExchange exchange) { String name = Conventions.getVariableNameForParameter(param); - - return target -> binding.createBinder(exchange, target, name) - .map(binder -> { - binder.validate(validationHints); - if (binder.getBindingResult().hasErrors()) { - throw new ServerWebInputException("Validation failed", param); - } - return target; - }); + WebExchangeDataBinder binder = binding.createBinder(exchange, target, name); + binder.validate(validationHints); + if (binder.getBindingResult().hasErrors()) { + throw new ServerWebInputException("Validation failed", param); + } } }