Browse Source

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
pull/1214/head
Rossen Stoyanchev 9 years ago
parent
commit
0b76b6d7e9
  1. 25
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/BindingContext.java
  2. 24
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java

25
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 java.lang.reflect.Field;
import reactor.core.publisher.Mono;
import org.springframework.beans.TypeConverter; import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException; import org.springframework.beans.TypeMismatchException;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
@ -42,7 +40,7 @@ public class BindingContext implements TypeConverter {
private final WebBindingInitializer initializer; private final WebBindingInitializer initializer;
private final WebDataBinder simpleValueDataBinder; private final TypeConverter simpleValueTypeConverter;
public BindingContext() { public BindingContext() {
@ -51,10 +49,15 @@ public class BindingContext implements TypeConverter {
public BindingContext(WebBindingInitializer initializer) { public BindingContext(WebBindingInitializer initializer) {
this.initializer = 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) { 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 * @param objectName the name of the target object
* @return a Mono for the created {@link WebDataBinder} instance * @return a Mono for the created {@link WebDataBinder} instance
*/ */
public Mono<WebExchangeDataBinder> createBinder(ServerWebExchange exchange, Object target, public WebExchangeDataBinder createBinder(ServerWebExchange exchange, Object target,
String objectName) { String objectName) {
WebExchangeDataBinder dataBinder = createBinderInstance(target, objectName); WebExchangeDataBinder dataBinder = createBinderInstance(target, objectName);
@ -87,24 +90,24 @@ public class BindingContext implements TypeConverter {
return new WebExchangeDataBinder(target, objectName); return new WebExchangeDataBinder(target, objectName);
} }
protected Mono<WebExchangeDataBinder> initBinder(WebExchangeDataBinder binder, ServerWebExchange exchange) { protected WebExchangeDataBinder initBinder(WebExchangeDataBinder binder, ServerWebExchange exchange) {
return Mono.just(binder); return binder;
} }
public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException { public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
return this.simpleValueDataBinder.convertIfNecessary(value, requiredType); return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType);
} }
public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
throws TypeMismatchException { throws TypeMismatchException {
return this.simpleValueDataBinder.convertIfNecessary(value, requiredType, methodParam); return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType, methodParam);
} }
public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field) public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
throws TypeMismatchException { throws TypeMismatchException {
return this.simpleValueDataBinder.convertIfNecessary(value, requiredType, field); return this.simpleValueTypeConverter.convertIfNecessary(value, requiredType, field);
} }
} }

24
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.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
@ -39,6 +38,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebExchangeDataBinder;
import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException; import org.springframework.web.server.ServerWebInputException;
@ -143,7 +143,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
} }
Object[] hints = extractValidationHints(bodyParameter); Object[] hints = extractValidationHints(bodyParameter);
if (hints != null) { 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)); return Mono.just(adapter.fromPublisher(flux));
} }
@ -162,7 +163,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
} }
Object[] hints = extractValidationHints(bodyParameter); Object[] hints = extractValidationHints(bodyParameter);
if (hints != null) { if (hints != null) {
mono = mono.then(getValidator(hints, bodyParameter, bindingContext, exchange)); mono = mono.doOnNext(target ->
validate(target, hints, bodyParameter, bindingContext, exchange));
} }
if (adapter != null) { if (adapter != null) {
return Mono.just(adapter.fromPublisher(mono)); return Mono.just(adapter.fromPublisher(mono));
@ -207,19 +209,15 @@ public abstract class AbstractMessageReaderArgumentResolver {
return null; return null;
} }
protected <T> Function<T, Mono<T>> getValidator(Object[] validationHints, protected void validate(Object target, Object[] validationHints,
MethodParameter param, BindingContext binding, ServerWebExchange exchange) { MethodParameter param, BindingContext binding, ServerWebExchange exchange) {
String name = Conventions.getVariableNameForParameter(param); String name = Conventions.getVariableNameForParameter(param);
WebExchangeDataBinder binder = binding.createBinder(exchange, target, name);
return target -> binding.createBinder(exchange, target, name) binder.validate(validationHints);
.map(binder -> { if (binder.getBindingResult().hasErrors()) {
binder.validate(validationHints); throw new ServerWebInputException("Validation failed", param);
if (binder.getBindingResult().hasErrors()) { }
throw new ServerWebInputException("Validation failed", param);
}
return target;
});
} }
} }

Loading…
Cancel
Save