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
This commit is contained in:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user