Browse Source

Reactive type checks for all argument method resolvers

All method argument resolvers now explicitly check for the presence
of a reactive type wrapper and reject it where not expected.

Issue: SPR-15297
pull/1357/merge
Rossen Stoyanchev 8 years ago
parent
commit
164204ca04
  1. 136
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverSupport.java
  2. 14
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
  3. 11
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java
  4. 13
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java
  5. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java
  6. 24
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java
  7. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java
  8. 17
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
  9. 14
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java
  10. 45
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
  11. 20
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
  12. 26
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java
  13. 25
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java
  14. 17
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java
  15. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
  16. 20
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java
  17. 17
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java
  18. 56
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
  19. 25
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java
  20. 41
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java
  21. 20
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java
  22. 7
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java
  23. 25
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java
  24. 25
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java
  25. 19
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsArgumentResolverTests.java
  26. 27
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java
  27. 26
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
  28. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContextTests.java
  29. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java
  30. 14
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelInitializerTests.java
  31. 21
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolverTests.java
  32. 27
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java
  33. 16
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java
  34. 3
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java
  35. 28
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java
  36. 18
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java
  37. 19
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java
  38. 46
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java
  39. 16
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java
  40. 14
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java
  41. 3
      spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverKotlinTests.kt

136
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/HandlerMethodArgumentResolverSupport.java

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.result.method;
import java.lang.annotation.Annotation;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.util.Assert;
/**
* Base class for {@link HandlerMethodArgumentResolver} implementations with
* access to a {@code ReactiveAdapterRegistry} and methods to check for
* method parameter support.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public abstract class HandlerMethodArgumentResolverSupport {
private final ReactiveAdapterRegistry adapterRegistry;
protected HandlerMethodArgumentResolverSupport(ReactiveAdapterRegistry adapterRegistry) {
Assert.notNull(adapterRegistry, "ReactiveAdapterRegistry is required");
this.adapterRegistry = adapterRegistry;
}
/**
* Return the configured {@link ReactiveAdapterRegistry}.
*/
public ReactiveAdapterRegistry getAdapterRegistry() {
return this.adapterRegistry;
}
/**
* Evaluate the {@code Predicate} on the the method parameter type or on
* the generic type within a reactive type wrapper.
*/
protected boolean checkParamType(MethodParameter param, Predicate<Class<?>> predicate) {
Class<?> type = param.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, param);
type = param.nested().getNestedParameterType();
}
return predicate.test(type);
}
private void assertHasValues(ReactiveAdapter adapter, MethodParameter param) {
if (adapter.isNoValue()) {
throw new IllegalArgumentException(
"No value reactive types not supported: " + param.getGenericParameterType());
}
}
/**
* Evaluate the {@code Predicate} on the method parameter type but raise an
* {@code IllegalStateException} if the same matches the generic type
* within a reactive type wrapper.
*/
protected boolean checkParamTypeNoReactiveWrapper(MethodParameter param, Predicate<Class<?>> predicate) {
Class<?> type = param.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, param);
type = param.nested().getNestedParameterType();
}
if (predicate.test(type)) {
if (adapter == null) {
return true;
}
throw getReactiveWrapperError(param);
}
return false;
}
private IllegalStateException getReactiveWrapperError(MethodParameter param) {
return new IllegalStateException(getClass().getSimpleName() +
" doesn't support reactive type wrapper: " + param.getGenericParameterType());
}
/**
* Evaluate the {@code Predicate} on the method parameter type if it has the
* given annotation, nesting within {@link java.util.Optional} if necessary,
* but raise an {@code IllegalStateException} if the same matches the generic
* type within a reactive type wrapper.
*/
protected <A extends Annotation> boolean checkAnnotatedParamNoReactiveWrapper(
MethodParameter param, Class<A> annotationType,
BiPredicate<A, Class<?>> typePredicate) {
A annotation = param.getParameterAnnotation(annotationType);
if (annotation == null) {
return false;
}
param = param.nestedIfOptional();
Class<?> type = param.getNestedParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, param);
param = param.nested();
type = param.getNestedParameterType();
}
if (typePredicate.test(annotation, type)) {
if (adapter == null) {
return true;
}
throw getReactiveWrapperError(param);
}
return false;
}
}

14
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java

