From 8a043ae9aad072f888650b9ccd929f6c1e61e7fa Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 11 Oct 2016 20:16:03 -0400 Subject: [PATCH] Replace direct use of Validator and ConversionService This commit replaces direct use of Validator and ConversionService in the reactive @RequestMapping infrustructure in favor of using the BindingContext. Issue: SPR-14541 --- .../config/WebReactiveConfiguration.java | 7 +- .../result/method/BindingContext.java | 31 +++++ ...AbstractMessageReaderArgumentResolver.java | 113 +++++++++--------- ...tractNamedValueMethodArgumentResolver.java | 29 ++--- .../CookieValueMethodArgumentResolver.java | 7 +- ...ExpressionValueMethodArgumentResolver.java | 7 +- .../HttpEntityArgumentResolver.java | 16 +-- .../PathVariableMethodArgumentResolver.java | 6 +- ...equestAttributeMethodArgumentResolver.java | 7 +- .../RequestBodyArgumentResolver.java | 16 +-- .../RequestHeaderMethodArgumentResolver.java | 7 +- .../RequestMappingHandlerAdapter.java | 63 ++-------- .../RequestParamMethodArgumentResolver.java | 8 +- ...essionAttributeMethodArgumentResolver.java | 7 +- .../config/WebReactiveConfigurationTests.java | 16 +-- ...ookieValueMethodArgumentResolverTests.java | 7 +- ...ssionValueMethodArgumentResolverTests.java | 7 +- .../HttpEntityArgumentResolverTests.java | 4 +- .../MessageReaderArgumentResolverTests.java | 17 ++- ...thVariableMethodArgumentResolverTests.java | 12 +- ...tAttributeMethodArgumentResolverTests.java | 15 ++- .../RequestBodyArgumentResolverTests.java | 6 +- ...uestHeaderMethodArgumentResolverTests.java | 13 +- ...questParamMethodArgumentResolverTests.java | 21 ++-- ...nAttributeMethodArgumentResolverTests.java | 15 ++- 25 files changed, 208 insertions(+), 249 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java index 5de6553f930..9a55e2e435e 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java @@ -252,6 +252,8 @@ public class WebReactiveConfiguration implements ApplicationContextAware { @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); + adapter.setMessageReaders(getMessageReaders()); + adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); List resolvers = new ArrayList<>(); addArgumentResolvers(resolvers); @@ -259,11 +261,6 @@ public class WebReactiveConfiguration implements ApplicationContextAware { adapter.setCustomArgumentResolvers(resolvers); } - adapter.setMessageReaders(getMessageReaders()); - adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); - adapter.setConversionService(webReactiveConversionService()); - adapter.setValidator(webReactiveValidator()); - return adapter; } 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 6650b005a7f..42820303a88 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,10 +17,13 @@ package org.springframework.web.reactive.result.method; import reactor.core.publisher.Mono; +import org.springframework.beans.SimpleTypeConverter; +import org.springframework.beans.TypeConverter; import org.springframework.ui.ModelMap; import org.springframework.validation.support.BindingAwareModelMap; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebExchangeDataBinder; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.server.ServerWebExchange; @@ -37,6 +40,8 @@ public class BindingContext { private final WebBindingInitializer initializer; + private final TypeConverter typeConverter; + public BindingContext() { this(null); @@ -44,6 +49,21 @@ public class BindingContext { public BindingContext(WebBindingInitializer initializer) { this.initializer = initializer; + this.typeConverter = initSimpleTypeConverter(initializer); + } + + private static SimpleTypeConverter initSimpleTypeConverter(WebBindingInitializer initializer) { + SimpleTypeConverter converter = new SimpleTypeConverter(); + if (initializer instanceof ConfigurableWebBindingInitializer) { + converter.setConversionService( + ((ConfigurableWebBindingInitializer) initializer).getConversionService()); + } + else if (initializer != null) { + WebDataBinder dataBinder = new WebDataBinder(null); + initializer.initBinder(dataBinder); + converter.setConversionService(dataBinder.getConversionService()); + } + return converter; } @@ -80,4 +100,15 @@ public class BindingContext { return Mono.just(dataBinder); } + /** + * Return a {@link TypeConverter} for converting plain parameter values. + * This is a shortcut for: + *
+	 * new WebDataBinder(null).getTypeConverter();
+	 * 
+ */ + public TypeConverter getTypeConverter() { + return this.typeConverter; + } + } 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 72d82b53a2a..a6cea58e57f 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 @@ -18,6 +18,7 @@ package org.springframework.web.reactive.result.method.annotation; 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; @@ -36,12 +37,9 @@ import org.springframework.http.codec.ServerHttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.Errors; -import org.springframework.validation.SmartValidator; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; +import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; import org.springframework.web.server.UnsupportedMediaTypeStatusException; @@ -62,8 +60,6 @@ public abstract class AbstractMessageReaderArgumentResolver { private final List> messageReaders; - private final Validator validator; - private final ReactiveAdapterRegistry adapterRegistry; private final List supportedMediaTypes; @@ -72,26 +68,22 @@ public abstract class AbstractMessageReaderArgumentResolver { /** * Constructor with {@link HttpMessageReader}'s and a {@link Validator}. * @param readers readers to convert from the request body - * @param validator validator to validate decoded objects with */ - protected AbstractMessageReaderArgumentResolver(List> readers, Validator validator) { - - this(readers, validator, new ReactiveAdapterRegistry()); + protected AbstractMessageReaderArgumentResolver(List> readers) { + this(readers, new ReactiveAdapterRegistry()); } /** * Constructor that also accepts a {@link ReactiveAdapterRegistry}. * @param messageReaders readers to convert from the request body - * @param validator validator to validate decoded objects with * @param adapterRegistry for adapting to other reactive types from Flux and Mono */ protected AbstractMessageReaderArgumentResolver(List> messageReaders, - Validator validator, ReactiveAdapterRegistry adapterRegistry) { + ReactiveAdapterRegistry adapterRegistry) { Assert.notEmpty(messageReaders, "At least one HttpMessageReader is required."); Assert.notNull(adapterRegistry, "'adapterRegistry' is required"); this.messageReaders = messageReaders; - this.validator = validator; this.adapterRegistry = adapterRegistry; this.supportedMediaTypes = messageReaders.stream() .flatMap(converter -> converter.getReadableMediaTypes().stream()) @@ -115,7 +107,7 @@ public abstract class AbstractMessageReaderArgumentResolver { protected Mono readBody(MethodParameter bodyParameter, boolean isBodyRequired, - ServerWebExchange exchange) { + BindingContext bindingContext, ServerWebExchange exchange) { ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter); ReactiveAdapter adapter = getAdapterRegistry().getAdapterTo(bodyType.resolve()); @@ -135,32 +127,42 @@ public abstract class AbstractMessageReaderArgumentResolver { for (HttpMessageReader reader : getMessageReaders()) { if (reader.canRead(elementType, mediaType)) { - + Map readHints = Collections.emptyMap(); if (adapter != null && adapter.getDescriptor().isMultiValue()) { - Flux flux = (reader instanceof ServerHttpMessageReader ? - ((ServerHttpMessageReader)reader).read(bodyType, elementType, - request, response, Collections.emptyMap()) : - reader.read(elementType, request, Collections.emptyMap()) - .onErrorResumeWith(ex -> Flux.error(getReadError(ex, bodyParameter)))); + Flux flux; + if (reader instanceof ServerHttpMessageReader) { + ServerHttpMessageReader serverReader = ((ServerHttpMessageReader) reader); + flux = serverReader.read(bodyType, elementType, request, response, readHints); + } + else { + flux = reader.read(elementType, request, readHints); + } + flux = flux.onErrorResumeWith(ex -> Flux.error(wrapReadError(ex, bodyParameter))); if (checkRequired(adapter, isBodyRequired)) { flux = flux.switchIfEmpty(Flux.error(getRequiredBodyError(bodyParameter))); } - if (this.validator != null) { - flux = flux.map(applyValidationIfApplicable(bodyParameter)); + Object[] hints = extractValidationHints(bodyParameter); + if (hints != null) { + flux = flux.concatMap(getValidator(hints, bodyParameter, bindingContext, exchange)); } return Mono.just(adapter.fromPublisher(flux)); } else { - Mono mono = (reader instanceof ServerHttpMessageReader ? - ((ServerHttpMessageReader)reader).readMono(bodyType, elementType, - request, response, Collections.emptyMap()) : - reader.readMono(elementType, request, Collections.emptyMap()) - .otherwise(ex -> Mono.error(getReadError(ex, bodyParameter)))); + Mono mono; + if (reader instanceof ServerHttpMessageReader) { + ServerHttpMessageReader serverReader = (ServerHttpMessageReader) reader; + mono = serverReader.readMono(bodyType, elementType, request, response, readHints); + } + else { + mono = reader.readMono(elementType, request, readHints); + } + mono = mono.otherwise(ex -> Mono.error(wrapReadError(ex, bodyParameter))); if (checkRequired(adapter, isBodyRequired)) { mono = mono.otherwiseIfEmpty(Mono.error(getRequiredBodyError(bodyParameter))); } - if (this.validator != null) { - mono = mono.map(applyValidationIfApplicable(bodyParameter)); + Object[] hints = extractValidationHints(bodyParameter); + if (hints != null) { + mono = mono.then(getValidator(hints, bodyParameter, bindingContext, exchange)); } if (adapter != null) { return Mono.just(adapter.fromPublisher(mono)); @@ -175,12 +177,12 @@ public abstract class AbstractMessageReaderArgumentResolver { return Mono.error(new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes)); } - protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) { - return adapter != null && !adapter.getDescriptor().supportsEmpty() || isBodyRequired; + protected ServerWebInputException wrapReadError(Throwable ex, MethodParameter parameter) { + return new ServerWebInputException("Failed to read HTTP message", parameter, ex); } - protected ServerWebInputException getReadError(Throwable ex, MethodParameter parameter) { - return new ServerWebInputException("Failed to read HTTP message", parameter, ex); + protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) { + return adapter != null && !adapter.getDescriptor().supportsEmpty() || isBodyRequired; } protected ServerWebInputException getRequiredBodyError(MethodParameter parameter) { @@ -188,37 +190,36 @@ public abstract class AbstractMessageReaderArgumentResolver { parameter.getMethod().toGenericString()); } - protected Function applyValidationIfApplicable(MethodParameter methodParam) { - Annotation[] annotations = methodParam.getParameterAnnotations(); + /** + * Check if the given MethodParameter requires validation and if so return + * a (possibly empty) Object[] with validation hints. A return value of + * {@code null} indicates that validation is not required. + */ + protected Object[] extractValidationHints(MethodParameter parameter) { + Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation ann : annotations) { Validated validAnnot = AnnotationUtils.getAnnotation(ann, Validated.class); if (validAnnot != null || ann.annotationType().getSimpleName().startsWith("Valid")) { Object hints = (validAnnot != null ? validAnnot.value() : AnnotationUtils.getValue(ann)); - Object[] validHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); - return element -> { - doValidate(element, validHints, methodParam); - return element; - }; + return (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); } } - return element -> element; + return null; } - /** - * TODO: replace with use of DataBinder - */ - private void doValidate(Object target, Object[] validationHints, MethodParameter methodParam) { - String name = Conventions.getVariableNameForParameter(methodParam); - Errors errors = new BeanPropertyBindingResult(target, name); - if (!ObjectUtils.isEmpty(validationHints) && this.validator instanceof SmartValidator) { - ((SmartValidator) this.validator).validate(target, errors, validationHints); - } - else if (this.validator != null) { - this.validator.validate(target, errors); - } - if (errors.hasErrors()) { - throw new ServerWebInputException("Validation failed", methodParam); - } + protected Function> getValidator(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; + }); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java index 9b2fabb78c4..7a2d3b5b13a 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java @@ -22,15 +22,13 @@ import java.util.concurrent.ConcurrentHashMap; import reactor.core.publisher.Mono; import org.springframework.beans.ConversionNotSupportedException; -import org.springframework.beans.SimpleTypeConverter; +import org.springframework.beans.TypeConverter; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.ui.ModelMap; -import org.springframework.util.Assert; import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; @@ -64,22 +62,13 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle private final Map namedValueInfoCache = new ConcurrentHashMap<>(256); - /** Instead of a WebDataBinder for now */ - private final SimpleTypeConverter typeConverter; - /** - * @param conversionService for type conversion (to be replaced with WebDataBinder) * @param beanFactory a bean factory to use for resolving ${...} placeholder * and #{...} SpEL expressions in default values, or {@code null} if default * values are not expected to contain expressions */ - public AbstractNamedValueMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - Assert.notNull(conversionService, "'conversionService' is required."); - this.typeConverter = new SimpleTypeConverter(); - this.typeConverter.setConversionService(conversionService); + public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { this.configurableBeanFactory = beanFactory; this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null); } @@ -105,11 +94,12 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle if ("".equals(arg) && namedValueInfo.defaultValue != null) { arg = resolveStringValue(namedValueInfo.defaultValue); } - arg = applyConversion(arg, parameter); + arg = applyConversion(arg, parameter, bindingContext); handleResolvedValue(arg, namedValueInfo.name, parameter, model, exchange); return arg; }) - .otherwiseIfEmpty(getDefaultValue(namedValueInfo, parameter, model, exchange)); + .otherwiseIfEmpty(getDefaultValue( + namedValueInfo, parameter, bindingContext, model, exchange)); } /** @@ -179,9 +169,10 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle protected abstract Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange); - private Object applyConversion(Object value, MethodParameter parameter) { + private Object applyConversion(Object value, MethodParameter parameter, BindingContext bindingContext) { try { - value = this.typeConverter.convertIfNecessary(value, parameter.getParameterType(), parameter); + TypeConverter typeConverter = bindingContext.getTypeConverter(); + value = typeConverter.convertIfNecessary(value, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { throw new ServerErrorException("Conversion not supported.", parameter, ex); @@ -193,7 +184,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle } private Mono getDefaultValue(NamedValueInfo namedValueInfo, MethodParameter parameter, - ModelMap model, ServerWebExchange exchange) { + BindingContext bindingContext, ModelMap model, ServerWebExchange exchange) { Object value = null; try { @@ -204,7 +195,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle handleMissingValue(namedValueInfo.name, parameter, exchange); } value = handleNullValue(namedValueInfo.name, value, parameter.getNestedParameterType()); - value = applyConversion(value, parameter); + value = applyConversion(value, parameter, bindingContext); handleResolvedValue(value, namedValueInfo.name, parameter, model, exchange); return Mono.justOrEmpty(value); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java index 34cf2e8db23..5aa8c70dbab 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java @@ -20,7 +20,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.http.HttpCookie; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.server.ServerWebExchange; @@ -44,10 +43,8 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodA * placeholder and #{...} SpEL expressions in default values; * or {@code null} if default values are not expected to contain expressions */ - public CookieValueMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - super(conversionService, beanFactory); + public CookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java index d5d5098015c..07985bc9f77 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java @@ -21,7 +21,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.web.server.ServerWebExchange; /** @@ -42,10 +41,8 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet * placeholder and #{...} SpEL expressions in default values; * or {@code null} if default values are not expected to contain expressions */ - public ExpressionValueMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - super(conversionService, beanFactory); + public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java index 857bbe08882..98c6e90f9a2 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java @@ -47,22 +47,18 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes /** * Constructor with {@link HttpMessageReader}'s and a {@link Validator}. * @param readers readers for de-serializing the request body with - * @param validator validator to validate decoded objects with */ - public HttpEntityArgumentResolver(List> readers, Validator validator) { - super(readers, validator); + public HttpEntityArgumentResolver(List> readers) { + super(readers); } /** * Constructor that also accepts a {@link ReactiveAdapterRegistry}. * @param readers readers for de-serializing the request body with - * @param validator validator to validate decoded objects with - * @param adapterRegistry for adapting to other reactive types from Flux and Mono + * @param registry for adapting to other reactive types from Flux and Mono */ - public HttpEntityArgumentResolver(List> readers, Validator validator, - ReactiveAdapterRegistry adapterRegistry) { - - super(readers, validator, adapterRegistry); + public HttpEntityArgumentResolver(List> readers, ReactiveAdapterRegistry registry) { + super(readers, registry); } @@ -80,7 +76,7 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes MethodParameter bodyParameter = new MethodParameter(param); bodyParameter.increaseNestingLevel(); - return readBody(bodyParameter, false, exchange) + return readBody(bodyParameter, false, bindingContext, exchange) .map(body -> createHttpEntity(body, entityType, exchange)) .defaultIfEmpty(createHttpEntity(null, entityType, exchange)); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java index d6250967263..274e2a6c610 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java @@ -23,7 +23,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.ui.ModelMap; import org.springframework.util.StringUtils; @@ -54,10 +53,9 @@ import org.springframework.web.server.ServerWebExchange; */ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - public PathVariableMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - super(conversionService, beanFactory); + public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java index 837a81038df..670cb628a6f 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java @@ -19,7 +19,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.server.ServerWebExchange; @@ -35,10 +34,8 @@ import org.springframework.web.server.ServerWebInputException; public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - public RequestAttributeMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - super(conversionService, beanFactory); + public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java index 4fccceac8ca..74144e76ef9 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java @@ -51,22 +51,18 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe /** * Constructor with {@link HttpMessageReader}'s and a {@link Validator}. * @param readers readers for de-serializing the request body with - * @param validator validator to validate decoded objects with */ - public RequestBodyArgumentResolver(List> readers, Validator validator) { - super(readers, validator); + public RequestBodyArgumentResolver(List> readers) { + super(readers); } /** * Constructor that also accepts a {@link ReactiveAdapterRegistry}. * @param readers readers for de-serializing the request body with - * @param validator validator to validate decoded objects with - * @param adapterRegistry for adapting to other reactive types from Flux and Mono + * @param registry for adapting to other reactive types from Flux and Mono */ - public RequestBodyArgumentResolver(List> readers, Validator validator, - ReactiveAdapterRegistry adapterRegistry) { - - super(readers, validator, adapterRegistry); + public RequestBodyArgumentResolver(List> readers, ReactiveAdapterRegistry registry) { + super(readers, registry); } @@ -80,7 +76,7 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe ServerWebExchange exchange) { boolean isRequired = param.getParameterAnnotation(RequestBody.class).required(); - return readBody(param, isRequired, exchange); + return readBody(param, isRequired, bindingContext, exchange); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java index 56b78961405..6256a11c0fe 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java @@ -46,15 +46,14 @@ import org.springframework.web.server.ServerWebInputException; */ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { + /** * @param beanFactory a bean factory to use for resolving ${...} * placeholder and #{...} SpEL expressions in default values; * or {@code null} if default values are not expected to have expressions */ - public RequestHeaderMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - super(conversionService, beanFactory); + public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java index 6524ed92742..44200c184a8 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java @@ -34,11 +34,8 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.codec.ByteBufferDecoder; import org.springframework.core.codec.StringDecoder; -import org.springframework.core.convert.ConversionService; -import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.HttpMessageReader; -import org.springframework.validation.Validator; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver; @@ -70,10 +67,6 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory private List argumentResolvers; - private ConversionService conversionService = new DefaultFormattingConversionService(); - - private Validator validator; - private ConfigurableBeanFactory beanFactory; private final Map, ExceptionHandlerMethodResolver> exceptionHandlerCache = @@ -154,41 +147,6 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory return this.argumentResolvers; } - /** - * Configure a ConversionService for type conversion of controller method - * arguments as well as for converting from different async types to - * {@code Flux} and {@code Mono}. - * - * TODO: this may be replaced by DataBinder - */ - public void setConversionService(ConversionService conversionService) { - this.conversionService = conversionService; - } - - /** - * Return the configured ConversionService. - */ - public ConversionService getConversionService() { - return this.conversionService; - } - - /** - * Configure a Validator for validation of controller method arguments such - * as {@code @RequestBody}. - * - * TODO: this may be replaced by DataBinder - */ - public void setValidator(Validator validator) { - this.validator = validator; - } - - /** - * Return the configured Validator. - */ - public Validator getValidator() { - return this.validator; - } - /** * A {@link ConfigurableBeanFactory} is expected for resolving expressions * in method argument default values. @@ -215,24 +173,23 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory protected List initArgumentResolvers() { List resolvers = new ArrayList<>(); - ConversionService cs = getConversionService(); ReactiveAdapterRegistry adapterRegistry = getReactiveAdapterRegistry(); // Annotation-based argument resolution - resolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), false)); + resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); - resolvers.add(new PathVariableMethodArgumentResolver(cs, getBeanFactory())); + resolvers.add(new PathVariableMethodArgumentResolver(getBeanFactory())); resolvers.add(new PathVariableMapMethodArgumentResolver()); - resolvers.add(new RequestBodyArgumentResolver(getMessageReaders(), getValidator(), adapterRegistry)); - resolvers.add(new RequestHeaderMethodArgumentResolver(cs, getBeanFactory())); + resolvers.add(new RequestBodyArgumentResolver(getMessageReaders(), adapterRegistry)); + resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); - resolvers.add(new CookieValueMethodArgumentResolver(cs, getBeanFactory())); - resolvers.add(new ExpressionValueMethodArgumentResolver(cs, getBeanFactory())); - resolvers.add(new SessionAttributeMethodArgumentResolver(cs, getBeanFactory())); - resolvers.add(new RequestAttributeMethodArgumentResolver(cs , getBeanFactory())); + resolvers.add(new CookieValueMethodArgumentResolver(getBeanFactory())); + resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); + resolvers.add(new SessionAttributeMethodArgumentResolver(getBeanFactory())); + resolvers.add(new RequestAttributeMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution - resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), getValidator(), adapterRegistry)); + resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), adapterRegistry)); resolvers.add(new ModelArgumentResolver()); resolvers.add(new ServerWebExchangeArgumentResolver()); @@ -242,7 +199,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory } // Catch-all - resolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), true)); + resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); return resolvers; } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java index c337e056674..b15e94fbf26 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java @@ -24,7 +24,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestParam; @@ -57,7 +56,6 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod /** - * @param conversionService for type conversion (to be replaced with WebDataBinder) * @param beanFactory a bean factory used for resolving ${...} placeholder * and #{...} SpEL expressions in default values, or {@code null} if default * values are not expected to contain expressions @@ -66,10 +64,8 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod * is treated as a request parameter even if it isn't annotated, the * request parameter name is derived from the method parameter name. */ - public RequestParamMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory, boolean useDefaultResolution) { - - super(conversionService, beanFactory); + public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory, boolean useDefaultResolution) { + super(beanFactory); this.useDefaultResolution = useDefaultResolution; } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java index be6883273c5..4fa1cd87715 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java @@ -21,7 +21,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.web.bind.annotation.SessionAttribute; import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.server.ServerWebExchange; @@ -37,10 +36,8 @@ import org.springframework.web.server.ServerWebInputException; public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - public SessionAttributeMethodArgumentResolver(ConversionService conversionService, - ConfigurableBeanFactory beanFactory) { - - super(conversionService, beanFactory); + public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java index 5b558ccc087..122e51ce923 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java @@ -48,7 +48,6 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; import org.springframework.validation.Validator; -import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean; import org.springframework.web.bind.WebExchangeDataBinder; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; @@ -155,20 +154,17 @@ public class WebReactiveConfigurationTests { assertHasMessageReader(readers, TestBean.class, APPLICATION_JSON); assertHasMessageReader(readers, TestBean.class, null); - name = "webReactiveConversionService"; - ConversionService service = context.getBean(name, ConversionService.class); - assertSame(service, adapter.getConversionService()); - - name = "webReactiveValidator"; - Validator validator = context.getBean(name, Validator.class); - assertSame(validator, adapter.getValidator()); - assertEquals(OptionalValidatorFactoryBean.class, validator.getClass()); - WebBindingInitializer bindingInitializer = adapter.getWebBindingInitializer(); assertNotNull(bindingInitializer); WebExchangeDataBinder binder = new WebExchangeDataBinder(new Object()); bindingInitializer.initBinder(binder); + + name = "webReactiveConversionService"; + ConversionService service = context.getBean(name, ConversionService.class); assertSame(service, binder.getConversionService()); + + name = "webReactiveValidator"; + Validator validator = context.getBean(name, Validator.class); assertSame(validator, binder.getValidator()); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java index f6db8ff2525..b19292b0995 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java @@ -25,13 +25,11 @@ import reactor.core.publisher.Mono; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.http.HttpCookie; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.tests.TestSubscriber; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.reactive.result.method.BindingContext; @@ -67,8 +65,7 @@ public class CookieValueMethodArgumentResolverTests { public void setUp() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); - ConversionService cs = new DefaultConversionService(); - this.resolver = new CookieValueMethodArgumentResolver(cs, context.getBeanFactory()); + this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory()); ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/"); WebSessionManager sessionManager = new MockWebSessionManager(); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java index 6ff03b61362..9d125e03597 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java @@ -25,12 +25,10 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.MethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.GenericConversionService; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -58,10 +56,9 @@ public class ExpressionValueMethodArgumentResolverTests { @Before public void setUp() throws Exception { - ConversionService conversionService = new GenericConversionService(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); - this.resolver = new ExpressionValueMethodArgumentResolver(conversionService, context.getBeanFactory()); + this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory()); ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/"); WebSessionManager sessionManager = new MockWebSessionManager(); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java index 82c5a933e79..24ffa019b15 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java @@ -46,7 +46,6 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; import org.springframework.tests.TestSubscriber; -import org.springframework.validation.Validator; import org.springframework.web.reactive.result.ResolvableMethod; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; @@ -59,7 +58,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; import static org.springframework.core.ResolvableType.forClassWithGenerics; /** @@ -91,7 +89,7 @@ public class HttpEntityArgumentResolverTests { private HttpEntityArgumentResolver createResolver() { List> readers = new ArrayList<>(); readers.add(new DecoderHttpMessageReader<>(new StringDecoder())); - return new HttpEntityArgumentResolver(readers, mock(Validator.class)); + return new HttpEntityArgumentResolver(readers); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java index 81871441b33..e44496f474c 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java @@ -49,8 +49,10 @@ import org.springframework.tests.TestSubscriber; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.result.ResolvableMethod; +import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; import org.springframework.web.server.UnsupportedMediaTypeStatusException; @@ -76,6 +78,8 @@ public class MessageReaderArgumentResolverTests { private MockServerHttpRequest request; + private BindingContext bindingContext; + private ResolvableMethod testMethod = ResolvableMethod.onClass(this.getClass()).name("handle"); @@ -84,6 +88,10 @@ public class MessageReaderArgumentResolverTests { this.request = new MockServerHttpRequest(HttpMethod.POST, "/path"); MockServerHttpResponse response = new MockServerHttpResponse(); this.exchange = new DefaultServerWebExchange(this.request, response, new MockWebSessionManager()); + + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setValidator(new TestBeanValidator()); + this.bindingContext = new BindingContext(initializer); } @@ -92,7 +100,7 @@ public class MessageReaderArgumentResolverTests { this.request.setBody("{\"bar\":\"BARBAR\",\"foo\":\"FOOFOO\"}"); ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class); MethodParameter param = this.testMethod.resolveParam(type); - Mono result = this.resolver.readBody(param, true, this.exchange); + Mono result = this.resolver.readBody(param, true, this.bindingContext, this.exchange); TestSubscriber.subscribe(result) .assertError(UnsupportedMediaTypeStatusException.class); @@ -105,7 +113,8 @@ public class MessageReaderArgumentResolverTests { this.request.setHeader("Content-Type", "application/json"); ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class); MethodParameter param = this.testMethod.resolveParam(type); - Mono result = (Mono) this.resolver.readBody(param, true, this.exchange).block(); + Mono result = (Mono) this.resolver.readBody( + param, true, this.bindingContext, this.exchange).block(); TestSubscriber.subscribe(result).assertError(ServerWebInputException.class); } @@ -285,7 +294,7 @@ public class MessageReaderArgumentResolverTests { @SuppressWarnings("unchecked") private T resolveValue(MethodParameter param, String body) { this.request.setHeader("Content-Type", "application/json").setBody(body); - Mono result = this.resolver.readBody(param, true, this.exchange); + Mono result = this.resolver.readBody(param, true, this.bindingContext, this.exchange); Object value = result.block(Duration.ofSeconds(5)); assertNotNull(value); @@ -299,7 +308,7 @@ public class MessageReaderArgumentResolverTests { private AbstractMessageReaderArgumentResolver resolver(Decoder... decoders) { List> readers = new ArrayList<>(); Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder))); - return new AbstractMessageReaderArgumentResolver(readers, new TestBeanValidator()) {}; + return new AbstractMessageReaderArgumentResolver(readers) {}; } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java index 290b2a69c07..7828a07bc89 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java @@ -27,8 +27,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; @@ -36,6 +35,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse import org.springframework.tests.TestSubscriber; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerErrorException; @@ -71,8 +71,7 @@ public class PathVariableMethodArgumentResolverTests { @Before public void setUp() throws Exception { - ConversionService conversionService = new DefaultConversionService(); - this.resolver = new PathVariableMethodArgumentResolver(conversionService, null); + this.resolver = new PathVariableMethodArgumentResolver(null); ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/"); WebSessionManager sessionManager = new MockWebSessionManager(); @@ -122,7 +121,10 @@ public class PathVariableMethodArgumentResolverTests { uriTemplateVars.put("name", "value"); this.exchange.getAttributes().put(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars); - BindingContext bindingContext = new BindingContext(); + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setConversionService(new DefaultFormattingConversionService()); + BindingContext bindingContext = new BindingContext(initializer); + Mono mono = this.resolver.resolveArgument(this.paramOptional, bindingContext, this.exchange); Object result = mono.block(); assertEquals(Optional.of("value"), result); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java index da2954b6e6a..8dccb347dd4 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java @@ -27,15 +27,15 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.tests.TestSubscriber; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; @@ -69,8 +69,7 @@ public class RequestAttributeMethodArgumentResolverTests { public void setUp() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); - ConversionService cs = new DefaultConversionService(); - this.resolver = new RequestAttributeMethodArgumentResolver(cs, context.getBeanFactory()); + this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory()); ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/"); WebSessionManager sessionManager = new MockWebSessionManager(); @@ -130,9 +129,13 @@ public class RequestAttributeMethodArgumentResolverTests { assertEquals(Optional.class, mono.block().getClass()); assertFalse(((Optional) mono.block()).isPresent()); + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setConversionService(new DefaultFormattingConversionService()); + BindingContext bindingContext = new BindingContext(initializer); + Foo foo = new Foo(); this.exchange.getAttributes().put("foo", foo); - mono = this.resolver.resolveArgument(param, new BindingContext(), this.exchange); + mono = this.resolver.resolveArgument(param, bindingContext, this.exchange); assertNotNull(mono.block()); assertEquals(Optional.class, mono.block().getClass()); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java index f9069cf984c..d7e90477f35 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java @@ -39,7 +39,6 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; import org.springframework.tests.TestSubscriber; -import org.springframework.validation.Validator; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.reactive.result.ResolvableMethod; import org.springframework.web.reactive.result.method.BindingContext; @@ -53,7 +52,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; import static org.springframework.core.ResolvableType.forClass; import static org.springframework.core.ResolvableType.forClassWithGenerics; @@ -85,7 +83,7 @@ public class RequestBodyArgumentResolverTests { private RequestBodyArgumentResolver resolver() { List> readers = new ArrayList<>(); readers.add(new DecoderHttpMessageReader<>(new StringDecoder())); - return new RequestBodyArgumentResolver(readers, mock(Validator.class)); + return new RequestBodyArgumentResolver(readers); } @@ -199,7 +197,7 @@ public class RequestBodyArgumentResolverTests { @SuppressWarnings("unchecked") private T resolveValue(MethodParameter param, String body) { this.request.setBody(body); - Mono result = this.resolver.readBody(param, true, this.exchange); + Mono result = this.resolver.readBody(param, true, new BindingContext(), this.exchange); Object value = result.block(Duration.ofSeconds(5)); assertNotNull(value); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java index 0026f5069df..b88155c620d 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java @@ -30,15 +30,15 @@ import reactor.core.publisher.Mono; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.tests.TestSubscriber; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; @@ -71,15 +71,14 @@ public class RequestHeaderMethodArgumentResolverTests { private ServerWebExchange exchange; - private BindingContext bindingContext = new BindingContext(); + private BindingContext bindingContext; @Before public void setUp() throws Exception { - ConversionService conversionService = new DefaultFormattingConversionService(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); - this.resolver = new RequestHeaderMethodArgumentResolver(conversionService, context.getBeanFactory()); + this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory()); @SuppressWarnings("ConfusingArgumentToVarargsMethod") Method method = ReflectionUtils.findMethod(getClass(), "params", (Class[]) null); @@ -95,6 +94,10 @@ public class RequestHeaderMethodArgumentResolverTests { ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/"); WebSessionManager sessionManager = new MockWebSessionManager(); this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager); + + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setConversionService(new DefaultFormattingConversionService()); + this.bindingContext = new BindingContext(initializer); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java index 5a74e6aed19..d19f1f19245 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java @@ -29,16 +29,15 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.tests.TestSubscriber; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; @@ -72,13 +71,12 @@ public class RequestParamMethodArgumentResolverTests { private MethodParameter paramNotRequired; private MethodParameter paramOptional; - private BindingContext bindingContext = new BindingContext(); + private BindingContext bindingContext; @Before @SuppressWarnings("ConfusingArgumentToVarargsMethod") public void setUp() throws Exception { - ConversionService conversionService = new DefaultConversionService(); - this.resolver = new RequestParamMethodArgumentResolver(conversionService, null, true); + this.resolver = new RequestParamMethodArgumentResolver(null, true); ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class[]) null); @@ -96,12 +94,17 @@ public class RequestParamMethodArgumentResolverTests { this.paramRequired = new SynthesizingMethodParameter(method, 5); this.paramNotRequired = new SynthesizingMethodParameter(method, 6); this.paramOptional = new SynthesizingMethodParameter(method, 7); + + + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setConversionService(new DefaultFormattingConversionService()); + this.bindingContext = new BindingContext(initializer); } @Test public void supportsParameter() { - this.resolver = new RequestParamMethodArgumentResolver(new GenericConversionService(), null, true); + this.resolver = new RequestParamMethodArgumentResolver(null, true); assertTrue(this.resolver.supportsParameter(this.paramNamedDefaultValueString)); assertTrue(this.resolver.supportsParameter(this.paramNamedStringArray)); assertTrue(this.resolver.supportsParameter(this.paramNamedMap)); @@ -111,7 +114,7 @@ public class RequestParamMethodArgumentResolverTests { assertTrue(this.resolver.supportsParameter(this.paramNotRequired)); assertTrue(this.resolver.supportsParameter(this.paramOptional)); - this.resolver = new RequestParamMethodArgumentResolver(new GenericConversionService(), null, false); + this.resolver = new RequestParamMethodArgumentResolver(null, false); assertFalse(this.resolver.supportsParameter(this.paramStringNotAnnot)); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java index e1dabd51d65..71c60481054 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java @@ -27,15 +27,15 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.tests.TestSubscriber; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.SessionAttribute; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.result.method.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; @@ -74,8 +74,7 @@ public class SessionAttributeMethodArgumentResolverTests { public void setUp() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); - ConversionService cs = new DefaultConversionService(); - this.resolver = new SessionAttributeMethodArgumentResolver(cs, context.getBeanFactory()); + this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory()); this.session = mock(WebSession.class); when(this.session.getAttribute(any())).thenReturn(Optional.empty()); @@ -136,9 +135,13 @@ public class SessionAttributeMethodArgumentResolverTests { assertEquals(Optional.class, mono.block().getClass()); assertFalse(((Optional) mono.block()).isPresent()); + ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); + initializer.setConversionService(new DefaultFormattingConversionService()); + BindingContext bindingContext = new BindingContext(initializer); + Foo foo = new Foo(); when(this.session.getAttribute("foo")).thenReturn(Optional.of(foo)); - mono = this.resolver.resolveArgument(param, new BindingContext(), this.exchange); + mono = this.resolver.resolveArgument(param, bindingContext, this.exchange); assertNotNull(mono.block()); assertEquals(Optional.class, mono.block().getClass());