提交 8a043ae9 编写于 作者: R Rossen Stoyanchev

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
上级 d87aa40e
......@@ -252,6 +252,8 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setMessageReaders(getMessageReaders());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
List<HandlerMethodArgumentResolver> 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;
}
......
......@@ -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:
* <pre>
* new WebDataBinder(null).getTypeConverter();
* </pre>
*/
public TypeConverter getTypeConverter() {
return this.typeConverter;
}
}
......@@ -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<HttpMessageReader<?>> messageReaders;
private final Validator validator;
private final ReactiveAdapterRegistry adapterRegistry;
private final List<MediaType> 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<HttpMessageReader<?>> readers, Validator validator) {
this(readers, validator, new ReactiveAdapterRegistry());
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> 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<HttpMessageReader<?>> 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<Object> 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<String, Object> 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 <T> Function<T, T> 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 <T> Function<T, Mono<T>> 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;
});
}
}
......@@ -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<MethodParameter, NamedValueInfo> 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<Object> 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<Object> 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);
}
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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<HttpMessageReader<?>> readers, Validator validator) {
super(readers, validator);
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> 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<HttpMessageReader<?>> readers, Validator validator,
ReactiveAdapterRegistry adapterRegistry) {
super(readers, validator, adapterRegistry);
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> 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));
}
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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<HttpMessageReader<?>> readers, Validator validator) {
super(readers, validator);
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> 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<HttpMessageReader<?>> readers, Validator validator,
ReactiveAdapterRegistry adapterRegistry) {
super(readers, validator, adapterRegistry);
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> 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);
}
}
......@@ -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);
}
......
......@@ -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<HandlerMethodArgumentResolver> argumentResolvers;
private ConversionService conversionService = new DefaultFormattingConversionService();
private Validator validator;
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, 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<HandlerMethodArgumentResolver> initArgumentResolvers() {
List<HandlerMethodArgumentResolver> 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;
}
......
......@@ -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;
}
......
......@@ -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);
}
......
......@@ -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());
}
......
......@@ -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();
......
......@@ -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();
......
......@@ -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<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new HttpEntityArgumentResolver(readers, mock(Validator.class));
return new HttpEntityArgumentResolver(readers);
}
......
......@@ -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<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> 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<TestBean> result = (Mono<TestBean>) this.resolver.readBody(param, true, this.exchange).block();
Mono<TestBean> result = (Mono<TestBean>) 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> T resolveValue(MethodParameter param, String body) {
this.request.setHeader("Content-Type", "application/json").setBody(body);
Mono<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> 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<HttpMessageReader<?>> readers = new ArrayList<>();
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
return new AbstractMessageReaderArgumentResolver(readers, new TestBeanValidator()) {};
return new AbstractMessageReaderArgumentResolver(readers) {};
}
......
......@@ -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<Object> mono = this.resolver.resolveArgument(this.paramOptional, bindingContext, this.exchange);
Object result = mono.block();
assertEquals(Optional.of("value"), result);
......
......@@ -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());
......
......@@ -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<HttpMessageReader<?>> 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> T resolveValue(MethodParameter param, String body) {
this.request.setBody(body);
Mono<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> result = this.resolver.readBody(param, true, new BindingContext(), this.exchange);
Object value = result.block(Duration.ofSeconds(5));
assertNotNull(value);
......
......@@ -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);
}
......
......@@ -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));
}
......
......@@ -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());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册