@ -42,6 +42,7 @@ import org.springframework.validation.annotation.Validated; @@ -42,6 +42,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.bind.support.WebExchangeDataBinder;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
@ -58,12 +59,10 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException; @@ -58,12 +59,10 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
* @author Rossen Stoyanchev
* @since 5.0
*/
public abstract class AbstractMessageReaderArgumentResolver {
public abstract class AbstractMessageReaderArgumentResolver extends HandlerMethodArgumentResolverSupport {
private final List<HttpMessageReader<?>> messageReaders;
private final ReactiveAdapterRegistry adapterRegistry;
private final List<MediaType> supportedMediaTypes;
@ -83,10 +82,10 @@ public abstract class AbstractMessageReaderArgumentResolver { @@ -83,10 +82,10 @@ public abstract class AbstractMessageReaderArgumentResolver {
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> messageReaders,
ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
Assert.notEmpty(messageReaders, "At least one HttpMessageReader is required.");
Assert.notNull(adapterRegistry, "'adapterRegistry' is required");
this.messageReaders = messageReaders;
this.adapterRegistry = adapterRegistry;
this.supportedMediaTypes = messageReaders.stream()
.flatMap(converter -> converter.getReadableMediaTypes().stream())
.collect(Collectors.toList());
@ -100,13 +99,6 @@ public abstract class AbstractMessageReaderArgumentResolver { @@ -100,13 +99,6 @@ public abstract class AbstractMessageReaderArgumentResolver {
return this.messageReaders;
}
/**
* Return the configured {@link ReactiveAdapterRegistry}.
*/
public ReactiveAdapterRegistry getAdapterRegistry() {
return this.adapterRegistry;
}
protected Mono<Object> readBody(MethodParameter bodyParameter, boolean isBodyRequired,
BindingContext bindingContext, ServerWebExchange exchange) {

11
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java

@ -27,11 +27,13 @@ import org.springframework.beans.factory.config.BeanExpressionContext; @@ -27,11 +27,13 @@ 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.ReactiveAdapterRegistry;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerErrorException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
@ -56,7 +58,8 @@ import org.springframework.web.server.ServerWebInputException; @@ -56,7 +58,8 @@ import org.springframework.web.server.ServerWebInputException;
* @author Rossen Stoyanchev
* @since 5.0
*/
public abstract class AbstractNamedValueArgumentResolver implements HandlerMethodArgumentResolver {
public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodArgumentResolverSupport
implements HandlerMethodArgumentResolver {
private final ConfigurableBeanFactory configurableBeanFactory;
@ -69,8 +72,12 @@ public abstract class AbstractNamedValueArgumentResolver implements HandlerMetho @@ -69,8 +72,12 @@ public abstract class AbstractNamedValueArgumentResolver implements HandlerMetho
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public AbstractNamedValueArgumentResolver(ConfigurableBeanFactory beanFactory) {
public AbstractNamedValueArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
this.configurableBeanFactory = beanFactory;
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
}

13
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java

@ -22,6 +22,7 @@ import reactor.core.publisher.Mono; @@ -22,6 +22,7 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -39,8 +40,16 @@ public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNam @@ -39,8 +40,16 @@ public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNam
implements SyncHandlerMethodArgumentResolver {
protected AbstractNamedValueSyncArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
/**
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
protected AbstractNamedValueSyncArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}

12
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java

@ -20,6 +20,7 @@ import java.util.Optional; @@ -20,6 +20,7 @@ import java.util.Optional;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpCookie;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.server.ServerWebExchange;
@ -42,15 +43,18 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArg @@ -42,15 +43,18 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArg
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public CookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
public CookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CookieValue.class);
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, CookieValue.class, (annot, type) -> true);
}
@Override

24
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java

@ -30,6 +30,7 @@ import org.springframework.validation.Errors; @@ -30,6 +30,7 @@ import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;
/**
@ -40,33 +41,18 @@ import org.springframework.web.server.ServerWebExchange; @@ -40,33 +41,18 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver {
public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements HandlerMethodArgumentResolver {
private final ReactiveAdapterRegistry adapterRegistry;
/**
* Class constructor.
* @param registry for adapting to other reactive types from and to Mono
*/
public ErrorsMethodArgumentResolver(ReactiveAdapterRegistry registry) {
Assert.notNull(registry, "'ReactiveAdapterRegistry' is required.");
this.adapterRegistry = registry;
}
/**
* Return the configured {@link ReactiveAdapterRegistry}.
*/
public ReactiveAdapterRegistry getAdapterRegistry() {
return this.adapterRegistry;
super(registry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz = parameter.getParameterType();
return Errors.class.isAssignableFrom(clazz);
return checkParamTypeNoReactiveWrapper(parameter, Errors.class::isAssignableFrom);
}

12
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java

@ -21,6 +21,7 @@ import java.util.Optional; @@ -21,6 +21,7 @@ import java.util.Optional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.web.server.ServerWebExchange;
/**
@ -40,15 +41,18 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueSyn @@ -40,15 +41,18 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueSyn
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Value.class);
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, Value.class, (annot, type) -> true);
}
@Override

17
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java

@ -26,7 +26,6 @@ import org.springframework.http.HttpEntity; @@ -26,7 +26,6 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.RequestEntity;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -42,19 +41,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -42,19 +41,7 @@ import org.springframework.web.server.ServerWebExchange;
public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentResolver
implements HandlerMethodArgumentResolver {
/**
* Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
* @param readers readers for de-serializing the request body with
*/
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 registry for adapting to other reactive types from Flux and Mono
*/
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
super(readers, registry);
}
@ -62,8 +49,8 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes @@ -62,8 +49,8 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz = parameter.getParameterType();
return (HttpEntity.class.equals(clazz) || RequestEntity.class.equals(clazz));
return checkParamTypeNoReactiveWrapper(parameter,
type -> HttpEntity.class.equals(type) || RequestEntity.class.equals(type));
}
@Override

14
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java

@ -19,8 +19,11 @@ package org.springframework.web.reactive.result.method.annotation; @@ -19,8 +19,11 @@ package org.springframework.web.reactive.result.method.annotation;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -30,18 +33,25 @@ import org.springframework.web.server.ServerWebExchange; @@ -30,18 +33,25 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ModelArgumentResolver implements SyncHandlerMethodArgumentResolver {
public class ModelArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public ModelArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Model.class.isAssignableFrom(parameter.getParameterType());
return checkParamTypeNoReactiveWrapper(parameter, Model.class::isAssignableFrom);
}
@Override
public Optional<Object> resolveArgumentValue(MethodParameter methodParameter,
BindingContext context, ServerWebExchange exchange) {
Assert.isAssignable(Model.class, methodParameter.getParameterType());
return Optional.of(context.getModel());
}

45
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java

@ -40,6 +40,7 @@ import org.springframework.web.bind.support.WebExchangeBindException; @@ -40,6 +40,7 @@ import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.bind.support.WebExchangeDataBinder;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;
/**
@ -59,42 +60,24 @@ import org.springframework.web.server.ServerWebExchange; @@ -59,42 +60,24 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgumentResolver {
private final ReactiveAdapterRegistry adapterRegistry;
public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements HandlerMethodArgumentResolver {
private final boolean useDefaultResolution;
/**
* Class constructor.
* @param registry for adapting to other reactive types from and to Mono
*/
public ModelAttributeMethodArgumentResolver(ReactiveAdapterRegistry registry) {
this(registry, false);
}
/**
* Class constructor with a default resolution mode flag.
* @param registry for adapting to other reactive types from and to Mono
* @param adapterRegistry for adapting to other reactive types from and to Mono
* @param useDefaultResolution if "true", non-simple method arguments and
* return values are considered model attributes with or without a
* {@code @ModelAttribute} annotation present.
*/
public ModelAttributeMethodArgumentResolver(ReactiveAdapterRegistry registry,
public ModelAttributeMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry,
boolean useDefaultResolution) {
Assert.notNull(registry, "'ReactiveAdapterRegistry' is required.");
super(adapterRegistry);
this.useDefaultResolution = useDefaultResolution;
this.adapterRegistry = registry;
}
/**
* Return the configured {@link ReactiveAdapterRegistry}.
*/
public ReactiveAdapterRegistry getAdapterRegistry() {
return this.adapterRegistry;
}
@ -103,16 +86,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume @@ -103,16 +86,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
return true;
}
if (this.useDefaultResolution) {
Class<?> clazz = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(clazz);
if (adapter != null) {
if (adapter.isNoValue() || adapter.isMultiValue()) {
return false;
}
clazz = parameter.nested().getNestedParameterType();
}
return !BeanUtils.isSimpleProperty(clazz);
else if (this.useDefaultResolution) {
return checkParamType(parameter, type -> !BeanUtils.isSimpleProperty(type));
}
return false;
}
@ -125,6 +100,10 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume @@ -125,6 +100,10 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.resolve());
ResolvableType valueType = (adapter != null ? type.getGeneric(0) : type);
Assert.state(adapter == null || !adapter.isMultiValue(),
getClass().getSimpleName() + " doesn't support multi-value reactive type wrapper: " +
parameter.getGenericParameterType());
String name = getAttributeName(valueType, parameter);
Mono<?> valueMono = getAttributeMono(name, valueType, context.getModel());

20
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java

@ -21,10 +21,12 @@ import java.util.Map; @@ -21,10 +21,12 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -38,17 +40,25 @@ import org.springframework.web.server.ServerWebExchange; @@ -38,17 +40,25 @@ import org.springframework.web.server.ServerWebExchange;
* @since 5.0
* @see PathVariableMethodArgumentResolver
*/
public class PathVariableMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver {
public class PathVariableMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public PathVariableMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class);
return (annotation != null &&
Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(annotation.value()));
return checkAnnotatedParamNoReactiveWrapper(parameter, PathVariable.class, this::allVariables);
}
private boolean allVariables(PathVariable pathVariable, Class<?> type) {
return Map.class.isAssignableFrom(type) && !StringUtils.hasText(pathVariable.value());
}
@Override
public Optional<Object> resolveArgumentValue(MethodParameter methodParameter,
BindingContext context, ServerWebExchange exchange) {

26
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java

@ -21,6 +21,7 @@ import java.util.Optional; @@ -21,6 +21,7 @@ import java.util.Optional;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.converter.Converter;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
@ -52,21 +53,26 @@ import org.springframework.web.server.ServerWebExchange; @@ -52,21 +53,26 @@ import org.springframework.web.server.ServerWebExchange;
public class PathVariableMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
/**
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
return false;
}
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
return StringUtils.hasText(paramName);
}
return true;
return checkAnnotatedParamNoReactiveWrapper(parameter, PathVariable.class, this::singlePathVariable);
}
private boolean singlePathVariable(PathVariable pathVariable, Class<?> type) {
return !Map.class.isAssignableFrom(type) || StringUtils.hasText(pathVariable.name());
}
@Override

25
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java

@ -21,8 +21,11 @@ import java.security.Principal; @@ -21,8 +21,11 @@ import java.security.Principal;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.util.Assert;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;
/**
@ -32,26 +35,26 @@ import org.springframework.web.server.ServerWebExchange; @@ -32,26 +35,26 @@ import org.springframework.web.server.ServerWebExchange;
* @since 5.0
* @see ServerWebExchangeArgumentResolver
*/
public class PrincipalArgumentResolver implements HandlerMethodArgumentResolver {
public class PrincipalArgumentResolver extends HandlerMethodArgumentResolverSupport
implements HandlerMethodArgumentResolver {
public PrincipalArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (Principal.class.isAssignableFrom(parameter.getParameterType()));
return checkParamTypeNoReactiveWrapper(parameter, Principal.class::isAssignableFrom);
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext context,
ServerWebExchange exchange) {
Class<?> paramType = parameter.getParameterType();
if (Principal.class.isAssignableFrom(paramType)) {
return exchange.getPrincipal().cast(Object.class);
}
else {
// should never happen...
throw new IllegalArgumentException(
"Unknown parameter type: " + paramType + " in method: " + parameter.getMethod());
}
Assert.isAssignable(Principal.class, parameter.getParameterType());
return exchange.getPrincipal().cast(Object.class);
}
}

17
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java

@ -19,6 +19,7 @@ import java.util.Optional; @@ -19,6 +19,7 @@ import java.util.Optional;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.server.ServerWebExchange;
@ -34,14 +35,22 @@ import org.springframework.web.server.ServerWebInputException; @@ -34,14 +35,22 @@ import org.springframework.web.server.ServerWebInputException;
public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
/**
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestAttribute.class);
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, RequestAttribute.class, (annot, type) -> true);
}

12
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java

@ -47,19 +47,7 @@ import org.springframework.web.server.ServerWebInputException; @@ -47,19 +47,7 @@ import org.springframework.web.server.ServerWebInputException;
public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver
implements HandlerMethodArgumentResolver {
/**
* Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
* @param readers readers for de-serializing the request body with
*/
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 registry for adapting to other reactive types from Flux and Mono
*/
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
super(readers, registry);
}

20
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java

@ -20,10 +20,12 @@ import java.util.Map; @@ -20,10 +20,12 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpHeaders;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -40,15 +42,25 @@ import org.springframework.web.server.ServerWebExchange; @@ -40,15 +42,25 @@ import org.springframework.web.server.ServerWebExchange;
* @since 5.0
* @see RequestHeaderMethodArgumentResolver
*/
public class RequestHeaderMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver {
public class RequestHeaderMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public RequestHeaderMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
Map.class.isAssignableFrom(parameter.getParameterType()));
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, RequestHeader.class, this::allParams);
}
private boolean allParams(RequestHeader annotation, Class<?> type) {
return Map.class.isAssignableFrom(type);
}
@Override
public Optional<Object> resolveArgumentValue(MethodParameter methodParameter,
BindingContext context, ServerWebExchange exchange) {

17
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java

@ -22,6 +22,7 @@ import java.util.Optional; @@ -22,6 +22,7 @@ import java.util.Optional;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.ConversionService;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.server.ServerWebExchange;
@ -49,16 +50,22 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueSyncA @@ -49,16 +50,22 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueSyncA
* @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
* @param adapterRegistry for checking reactive type wrappers
*/
public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(RequestHeader.class) &&
!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, RequestHeader.class, this::singleParam);
}
private boolean singleParam(RequestHeader annotation, Class<?> type) {
return !Map.class.isAssignableFrom(type);
}
@Override

56
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java

@ -294,26 +294,26 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -294,26 +294,26 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(getBeanFactory()));
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new PathVariableMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new PathVariableMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new RequestBodyArgumentResolver(getMessageReaders(), getReactiveAdapterRegistry()));
resolvers.add(new ModelAttributeMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new CookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestAttributeMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ModelAttributeMethodArgumentResolver(getReactiveAdapterRegistry(), false));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new CookieValueMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new SessionAttributeMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new RequestAttributeMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
// Type-based argument resolution
resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), getReactiveAdapterRegistry()));
resolvers.add(new ModelArgumentResolver());
resolvers.add(new ModelArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new ErrorsMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new ServerWebExchangeArgumentResolver());
resolvers.add(new PrincipalArgumentResolver());
resolvers.add(new WebSessionArgumentResolver());
resolvers.add(new ServerWebExchangeArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new PrincipalArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new WebSessionArgumentResolver(getReactiveAdapterRegistry()));
// Custom resolvers
if (getCustomArgumentResolvers() != null) {
@ -321,7 +321,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -321,7 +321,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry(), true));
resolvers.add(new ModelAttributeMethodArgumentResolver(getReactiveAdapterRegistry(), true));
return resolvers;
}
@ -330,19 +330,19 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -330,19 +330,19 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
List<SyncHandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(getBeanFactory()));
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new CookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestAttributeMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new PathVariableMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new PathVariableMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new CookieValueMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
resolvers.add(new RequestAttributeMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry()));
// Type-based argument resolution
resolvers.add(new ModelArgumentResolver());
resolvers.add(new ServerWebExchangeArgumentResolver());
resolvers.add(new ModelArgumentResolver(getReactiveAdapterRegistry()));
resolvers.add(new ServerWebExchangeArgumentResolver(getReactiveAdapterRegistry()));
// Custom resolvers
if (getCustomInitBinderArgumentResolvers() != null) {
@ -350,7 +350,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -350,7 +350,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), getReactiveAdapterRegistry(), true));
return resolvers;
}

25
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java

@ -20,11 +20,13 @@ import java.util.Map; @@ -20,11 +20,13 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -43,20 +45,25 @@ import org.springframework.web.server.ServerWebExchange; @@ -43,20 +45,25 @@ import org.springframework.web.server.ServerWebExchange;
* @since 5.0
* @see RequestParamMethodArgumentResolver
*/
public class RequestParamMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver {
public class RequestParamMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public RequestParamMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter methodParam) {
RequestParam requestParam = methodParam.getParameterAnnotation(RequestParam.class);
if (requestParam != null) {
if (Map.class.isAssignableFrom(methodParam.getParameterType())) {
return !StringUtils.hasText(requestParam.name());
}
}
return false;
public boolean supportsParameter(MethodParameter param) {
return checkAnnotatedParamNoReactiveWrapper(param, RequestParam.class, this::allParams);
}
private boolean allParams(RequestParam requestParam, Class<?> type) {
return Map.class.isAssignableFrom(type) && !StringUtils.hasText(requestParam.name());
}
@Override
public Optional<Object> resolveArgumentValue(MethodParameter methodParameter,
BindingContext context, ServerWebExchange exchange) {

41
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java

@ -23,6 +23,7 @@ import java.util.Optional; @@ -23,6 +23,7 @@ import java.util.Optional;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
@ -56,46 +57,38 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr @@ -56,46 +57,38 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
private final boolean useDefaultResolution;
/**
* Class constructor.
* @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
*/
public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
this(beanFactory, false);
}
/**
* Class constructor with a default resolution mode flag.
* @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
* @param adapterRegistry for checking reactive type wrappers
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* 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(ConfigurableBeanFactory beanFactory,
boolean useDefaultResolution) {
ReactiveAdapterRegistry adapterRegistry, boolean useDefaultResolution) {
super(beanFactory);
super(beanFactory, adapterRegistry);
this.useDefaultResolution = useDefaultResolution;
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(RequestParam.class)) {
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String paramName = parameter.getParameterAnnotation(RequestParam.class).name();
return StringUtils.hasText(paramName);
}
else {
return true;
}
public boolean supportsParameter(MethodParameter param) {
if (checkAnnotatedParamNoReactiveWrapper(param, RequestParam.class, this::singleParam)) {
return true;
}
else if (this.useDefaultResolution) {
return checkParamTypeNoReactiveWrapper(param, BeanUtils::isSimpleProperty);
}
return (this.useDefaultResolution && BeanUtils.isSimpleProperty(parameter.getNestedParameterType()));
return false;
}
private boolean singleParam(RequestParam requestParam, Class<?> type) {
return !Map.class.isAssignableFrom(type) || StringUtils.hasText(requestParam.name());
}
@Override
@ -132,11 +125,11 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr @@ -132,11 +125,11 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
private static class RequestParamNamedValueInfo extends NamedValueInfo {
public RequestParamNamedValueInfo() {
RequestParamNamedValueInfo() {
super("", false, ValueConstants.DEFAULT_NONE);
}
public RequestParamNamedValueInfo(RequestParam annotation) {
RequestParamNamedValueInfo(RequestParam annotation) {
super(annotation.name(), annotation.required(), annotation.defaultValue());
}
}

20
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java

@ -19,10 +19,12 @@ package org.springframework.web.reactive.result.method.annotation; @@ -19,10 +19,12 @@ package org.springframework.web.reactive.result.method.annotation;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
@ -43,16 +45,22 @@ import org.springframework.web.server.ServerWebExchange; @@ -43,16 +45,22 @@ import org.springframework.web.server.ServerWebExchange;
* @see WebSessionArgumentResolver
* @see PrincipalArgumentResolver
*/
public class ServerWebExchangeArgumentResolver implements SyncHandlerMethodArgumentResolver {
public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public ServerWebExchangeArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
return (ServerWebExchange.class.isAssignableFrom(paramType) ||
ServerHttpRequest.class.isAssignableFrom(paramType) ||
ServerHttpResponse.class.isAssignableFrom(paramType) ||
HttpMethod.class == paramType);
return checkParamTypeNoReactiveWrapper(parameter,
type -> ServerWebExchange.class.isAssignableFrom(type) ||
ServerHttpRequest.class.isAssignableFrom(type) ||
ServerHttpResponse.class.isAssignableFrom(type) ||
HttpMethod.class == type);
}
@Override

7
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java

@ -21,6 +21,7 @@ import reactor.core.publisher.Mono; @@ -21,6 +21,7 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.server.ServerWebExchange;
@ -36,8 +37,10 @@ import org.springframework.web.server.ServerWebInputException; @@ -36,8 +37,10 @@ import org.springframework.web.server.ServerWebInputException;
public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueArgumentResolver {
public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
super(beanFactory);
public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
ReactiveAdapterRegistry adapterRegistry) {
super(beanFactory, adapterRegistry);
}

25
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java

@ -19,8 +19,11 @@ package org.springframework.web.reactive.result.method.annotation; @@ -19,8 +19,11 @@ package org.springframework.web.reactive.result.method.annotation;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.util.Assert;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
@ -31,26 +34,26 @@ import org.springframework.web.server.WebSession; @@ -31,26 +34,26 @@ import org.springframework.web.server.WebSession;
* @since 5.0
* @see ServerWebExchangeArgumentResolver
*/
public class WebSessionArgumentResolver implements HandlerMethodArgumentResolver {
public class WebSessionArgumentResolver extends HandlerMethodArgumentResolverSupport
implements HandlerMethodArgumentResolver {
public WebSessionArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return (WebSession.class.isAssignableFrom(parameter.getParameterType()));
return checkParamTypeNoReactiveWrapper(parameter, WebSession.class::isAssignableFrom);
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext context,
ServerWebExchange exchange) {
Class<?> paramType = parameter.getParameterType();
if (WebSession.class.isAssignableFrom(paramType)) {
return exchange.getSession().cast(Object.class);
}
else {
// should never happen...
throw new IllegalArgumentException(
"Unknown parameter type: " + paramType + " in method: " + parameter.getMethod());
}
Assert.isAssignable(WebSession.class, parameter.getParameterType());
return exchange.getSession().cast(Object.class);
}
}

25
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolverTests.java

@ -25,11 +25,13 @@ import reactor.test.StepVerifier; @@ -25,11 +25,13 @@ import reactor.test.StepVerifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpCookie;
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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebInputException;
@ -53,6 +55,7 @@ public class CookieValueMethodArgumentResolverTests { @@ -53,6 +55,7 @@ public class CookieValueMethodArgumentResolverTests {
private MethodParameter cookieParameter;
private MethodParameter cookieStringParameter;
private MethodParameter stringParameter;
private MethodParameter cookieMonoParameter;
@Before
@ -60,14 +63,16 @@ public class CookieValueMethodArgumentResolverTests { @@ -60,14 +63,16 @@ public class CookieValueMethodArgumentResolverTests {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.request = MockServerHttpRequest.get("/").build();
this.bindingContext = new BindingContext();
Method method = getClass().getMethod("params", HttpCookie.class, String.class, String.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
this.cookieParameter = new SynthesizingMethodParameter(method, 0);
this.cookieStringParameter = new SynthesizingMethodParameter(method, 1);
this.stringParameter = new SynthesizingMethodParameter(method, 2);
this.cookieMonoParameter = new SynthesizingMethodParameter(method, 3);
}
@ -75,7 +80,20 @@ public class CookieValueMethodArgumentResolverTests { @@ -75,7 +80,20 @@ public class CookieValueMethodArgumentResolverTests {
public void supportsParameter() {
assertTrue(this.resolver.supportsParameter(this.cookieParameter));
assertTrue(this.resolver.supportsParameter(this.cookieStringParameter));
}
@Test
public void doesNotSupportParameter() {
assertFalse(this.resolver.supportsParameter(this.stringParameter));
try {
this.resolver.supportsParameter(this.cookieMonoParameter);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"CookieValueMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -128,7 +146,8 @@ public class CookieValueMethodArgumentResolverTests { @@ -128,7 +146,8 @@ public class CookieValueMethodArgumentResolverTests {
public void params(
@CookieValue("name") HttpCookie cookie,
@CookieValue(name = "name", defaultValue = "bar") String cookieString,
String stringParam) {
String stringParam,
@CookieValue Mono<String> monoCookie) {
}
}

19
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsArgumentResolverTests.java

@ -38,6 +38,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -38,6 +38,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link ErrorsMethodArgumentResolver}.
@ -78,12 +79,24 @@ public class ErrorsArgumentResolverTests { @@ -78,12 +79,24 @@ public class ErrorsArgumentResolverTests {
parameter = this.testMethod.arg(BindingResult.class);
assertTrue(this.resolver.supportsParameter(parameter));
}
parameter = this.testMethod.arg(ResolvableType.forClassWithGenerics(Mono.class, Errors.class));
assertFalse(this.resolver.supportsParameter(parameter));
@Test
public void doesNotSupport() throws Exception {
parameter = this.testMethod.arg(String.class);
MethodParameter parameter = this.testMethod.arg(String.class);
assertFalse(this.resolver.supportsParameter(parameter));
try {
parameter = this.testMethod.arg(ResolvableType.forClassWithGenerics(Mono.class, Errors.class));
assertFalse(this.resolver.supportsParameter(parameter));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ErrorsMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test

27
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolverTests.java

@ -25,9 +25,11 @@ import reactor.core.publisher.Mono; @@ -25,9 +25,11 @@ 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.ReactiveAdapterRegistry;
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.util.ReflectionUtils;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@ -47,27 +49,43 @@ public class ExpressionValueMethodArgumentResolverTests { @@ -47,27 +49,43 @@ public class ExpressionValueMethodArgumentResolverTests {
private MethodParameter paramSystemProperty;
private MethodParameter paramNotSupported;
private MethodParameter paramAlsoNotSupported;
@Before
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
Method method = getClass().getMethod("params", int.class, String.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
this.paramSystemProperty = new MethodParameter(method, 0);
this.paramNotSupported = new MethodParameter(method, 1);
this.paramAlsoNotSupported = new MethodParameter(method, 2);
}
@Test
public void supportsParameter() throws Exception {
assertTrue(this.resolver.supportsParameter(this.paramSystemProperty));
}
@Test
public void doesNotSupport() throws Exception {
assertFalse(this.resolver.supportsParameter(this.paramNotSupported));
try {
this.resolver.supportsParameter(this.paramAlsoNotSupported);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ExpressionValueMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -90,7 +108,10 @@ public class ExpressionValueMethodArgumentResolverTests { @@ -90,7 +108,10 @@ public class ExpressionValueMethodArgumentResolverTests {
@SuppressWarnings("unused")
public void params(@Value("#{systemProperties.systemProperty}") int param1, String notSupported) {
public void params(
@Value("#{systemProperties.systemProperty}") int param1,
String notSupported,
@Value("#{systemProperties.foo}") Mono<String> alsoNotSupported) {
}
}

26
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java

@ -34,6 +34,7 @@ import rx.RxReactiveStreams; @@ -34,6 +34,7 @@ import rx.RxReactiveStreams;
import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.HttpEntity;
@ -44,14 +45,19 @@ import org.springframework.http.codec.HttpMessageReader; @@ -44,14 +45,19 @@ 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.util.ObjectUtils;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.*;
import static org.springframework.core.ResolvableType.*;
import static org.junit.Assert.assertEquals;
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.junit.Assert.fail;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
/**
* Unit tests for {@link HttpEntityArgumentResolver}.When adding a test also
@ -78,7 +84,7 @@ public class HttpEntityArgumentResolverTests { @@ -78,7 +84,7 @@ public class HttpEntityArgumentResolverTests {
private HttpEntityArgumentResolver createResolver() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new HttpEntityArgumentResolver(readers);
return new HttpEntityArgumentResolver(readers, new ReactiveAdapterRegistry());
}
@ -105,6 +111,15 @@ public class HttpEntityArgumentResolverTests { @@ -105,6 +111,15 @@ public class HttpEntityArgumentResolverTests {
public void doesNotSupport() throws Exception {
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(Mono.class, String.class)));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
try {
this.resolver.supportsParameter(this.testMethod.arg(Mono.class, httpEntityType(String.class)));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"HttpEntityArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -348,6 +363,7 @@ public class HttpEntityArgumentResolverTests { @@ -348,6 +363,7 @@ public class HttpEntityArgumentResolverTests {
HttpEntity<io.reactivex.Observable<String>> rxJava2ObservableBody,
HttpEntity<Flowable<String>> flowableBody,
HttpEntity<CompletableFuture<String>> completableFutureBody,
RequestEntity<String> requestEntity) {}
RequestEntity<String> requestEntity,
Mono<HttpEntity<String>> httpEntityMono) {}
}

4
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/InitBinderBindingContextTests.java

@ -25,6 +25,7 @@ import org.junit.Before; @@ -25,6 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
@ -112,7 +113,8 @@ public class InitBinderBindingContextTests { @@ -112,7 +113,8 @@ public class InitBinderBindingContextTests {
@Test
public void createBinderTypeConversion() throws Exception {
this.request = MockServerHttpRequest.get("/path?requestParam=22").build();
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(null, false));
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(null, adapterRegistry, false));
BindingContext context = createBindingContext("initBinderTypeConversion", WebDataBinder.class, int.class);
WebDataBinder dataBinder = context.createDataBinder(createExchange(), null, "foo");

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java

@ -281,7 +281,7 @@ public class ModelAttributeMethodArgumentResolverTests { @@ -281,7 +281,7 @@ public class ModelAttributeMethodArgumentResolverTests {
private ModelAttributeMethodArgumentResolver createResolver() {
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry());
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry(), false);
}
private ServerWebExchange exchange(String formData) throws URISyntaxException {

14
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelInitializerTests.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -120,14 +121,17 @@ public class ModelInitializerTests { @@ -120,14 +121,17 @@ public class ModelInitializerTests {
private List<InvocableHandlerMethod> getAttributeMethods(Object controller) {
return MethodIntrospector
.selectMethods(controller.getClass(), ATTRIBUTE_METHODS).stream()
.map(method -> {
InvocableHandlerMethod invocable = new InvocableHandlerMethod(controller, method);
invocable.setArgumentResolvers(Collections.singletonList(new ModelArgumentResolver()));
return invocable;
})
.map(method -> toInvocable(controller, method))
.collect(Collectors.toList());
}
private InvocableHandlerMethod toInvocable(Object controller, Method method) {
ModelArgumentResolver resolver = new ModelArgumentResolver(new ReactiveAdapterRegistry());
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(controller, method);
handlerMethod.setArgumentResolvers(Collections.singletonList(resolver));
return handlerMethod;
}
@SuppressWarnings("unused")
private static class TestController {

21
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolverTests.java

@ -26,9 +26,11 @@ import org.junit.Test; @@ -26,9 +26,11 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
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.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerMapping;
@ -38,6 +40,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -38,6 +40,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link PathVariableMapMethodArgumentResolver}.
@ -53,19 +56,21 @@ public class PathVariableMapMethodArgumentResolverTests { @@ -53,19 +56,21 @@ public class PathVariableMapMethodArgumentResolverTests {
private MethodParameter paramMap;
private MethodParameter paramNamedMap;
private MethodParameter paramMapNoAnnot;
private MethodParameter paramMonoMap;
@Before
public void setup() throws Exception {
this.resolver = new PathVariableMapMethodArgumentResolver();
this.resolver = new PathVariableMapMethodArgumentResolver(new ReactiveAdapterRegistry());
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
Method method = getClass().getMethod("handle", Map.class, Map.class, Map.class);
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
this.paramMap = new MethodParameter(method, 0);
this.paramNamedMap = new MethodParameter(method, 1);
this.paramMapNoAnnot = new MethodParameter(method, 2);
this.paramMonoMap = new MethodParameter(method, 3);
}
@ -74,6 +79,15 @@ public class PathVariableMapMethodArgumentResolverTests { @@ -74,6 +79,15 @@ public class PathVariableMapMethodArgumentResolverTests {
assertTrue(resolver.supportsParameter(paramMap));
assertFalse(resolver.supportsParameter(paramNamedMap));
assertFalse(resolver.supportsParameter(paramMapNoAnnot));
try {
this.resolver.supportsParameter(this.paramMonoMap);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"PathVariableMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -102,7 +116,8 @@ public class PathVariableMapMethodArgumentResolverTests { @@ -102,7 +116,8 @@ public class PathVariableMapMethodArgumentResolverTests {
public void handle(
@PathVariable Map<String, String> map,
@PathVariable(value = "name") Map<String, String> namedMap,
Map<String, String> mapWithoutAnnotat) {
Map<String, String> mapWithoutAnnotat,
@PathVariable Mono<Map<?, ?>> monoMap) {
}
}

27
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolverTests.java

@ -27,6 +27,7 @@ import reactor.core.publisher.Mono; @@ -27,6 +27,7 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -44,6 +45,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -44,6 +45,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link PathVariableMethodArgumentResolver}.
@ -58,17 +60,15 @@ public class PathVariableMethodArgumentResolverTests { @@ -58,17 +60,15 @@ public class PathVariableMethodArgumentResolverTests {
private ServerWebExchange exchange;
private MethodParameter paramNamedString;
private MethodParameter paramString;
private MethodParameter paramNotRequired;
private MethodParameter paramOptional;
private MethodParameter paramMono;
@Before
public void setup() throws Exception {
this.resolver = new PathVariableMethodArgumentResolver(null);
this.resolver = new PathVariableMethodArgumentResolver(null, new ReactiveAdapterRegistry());
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
@ -78,6 +78,7 @@ public class PathVariableMethodArgumentResolverTests { @@ -78,6 +78,7 @@ public class PathVariableMethodArgumentResolverTests {
paramString = new SynthesizingMethodParameter(method, 1);
paramNotRequired = new SynthesizingMethodParameter(method, 2);
paramOptional = new SynthesizingMethodParameter(method, 3);
paramMono = new SynthesizingMethodParameter(method, 4);
}
@ -85,6 +86,15 @@ public class PathVariableMethodArgumentResolverTests { @@ -85,6 +86,15 @@ public class PathVariableMethodArgumentResolverTests {
public void supportsParameter() {
assertTrue(this.resolver.supportsParameter(this.paramNamedString));
assertFalse(this.resolver.supportsParameter(this.paramString));
try {
this.resolver.supportsParameter(this.paramMono);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"PathVariableMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -161,10 +171,13 @@ public class PathVariableMethodArgumentResolverTests { @@ -161,10 +171,13 @@ public class PathVariableMethodArgumentResolverTests {
}
@SuppressWarnings("unused")
public void handle(@PathVariable(value = "name") String param1, String param2,
@SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"})
public void handle(
@PathVariable(value = "name") String param1,
String param2,
@PathVariable(name = "name", required = false) String param3,
@PathVariable("name") Optional<String> param4) {
@PathVariable("name") Optional<String> param4,
@PathVariable Mono<String> param5) {
}
}

16
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolverTests.java

@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext @@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -61,7 +62,8 @@ public class RequestAttributeMethodArgumentResolverTests { @@ -61,7 +62,8 @@ public class RequestAttributeMethodArgumentResolverTests {
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
@ -74,6 +76,15 @@ public class RequestAttributeMethodArgumentResolverTests { @@ -74,6 +76,15 @@ public class RequestAttributeMethodArgumentResolverTests {
public void supportsParameter() throws Exception {
assertTrue(this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 0)));
assertFalse(this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 4)));
try {
this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 5));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestAttributeMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -151,7 +162,8 @@ public class RequestAttributeMethodArgumentResolverTests { @@ -151,7 +162,8 @@ public class RequestAttributeMethodArgumentResolverTests {
@RequestAttribute("specialFoo") Foo namedFoo,
@RequestAttribute(name="foo", required = false) Foo notRequiredFoo,
@RequestAttribute(name="foo") Optional<Foo> optionalFoo,
String notSupported) {
String notSupported,
@RequestAttribute Mono<Foo> alsoNotSupported) {
}

3
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java

@ -32,6 +32,7 @@ import rx.RxReactiveStreams; @@ -32,6 +32,7 @@ import rx.RxReactiveStreams;
import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
@ -69,7 +70,7 @@ public class RequestBodyArgumentResolverTests { @@ -69,7 +70,7 @@ public class RequestBodyArgumentResolverTests {
public void setup() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
this.resolver = new RequestBodyArgumentResolver(readers);
this.resolver = new RequestBodyArgumentResolver(readers, new ReactiveAdapterRegistry());
}

28
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java

@ -25,6 +25,7 @@ import org.junit.Test; @@ -25,6 +25,7 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -32,6 +33,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; @@ -32,6 +33,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@ -52,18 +54,21 @@ public class RequestHeaderMapMethodArgumentResolverTests { @@ -52,18 +54,21 @@ public class RequestHeaderMapMethodArgumentResolverTests {
private MethodParameter paramMultiValueMap;
private MethodParameter paramHttpHeaders;
private MethodParameter paramUnsupported;
private MethodParameter paramAlsoUnsupported;
@Before
public void setup() throws Exception {
resolver = new RequestHeaderMapMethodArgumentResolver();
resolver = new RequestHeaderMapMethodArgumentResolver(new ReactiveAdapterRegistry());
request = MockServerHttpRequest.get("/").build();
Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, HttpHeaders.class, Map.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
paramMap = new SynthesizingMethodParameter(method, 0);
paramMultiValueMap = new SynthesizingMethodParameter(method, 1);
paramHttpHeaders = new SynthesizingMethodParameter(method, 2);
paramUnsupported = new SynthesizingMethodParameter(method, 3);
paramUnsupported = new SynthesizingMethodParameter(method, 3);
paramAlsoUnsupported = new SynthesizingMethodParameter(method, 4);
}
@ -73,6 +78,15 @@ public class RequestHeaderMapMethodArgumentResolverTests { @@ -73,6 +78,15 @@ public class RequestHeaderMapMethodArgumentResolverTests {
assertTrue("MultiValueMap parameter not supported", resolver.supportsParameter(paramMultiValueMap));
assertTrue("HttpHeaders parameter not supported", resolver.supportsParameter(paramHttpHeaders));
assertFalse("non-@RequestParam map supported", resolver.supportsParameter(paramUnsupported));
try {
this.resolver.supportsParameter(this.paramAlsoUnsupported);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestHeaderMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -132,10 +146,12 @@ public class RequestHeaderMapMethodArgumentResolverTests { @@ -132,10 +146,12 @@ public class RequestHeaderMapMethodArgumentResolverTests {
@SuppressWarnings("unused")
public void params(@RequestHeader Map<?, ?> param1,
@RequestHeader MultiValueMap<?, ?> param2,
@RequestHeader HttpHeaders param3,
Map<?,?> unsupported) {
public void params(
@RequestHeader Map<?, ?> param1,
@RequestHeader MultiValueMap<?, ?> param2,
@RequestHeader HttpHeaders param3,
Map<?,?> unsupported,
@RequestHeader Mono<Map<?, ?>> alsoUnsupported) {
}
}

18
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolverTests.java

@ -29,6 +29,7 @@ import reactor.test.StepVerifier; @@ -29,6 +29,7 @@ import reactor.test.StepVerifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -64,13 +65,15 @@ public class RequestHeaderMethodArgumentResolverTests { @@ -64,13 +65,15 @@ public class RequestHeaderMethodArgumentResolverTests {
private MethodParameter paramNamedValueMap;
private MethodParameter paramDate;
private MethodParameter paramInstant;
private MethodParameter paramMono;
@Before
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.request = MockServerHttpRequest.get("/").build();
@ -87,6 +90,7 @@ public class RequestHeaderMethodArgumentResolverTests { @@ -87,6 +90,7 @@ public class RequestHeaderMethodArgumentResolverTests {
this.paramNamedValueMap = new SynthesizingMethodParameter(method, 5);
this.paramDate = new SynthesizingMethodParameter(method, 6);
this.paramInstant = new SynthesizingMethodParameter(method, 7);
this.paramMono = new SynthesizingMethodParameter(method, 8);
}
@ -95,6 +99,15 @@ public class RequestHeaderMethodArgumentResolverTests { @@ -95,6 +99,15 @@ public class RequestHeaderMethodArgumentResolverTests {
assertTrue("String parameter not supported", resolver.supportsParameter(paramNamedDefaultValueStringHeader));
assertTrue("String array parameter not supported", resolver.supportsParameter(paramNamedValueStringArray));
assertFalse("non-@RequestParam parameter supported", resolver.supportsParameter(paramNamedValueMap));
try {
this.resolver.supportsParameter(this.paramMono);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestHeaderMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -237,7 +250,8 @@ public class RequestHeaderMethodArgumentResolverTests { @@ -237,7 +250,8 @@ public class RequestHeaderMethodArgumentResolverTests {
@RequestHeader("${systemProperty}") String param5,
@RequestHeader("name") Map<?, ?> unsupported,
@RequestHeader("name") Date dateParam,
@RequestHeader("name") Instant instantParam) {
@RequestHeader("name") Instant instantParam,
@RequestHeader Mono<String> alsoNotSupported) {
}
}

19
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java

@ -23,8 +23,10 @@ import java.util.Map; @@ -23,8 +23,10 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
@ -37,6 +39,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -37,6 +39,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.web.method.MvcAnnotationPredicates.requestParam;
/**
@ -52,7 +55,7 @@ public class RequestParamMapMethodArgumentResolverTests { @@ -52,7 +55,7 @@ public class RequestParamMapMethodArgumentResolverTests {
@Before
public void setup() throws Exception {
this.resolver = new RequestParamMapMethodArgumentResolver();
this.resolver = new RequestParamMapMethodArgumentResolver(new ReactiveAdapterRegistry());
}
@ -69,6 +72,17 @@ public class RequestParamMapMethodArgumentResolverTests { @@ -69,6 +72,17 @@ public class RequestParamMapMethodArgumentResolverTests {
param = this.testMethod.annotNotPresent(RequestParam.class).arg(Map.class);
assertFalse(this.resolver.supportsParameter(param));
try {
param = this.testMethod.annot(requestParam()).arg(Mono.class, Map.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -120,7 +134,8 @@ public class RequestParamMapMethodArgumentResolverTests { @@ -120,7 +134,8 @@ public class RequestParamMapMethodArgumentResolverTests {
@RequestParam Map<?, ?> param1,
@RequestParam MultiValueMap<?, ?> param2,
@RequestParam("name") Map<?, ?> param3,
Map<?, ?> param4) {
Map<?, ?> param4,
@RequestParam Mono<Map<?, ?>> paramMono) {
}
}

46
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
@ -26,12 +27,14 @@ import reactor.core.publisher.Mono; @@ -26,12 +27,14 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.method.MvcAnnotationPredicates;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
@ -43,6 +46,7 @@ import static org.junit.Assert.assertEquals; @@ -43,6 +46,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.web.method.MvcAnnotationPredicates.requestParam;
@ -63,7 +67,8 @@ public class RequestParamMethodArgumentResolverTests { @@ -63,7 +67,8 @@ public class RequestParamMethodArgumentResolverTests {
@Before
public void setup() throws Exception {
this.resolver = new RequestParamMethodArgumentResolver(null, true);
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestParamMethodArgumentResolver(null, adapterRegistry, true);
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
@ -73,7 +78,6 @@ public class RequestParamMethodArgumentResolverTests { @@ -73,7 +78,6 @@ public class RequestParamMethodArgumentResolverTests {
@Test
public void supportsParameter() {
this.resolver = new RequestParamMethodArgumentResolver(null, true);
MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class);
assertTrue(this.resolver.supportsParameter(param));
@ -96,11 +100,42 @@ public class RequestParamMethodArgumentResolverTests { @@ -96,11 +100,42 @@ public class RequestParamMethodArgumentResolverTests {
param = this.testMethod.annot(requestParam().notRequired()).arg(String.class);
assertTrue(this.resolver.supportsParameter(param));
param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class);
this.resolver = new RequestParamMethodArgumentResolver(null, false);
}
@Test
public void doesNotSupportParameterWithDefaultResolutionTurnedOff() {
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestParamMethodArgumentResolver(null, adapterRegistry, false);
MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class);
assertFalse(this.resolver.supportsParameter(param));
}
@Test
public void doesNotSupportReactiveWrapper() {
MethodParameter param;
try {
param = this.testMethod.annot(requestParam()).arg(Mono.class, String.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMethodArgumentResolver doesn't support reactive type wrapper"));
}
try {
param = this.testMethod.annotNotPresent(RequestParam.class).arg(Mono.class, String.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
public void resolveWithQueryString() throws Exception {
MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class);
@ -208,7 +243,7 @@ public class RequestParamMethodArgumentResolverTests { @@ -208,7 +243,7 @@ public class RequestParamMethodArgumentResolverTests {
}
private Object resolve(MethodParameter parameter, ServerWebExchange exchange) {
return this.resolver.resolveArgument(parameter, this.bindContext, exchange).blockMillis(0);
return this.resolver.resolveArgument(parameter, this.bindContext, exchange).block(Duration.ZERO);
}
@ -219,6 +254,7 @@ public class RequestParamMethodArgumentResolverTests { @@ -219,6 +254,7 @@ public class RequestParamMethodArgumentResolverTests {
@RequestParam("name") Map<?, ?> param3,
@RequestParam Map<?, ?> param4,
String stringNotAnnot,
Mono<String> monoStringNotAnnot,
@RequestParam("name") String paramRequired,
@RequestParam(name = "name", required = false) String paramNotRequired,
@RequestParam("name") Optional<Integer> paramOptional,

16
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java

@ -21,6 +21,7 @@ import org.junit.Test; @@ -21,6 +21,7 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@ -43,7 +44,8 @@ import static org.mockito.Mockito.*; @@ -43,7 +44,8 @@ import static org.mockito.Mockito.*;
*/
public class ServerWebExchangeArgumentResolverTests {
private final ServerWebExchangeArgumentResolver resolver = new ServerWebExchangeArgumentResolver();
private final ServerWebExchangeArgumentResolver resolver =
new ServerWebExchangeArgumentResolver(new ReactiveAdapterRegistry());
private ServerWebExchange exchange;
@ -67,6 +69,15 @@ public class ServerWebExchangeArgumentResolverTests { @@ -67,6 +69,15 @@ public class ServerWebExchangeArgumentResolverTests {
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ServerHttpResponse.class)));
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(HttpMethod.class)));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
try {
this.resolver.supportsParameter(this.testMethod.arg(Mono.class, ServerWebExchange.class));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ServerWebExchangeArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@ -91,7 +102,8 @@ public class ServerWebExchangeArgumentResolverTests { @@ -91,7 +102,8 @@ public class ServerWebExchangeArgumentResolverTests {
ServerHttpResponse response,
WebSession session,
HttpMethod httpMethod,
String s) {
String s,
Mono<ServerWebExchange> monoExchange) {
}
}

14
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolverTests.java

@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext @@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -44,8 +45,14 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -44,8 +45,14 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link SessionAttributeMethodArgumentResolver}.
@ -67,7 +74,8 @@ public class SessionAttributeMethodArgumentResolverTests { @@ -67,7 +74,8 @@ public class SessionAttributeMethodArgumentResolverTests {
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.session = mock(WebSession.class);
WebSessionManager sessionManager = new MockWebSessionManager(this.session);

3
spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverKotlinTests.kt

@ -3,6 +3,7 @@ package org.springframework.web.reactive.result.method.annotation @@ -3,6 +3,7 @@ package org.springframework.web.reactive.result.method.annotation
import org.junit.Before
import org.junit.Test
import org.springframework.core.MethodParameter
import org.springframework.core.ReactiveAdapterRegistry
import org.springframework.core.annotation.SynthesizingMethodParameter
import org.springframework.format.support.DefaultFormattingConversionService
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest
@ -34,7 +35,7 @@ class RequestParamMethodArgumentResolverKotlinTests { @@ -34,7 +35,7 @@ class RequestParamMethodArgumentResolverKotlinTests {
@Before
fun setup() {
this.resolver = RequestParamMethodArgumentResolver(null, true)
this.resolver = RequestParamMethodArgumentResolver(null, ReactiveAdapterRegistry(), true)
this.request = MockServerHttpRequest.get("/").build()
val initializer = ConfigurableWebBindingInitializer()
initializer.conversionService = DefaultFormattingConversionService()

Loading…
Cancel
Save