> typePredicate) {
- A annotation = param.getParameterAnnotation(annotationType);
+ A annotation = parameter.getParameterAnnotation(annotationType);
if (annotation == null) {
return false;
}
- param = param.nestedIfOptional();
- Class> type = param.getNestedParameterType();
+ parameter = parameter.nestedIfOptional();
+ Class> type = parameter.getNestedParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
- assertHasValues(adapter, param);
- param = param.nested();
- type = param.getNestedParameterType();
+ assertHasValues(adapter, parameter);
+ parameter = parameter.nested();
+ type = parameter.getNestedParameterType();
}
if (typePredicate.test(annotation, type)) {
if (adapter == null) {
return true;
}
- throw getReactiveWrapperError(param);
+ throw buildReactiveWrapperException(parameter);
}
return false;
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java
index 5652412842..bc0392127f 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -33,15 +33,14 @@ import org.springframework.web.server.ServerWebExchange;
*/
public interface SyncHandlerMethodArgumentResolver extends HandlerMethodArgumentResolver {
-
/**
* {@inheritDoc}
* By default this simply delegates to {@link #resolveArgumentValue} for
* synchronous resolution.
*/
@Override
- default Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext,
- ServerWebExchange exchange) {
+ default Mono resolveArgument(
+ MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
return Mono.justOrEmpty(resolveArgumentValue(parameter, bindingContext, exchange));
}
@@ -53,7 +52,7 @@ public interface SyncHandlerMethodArgumentResolver extends HandlerMethodArgument
* @param exchange the current exchange
* @return an {@code Optional} with the resolved value, possibly empty
*/
- Optional resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext,
- ServerWebExchange exchange);
+ Optional resolveArgumentValue(
+ MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
index 57587d28fc..a833004b5b 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -114,7 +114,6 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
}
for (ServerHttpMessageReader> reader : getMessageReaders()) {
-
if (reader.canRead(elementType, mediaType)) {
Map readHints = Collections.emptyMap();
if (adapter != null && adapter.isMultiValue()) {
@@ -171,9 +170,9 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
private Object[] extractValidationHints(MethodParameter parameter) {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation ann : annotations) {
- Validated validAnnot = AnnotationUtils.getAnnotation(ann, Validated.class);
- if (validAnnot != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
- Object hints = (validAnnot != null ? validAnnot.value() : AnnotationUtils.getValue(ann));
+ Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
+ if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
+ Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
return (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
}
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java
index e41eac2ba4..8f9374f53a 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java
@@ -32,7 +32,6 @@ 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;
@@ -58,8 +57,7 @@ import org.springframework.web.server.ServerWebInputException;
* @author Rossen Stoyanchev
* @since 5.0
*/
-public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodArgumentResolverSupport
- implements HandlerMethodArgumentResolver {
+public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodArgumentResolverSupport {
private final ConfigurableBeanFactory configurableBeanFactory;
@@ -69,23 +67,21 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
/**
- * @param beanFactory a bean factory to use for resolving ${...} placeholder
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public AbstractNamedValueArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(adapterRegistry);
- this.configurableBeanFactory = beanFactory;
- this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
+ public AbstractNamedValueArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(registry);
+ this.configurableBeanFactory = factory;
+ this.expressionContext = (factory != null ? new BeanExpressionContext(factory, null) : null);
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
@@ -175,8 +171,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
* @param exchange the current exchange
* @return the resolved argument (may be {@code null})
*/
- protected abstract Mono resolveName(String name, MethodParameter parameter,
- ServerWebExchange exchange);
+ protected abstract Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange);
/**
* Apply type conversion if necessary.
@@ -277,8 +272,8 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr
* @param exchange the current exchange
*/
@SuppressWarnings("UnusedParameters")
- protected void handleResolvedValue(Object arg, String name, MethodParameter parameter,
- Model model, ServerWebExchange exchange) {
+ protected void handleResolvedValue(
+ Object arg, String name, MethodParameter parameter, Model model, ServerWebExchange exchange) {
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java
index ed24987cac..f0a5e8989e 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -39,23 +39,20 @@ import org.springframework.web.server.ServerWebExchange;
public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNamedValueArgumentResolver
implements SyncHandlerMethodArgumentResolver {
-
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- protected AbstractNamedValueSyncArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ protected AbstractNamedValueSyncArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
// Flip the default implementation from SyncHandlerMethodArgumentResolver:
// instead of delegating to (sync) resolveArgumentValue,
@@ -66,8 +63,8 @@ public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNam
}
@Override
- public Optional resolveArgumentValue(MethodParameter parameter,
- BindingContext context, ServerWebExchange exchange) {
+ public Optional resolveArgumentValue(
+ MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
// This won't block since resolveName below doesn't
Object value = resolveArgument(parameter, context, exchange).block();
@@ -76,16 +73,13 @@ public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNam
}
@Override
- protected final Mono resolveName(String name, MethodParameter param,
- ServerWebExchange exchange) {
-
+ protected final Mono resolveName(String name, MethodParameter param, ServerWebExchange exchange) {
return Mono.justOrEmpty(resolveNamedValue(name, param, exchange));
}
/**
* Actually resolve the value synchronously.
*/
- protected abstract Optional resolveNamedValue(String name,
- MethodParameter param, ServerWebExchange exchange);
+ protected abstract Optional resolveNamedValue(String name, MethodParameter param, ServerWebExchange exchange);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java
index 78dd40e389..b5b2d550e0 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java
@@ -38,17 +38,14 @@ import org.springframework.web.server.ServerWebInputException;
*/
public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
-
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public CookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public CookieValueMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@@ -64,9 +61,7 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArg
}
@Override
- protected Optional resolveNamedValue(String name, MethodParameter parameter,
- ServerWebExchange exchange) {
-
+ protected Optional resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
HttpCookie cookie = exchange.getRequest().getCookies().getFirst(name);
Class> paramType = parameter.getNestedParameterType();
if (HttpCookie.class.isAssignableFrom(paramType)) {
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java
index 5c84ef0dcd..d8bc9ab150 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -41,9 +41,7 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
-public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
- implements HandlerMethodArgumentResolver {
-
+public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverSupport {
public ErrorsMethodArgumentResolver(ReactiveAdapterRegistry registry) {
super(registry);
@@ -52,13 +50,13 @@ public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverS
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter, Errors.class::isAssignableFrom);
+ return checkParameterTypeNoReactiveWrapper(parameter, Errors.class::isAssignableFrom);
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext context,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
String name = getModelAttributeName(parameter);
Object errors = context.getModel().asMap().get(BindingResult.MODEL_KEY_PREFIX + name);
@@ -79,9 +77,8 @@ public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverS
}
private String getModelAttributeName(MethodParameter parameter) {
-
Assert.isTrue(parameter.getParameterIndex() > 0,
- "Errors argument must be immediately after a model attribute argument.");
+ "Errors argument must be immediately after a model attribute argument");
int index = parameter.getParameterIndex() - 1;
MethodParameter attributeParam = new MethodParameter(parameter.getMethod(), index);
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java
index 3ac65ecec1..542b49f964 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -36,17 +36,14 @@ import org.springframework.web.server.ServerWebExchange;
*/
public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
-
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@@ -62,9 +59,7 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueSyn
}
@Override
- protected Optional resolveNamedValue(String name, MethodParameter parameter,
- ServerWebExchange exchange) {
-
+ protected Optional resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
// No name to resolve
return Optional.empty();
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
index 41cfd15c73..7fd0576083 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -38,9 +38,7 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
-public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentResolver
- implements HandlerMethodArgumentResolver {
-
+public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentResolver {
public HttpEntityArgumentResolver(List> readers,
ReactiveAdapterRegistry registry) {
@@ -51,16 +49,15 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter,
+ return checkParameterTypeNoReactiveWrapper(parameter,
type -> HttpEntity.class.equals(type) || RequestEntity.class.equals(type));
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
Class> entityType = parameter.getParameterType();
-
return readBody(parameter.nested(), false, bindingContext, exchange)
.map(body -> createEntity(body, entityType, exchange.getRequest()))
.defaultIfEmpty(createEntity(null, entityType, exchange.getRequest()));
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java
index 4c97b57303..d34f3b87c8 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -36,7 +36,6 @@ import org.springframework.web.server.ServerWebExchange;
public class ModelArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
-
public ModelArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@@ -44,7 +43,7 @@ public class ModelArgumentResolver extends HandlerMethodArgumentResolverSupport
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter, Model.class::isAssignableFrom);
+ return checkParameterTypeNoReactiveWrapper(parameter, Model.class::isAssignableFrom);
}
@Override
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
index 89c50fdf54..3caef1a9f2 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
@@ -16,30 +16,34 @@
package org.springframework.web.reactive.result.method.annotation;
+import java.beans.ConstructorProperties;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.util.List;
import java.util.Map;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoProcessor;
import org.springframework.beans.BeanUtils;
+import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
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;
@@ -58,10 +62,12 @@ import org.springframework.web.server.ServerWebExchange;
* attribute with or without the presence of an {@code @ModelAttribute}.
*
* @author Rossen Stoyanchev
+ * @author Juergen Hoeller
* @since 5.0
*/
-public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
- implements HandlerMethodArgumentResolver {
+public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentResolverSupport {
+
+ private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private final boolean useDefaultResolution;
@@ -87,25 +93,25 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
return true;
}
else if (this.useDefaultResolution) {
- return checkParamType(parameter, type -> !BeanUtils.isSimpleProperty(type));
+ return checkParameterType(parameter, type -> !BeanUtils.isSimpleProperty(type));
}
return false;
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext context,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
ResolvableType type = ResolvableType.forMethodParameter(parameter);
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: " +
+ () -> getClass().getSimpleName() + " doesn't support multi-value reactive type wrapper: " +
parameter.getGenericParameterType());
String name = getAttributeName(valueType, parameter);
- Mono> valueMono = getAttributeMono(name, valueType, context.getModel());
+ Mono> valueMono = getAttributeMono(name, valueType, context, exchange);
Map model = context.getModel().asMap();
MonoProcessor bindingResultMono = MonoProcessor.create();
@@ -140,22 +146,25 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
}
private String getAttributeName(ResolvableType valueType, MethodParameter parameter) {
- ModelAttribute annot = parameter.getParameterAnnotation(ModelAttribute.class);
- if (annot != null && StringUtils.hasText(annot.value())) {
- return annot.value();
+ ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
+ if (ann != null && StringUtils.hasText(ann.value())) {
+ return ann.value();
}
// TODO: Conventions does not deal with async wrappers
return ClassUtils.getShortNameAsProperty(valueType.getRawClass());
}
- private Mono> getAttributeMono(String attributeName, ResolvableType attributeType, Model model) {
- Object attribute = model.asMap().get(attributeName);
+ private Mono> getAttributeMono(
+ String attributeName, ResolvableType attributeType, BindingContext context, ServerWebExchange exchange) {
+
+ Object attribute = context.getModel().asMap().get(attributeName);
if (attribute == null) {
- attribute = BeanUtils.instantiateClass(attributeType.getRawClass());
+ return createAttribute(attributeName, attributeType.getRawClass(), context, exchange);
}
+
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapter(null, attribute);
if (adapterFrom != null) {
- Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding supports single-value async types.");
+ Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding only supports single-value async types");
return Mono.from(adapterFrom.toPublisher(attribute));
}
else {
@@ -163,10 +172,48 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
}
}
- private boolean hasErrorsArgument(MethodParameter methodParam) {
- int i = methodParam.getParameterIndex();
- Class>[] paramTypes = methodParam.getMethod().getParameterTypes();
- return paramTypes.length > i && Errors.class.isAssignableFrom(paramTypes[i + 1]);
+ private Mono> createAttribute(
+ String attributeName, Class> attributeType, BindingContext context, ServerWebExchange exchange) {
+
+ Constructor>[] ctors = attributeType.getConstructors();
+ if (ctors.length != 1) {
+ // No standard data class or standard JavaBeans arrangement ->
+ // defensively go with default constructor, expecting regular bean property bindings.
+ return Mono.just(BeanUtils.instantiateClass(attributeType));
+ }
+ Constructor> ctor = ctors[0];
+ if (ctor.getParameterCount() == 0) {
+ // A single default constructor -> clearly a standard JavaBeans arrangement.
+ return Mono.just(BeanUtils.instantiateClass(ctor));
+ }
+
+ // A single data class constructor -> resolve constructor arguments from request parameters.
+ return exchange.getRequestParams().then(requestParams -> {
+ ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
+ String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
+ Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
+ Class>[] paramTypes = ctor.getParameterTypes();
+ Assert.state(paramNames.length == paramTypes.length,
+ () -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);
+ Object[] args = new Object[paramTypes.length];
+ WebDataBinder binder = context.createDataBinder(exchange, null, attributeName);
+ for (int i = 0; i < paramNames.length; i++) {
+ List paramValues = requestParams.get(paramNames[i]);
+ Object paramValue = null;
+ if (paramValues != null) {
+ paramValue = (paramValues.size() == 1 ? paramValues.get(0) :
+ paramValues.toArray(new String[paramValues.size()]));
+ }
+ args[i] = binder.convertIfNecessary(paramValue, paramTypes[i], new MethodParameter(ctor, i));
+ }
+ return Mono.fromSupplier(() -> BeanUtils.instantiateClass(ctor, args));
+ });
+ }
+
+ private boolean hasErrorsArgument(MethodParameter parameter) {
+ int i = parameter.getParameterIndex();
+ Class>[] paramTypes = parameter.getMethod().getParameterTypes();
+ return (paramTypes.length > i && Errors.class.isAssignableFrom(paramTypes[i + 1]));
}
private void validateIfApplicable(WebExchangeDataBinder binder, MethodParameter parameter) {
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
index eb220cac59..3b175b0e30 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -43,7 +43,6 @@ import org.springframework.web.server.ServerWebExchange;
public class PathVariableMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
-
public PathVariableMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java
index 2a936afaf9..7f749efe5c 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -52,17 +52,14 @@ import org.springframework.web.server.ServerWebExchange;
*/
public class PathVariableMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
-
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public PathVariableMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@@ -83,9 +80,7 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueSyncAr
@Override
@SuppressWarnings("unchecked")
- protected Optional resolveNamedValue(String name, MethodParameter parameter,
- ServerWebExchange exchange) {
-
+ protected Optional resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
String attributeName = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
return exchange.getAttribute(attributeName)
.map(value -> ((Map) value).get(name));
@@ -98,8 +93,8 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueSyncAr
@Override
@SuppressWarnings("unchecked")
- protected void handleResolvedValue(Object arg, String name, MethodParameter parameter,
- Model model, ServerWebExchange exchange) {
+ protected void handleResolvedValue(
+ Object arg, String name, MethodParameter parameter, Model model, ServerWebExchange exchange) {
// TODO: View.PATH_VARIABLES ?
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java
index 54559ce9f7..d469f940d7 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PrincipalArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -24,7 +24,6 @@ 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;
@@ -35,9 +34,7 @@ import org.springframework.web.server.ServerWebExchange;
* @since 5.0
* @see ServerWebExchangeArgumentResolver
*/
-public class PrincipalArgumentResolver extends HandlerMethodArgumentResolverSupport
- implements HandlerMethodArgumentResolver {
-
+public class PrincipalArgumentResolver extends HandlerMethodArgumentResolverSupport {
public PrincipalArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
@@ -46,7 +43,7 @@ public class PrincipalArgumentResolver extends HandlerMethodArgumentResolverSupp
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter, Principal.class::isAssignableFrom);
+ return checkParameterTypeNoReactiveWrapper(parameter, Principal.class::isAssignableFrom);
}
@Override
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java
index 079335c2f6..72c3f8a73d 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java
@@ -36,15 +36,13 @@ public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueSy
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@@ -61,9 +59,7 @@ public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueSy
}
@Override
- protected Optional resolveNamedValue(String name, MethodParameter parameter,
- ServerWebExchange exchange) {
-
+ protected Optional resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
return exchange.getAttribute(name);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
index c512fb2403..56ce5977d6 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -43,9 +43,7 @@ import org.springframework.web.server.ServerWebInputException;
* @author Rossen Stoyanchev
* @since 5.0
*/
-public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver
- implements HandlerMethodArgumentResolver {
-
+public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver {
public RequestBodyArgumentResolver(List> readers,
ReactiveAdapterRegistry registry) {
@@ -60,8 +58,8 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe
}
@Override
- public Mono resolveArgument(MethodParameter param, BindingContext bindingContext,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter param, BindingContext bindingContext, ServerWebExchange exchange) {
RequestBody annotation = param.getParameterAnnotation(RequestBody.class);
return readBody(param, annotation.required(), bindingContext, exchange);
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java
index d8d4e42575..db9ed78fe2 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -45,7 +45,6 @@ import org.springframework.web.server.ServerWebExchange;
public class RequestHeaderMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
-
public RequestHeaderMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java
index 5912ae39ec..754de6268c 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java
@@ -47,15 +47,13 @@ import org.springframework.web.server.ServerWebInputException;
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
/**
- * @param beanFactory a bean factory to use for resolving ${...}
+ * @param factory 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
+ * @param registry for checking reactive type wrappers
*/
- public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java
index 3cc13359f4..7635a55f3c 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java
@@ -48,7 +48,6 @@ import org.springframework.web.server.ServerWebExchange;
public class RequestParamMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
-
public RequestParamMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java
index 193cb5436c..c75f0819d1 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -59,19 +59,19 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
/**
* Class constructor with a default resolution mode flag.
- * @param beanFactory a bean factory used for resolving ${...} placeholder
+ * @param factory 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 registry 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,
- ReactiveAdapterRegistry adapterRegistry, boolean useDefaultResolution) {
+ public RequestParamMethodArgumentResolver(
+ ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry, boolean useDefaultResolution) {
- super(beanFactory, adapterRegistry);
+ super(factory, registry);
this.useDefaultResolution = useDefaultResolution;
}
@@ -82,7 +82,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
return true;
}
else if (this.useDefaultResolution) {
- return checkParamTypeNoReactiveWrapper(param, BeanUtils::isSimpleProperty);
+ return checkParameterTypeNoReactiveWrapper(param, BeanUtils::isSimpleProperty);
}
return false;
}
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java
index 6a095a2452..d748f626e1 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -48,7 +48,6 @@ import org.springframework.web.server.ServerWebExchange;
public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
-
public ServerWebExchangeArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
}
@@ -56,7 +55,7 @@ public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentReso
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter,
+ return checkParameterTypeNoReactiveWrapper(parameter,
type -> ServerWebExchange.class.isAssignableFrom(type) ||
ServerHttpRequest.class.isAssignableFrom(type) ||
ServerHttpResponse.class.isAssignableFrom(type) ||
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java
index bb557c1b3b..5b208f46c0 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.springframework.web.reactive.result.method.annotation;
import java.util.Optional;
@@ -36,11 +37,8 @@ import org.springframework.web.server.ServerWebInputException;
*/
public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueArgumentResolver {
-
- public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
- ReactiveAdapterRegistry adapterRegistry) {
-
- super(beanFactory, adapterRegistry);
+ public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory factory, ReactiveAdapterRegistry registry) {
+ super(factory, registry);
}
@@ -56,9 +54,7 @@ public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueAr
}
@Override
- protected Mono resolveName(String name, MethodParameter parameter,
- ServerWebExchange exchange) {
-
+ protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) {
return exchange.getSession()
.map(session -> session.getAttribute(name))
.filter(Optional::isPresent)
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java
index 265a64a804..d5895973e8 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -34,9 +34,7 @@ import org.springframework.web.server.WebSession;
* @since 5.0
* @see ServerWebExchangeArgumentResolver
*/
-public class WebSessionArgumentResolver extends HandlerMethodArgumentResolverSupport
- implements HandlerMethodArgumentResolver {
-
+public class WebSessionArgumentResolver extends HandlerMethodArgumentResolverSupport {
public WebSessionArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
@@ -45,12 +43,12 @@ public class WebSessionArgumentResolver extends HandlerMethodArgumentResolverSup
@Override
public boolean supportsParameter(MethodParameter parameter) {
- return checkParamTypeNoReactiveWrapper(parameter, WebSession.class::isAssignableFrom);
+ return checkParameterTypeNoReactiveWrapper(parameter, WebSession.class::isAssignableFrom);
}
@Override
- public Mono resolveArgument(MethodParameter parameter, BindingContext context,
- ServerWebExchange exchange) {
+ public Mono resolveArgument(
+ MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
Assert.isAssignable(WebSession.class, parameter.getParameterType());
return exchange.getSession().cast(Object.class);
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
index d231396765..7cc280bcc4 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
@@ -56,12 +56,9 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.springframework.core.ResolvableType.forClassWithGenerics;
-import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.post;
+import static org.junit.Assert.*;
+import static org.springframework.core.ResolvableType.*;
+import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
/**
* Unit tests for {@link AbstractMessageReaderArgumentResolver}.
@@ -307,7 +304,16 @@ public class MessageReaderArgumentResolverTests {
private AbstractMessageReaderArgumentResolver resolver(Decoder>... decoders) {
List> readers = new ArrayList<>();
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
- return new AbstractMessageReaderArgumentResolver(readers) {};
+ return new AbstractMessageReaderArgumentResolver(readers) {
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ return false;
+ }
+ @Override
+ public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
+ return null;
+ }
+ };
}
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java
index ab97efc882..6a1998b308 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolverTests.java
@@ -42,16 +42,13 @@ import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
/**
* Unit tests for {@link ModelAttributeMethodArgumentResolver}.
*
* @author Rossen Stoyanchev
+ * @author Juergen Hoeller
*/
public class ModelAttributeMethodArgumentResolverTests {
@@ -116,7 +113,6 @@ public class ModelAttributeMethodArgumentResolverTests {
@Test
public void createAndBindToMono() throws Exception {
-
MethodParameter parameter = this.testMethod
.annotNotPresent(ModelAttribute.class).arg(Mono.class, Foo.class);
@@ -130,7 +126,6 @@ public class ModelAttributeMethodArgumentResolverTests {
@Test
public void createAndBindToSingle() throws Exception {
-
MethodParameter parameter = this.testMethod
.annotPresent(ModelAttribute.class).arg(Single.class, Foo.class);
@@ -211,6 +206,7 @@ public class ModelAttributeMethodArgumentResolverTests {
Foo foo = valueExtractor.apply(value);
assertEquals("Robert", foo.getName());
+ assertEquals(25, foo.getAge());
String key = "foo";
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + key;
@@ -231,7 +227,6 @@ public class ModelAttributeMethodArgumentResolverTests {
@Test
@SuppressWarnings("unchecked")
public void validationErrorToMono() throws Exception {
-
MethodParameter parameter = this.testMethod
.annotNotPresent(ModelAttribute.class).arg(Mono.class, Foo.class);
@@ -246,7 +241,6 @@ public class ModelAttributeMethodArgumentResolverTests {
@Test
public void validationErrorToSingle() throws Exception {
-
MethodParameter parameter = this.testMethod
.annotPresent(ModelAttribute.class).arg(Single.class, Foo.class);
@@ -264,7 +258,6 @@ public class ModelAttributeMethodArgumentResolverTests {
ServerWebExchange exchange = postForm("age=invalid");
Mono> mono = createResolver().resolveArgument(param, this.bindContext, exchange);
-
mono = valueMonoExtractor.apply(mono);
StepVerifier.create(mono)
@@ -277,6 +270,31 @@ public class ModelAttributeMethodArgumentResolverTests {
.verify();
}
+ @Test
+ public void bindDataClass() throws Exception {
+ testBindBar(this.testMethod.annotNotPresent(ModelAttribute.class).arg(Bar.class));
+ }
+
+ private void testBindBar(MethodParameter param) throws Exception {
+ Object value = createResolver()
+ .resolveArgument(param, this.bindContext, postForm("name=Robert&age=25&count=1"))
+ .block(Duration.ZERO);
+
+ Bar bar = (Bar) value;
+ assertEquals("Robert", bar.getName());
+ assertEquals(25, bar.getAge());
+ assertEquals(1, bar.getCount());
+
+ String key = "bar";
+ String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + key;
+
+ Map map = bindContext.getModel().asMap();
+ assertEquals(map.toString(), 2, map.size());
+ assertSame(bar, map.get(key));
+ assertNotNull(map.get(bindingResultKey));
+ assertTrue(map.get(bindingResultKey) instanceof BindingResult);
+ }
+
private ModelAttributeMethodArgumentResolver createResolver() {
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry(), false);
@@ -298,7 +316,8 @@ public class ModelAttributeMethodArgumentResolverTests {
Foo fooNotAnnotated,
String stringNotAnnotated,
Mono monoNotAnnotated,
- Mono monoStringNotAnnotated) {
+ Mono monoStringNotAnnotated,
+ Bar barNotAnnotated) {
}
@@ -333,4 +352,35 @@ public class ModelAttributeMethodArgumentResolverTests {
}
}
+
+ private static class Bar {
+
+ private final String name;
+
+ private final int age;
+
+ private int count;
+
+ public Bar(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return this.age;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+ }
+
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java
index 5323c1a8f4..237526d0c4 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -89,7 +89,7 @@ public class ModelAndView {
}
/**
- * Creates new ModelAndView given a view name and a model.
+ * Create a new ModelAndView given a view name and a model.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param model Map of model names (Strings) to model objects
@@ -104,7 +104,7 @@ public class ModelAndView {
}
/**
- * Creates new ModelAndView given a View object and a model.
+ * Create a new ModelAndView given a View object and a model.
* Note: the supplied model data is copied into the internal
* storage of this class. You should not consider to modify the supplied
* Map after supplying it to this class
@@ -121,14 +121,27 @@ public class ModelAndView {
}
/**
- * Creates new ModelAndView given a view name, model, and status.
+ * Create a new ModelAndView given a view name and HTTP status.
+ * @param viewName name of the View to render, to be resolved
+ * by the DispatcherServlet's ViewResolver
+ * @param status an HTTP status code to use for the response
+ * (to be set just prior to View rendering)
+ * @since 4.3.8
+ */
+ public ModelAndView(String viewName, HttpStatus status) {
+ this.view = viewName;
+ this.status = status;
+ }
+
+ /**
+ * Create a new ModelAndView given a view name, model, and HTTP status.
* @param viewName name of the View to render, to be resolved
* by the DispatcherServlet's ViewResolver
* @param model Map of model names (Strings) to model objects
* (Objects). Model entries may not be {@code null}, but the
* model Map may be {@code null} if there is no model data.
- * @param status an alternative status code to use for the response;
- * The response status is set just prior to View rendering.
+ * @param status an HTTP status code to use for the response
+ * (to be set just prior to View rendering)
* @since 4.3
*/
public ModelAndView(String viewName, Map model, HttpStatus status) {
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java
index f21a23f58c..42fe205d26 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -16,6 +16,7 @@
package org.springframework.web.servlet.mvc.method.annotation;
+import java.beans.ConstructorProperties;
import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.Serializable;
@@ -140,14 +141,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
-import static org.junit.Assert.assertArrayEquals;
-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.junit.Assert.fail;
+import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
@@ -283,15 +277,13 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}, NestedSetController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
- request.addParameter("testBeanSet", new String[] {"1", "2"});
+ request.addParameter("testBeanSet", "1", "2");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals("[1, 2]-org.springframework.tests.sample.beans.TestBean", response.getContentAsString());
}
- // SPR-12903
-
- @Test
+ @Test // SPR-12903
public void pathVariableWithCustomConverter() throws Exception {
initServlet(new ApplicationContextInitializer() {
@Override
@@ -1244,9 +1236,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals("myParam-42", response.getContentAsString());
}
- // SPR-9062
-
- @Test
+ @Test // SPR-9062
public void ambiguousPathAndRequestMethod() throws Exception {
initServletWithControllers(AmbiguousPathAndRequestMethodController.class);
@@ -1498,9 +1488,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals(405, response.getStatus());
}
- // SPR-8536
-
- @Test
+ @Test // SPR-8536
public void testHeadersCondition() throws Exception {
initServletWithControllers(HeadersConditionController.class);
@@ -1571,7 +1559,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertTrue(RequestContextUtils.getOutputFlashMap(request).isEmpty());
}
- @Test // SPR-15176
+ @Test // SPR-15176
public void flashAttributesWithResponseEntity() throws Exception {
initServletWithControllers(RedirectAttributesController.class);
@@ -1831,6 +1819,31 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertTrue(response.getContentAsByteArray().length == 0);
}
+ @Test
+ public void dataClassBinding() throws ServletException, IOException {
+ initServletWithControllers(DataClassController.class);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
+ request.addParameter("param1", "value1");
+ request.addParameter("param2", "2");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ getServlet().service(request, response);
+ assertEquals("value1-2-0", response.getContentAsString());
+ }
+
+ @Test
+ public void dataClassBindingWithAdditionalSetter() throws ServletException, IOException {
+ initServletWithControllers(DataClassController.class);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
+ request.addParameter("param1", "value1");
+ request.addParameter("param2", "2");
+ request.addParameter("param3", "3");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ getServlet().service(request, response);
+ assertEquals("value1-2-3", response.getContentAsString());
+ }
+
@Controller
static class ControllerWithEmptyValueMapping {
@@ -2727,15 +2740,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@XmlRootElement
public static class A {
-
}
@XmlRootElement
public static class B {
-
}
-
public static class NotReadableMessageConverter implements HttpMessageConverter {
@Override
@@ -3313,7 +3323,6 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
public HttpHeaders createNoHeader() throws URISyntaxException {
return new HttpHeaders();
}
-
}
@RestController
@@ -3345,7 +3354,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@RequestMapping("/path")
public ModelAndView methodWithHttpStatus(MyEntity object) {
- return new ModelAndView("view", new ModelMap(), HttpStatus.UNPROCESSABLE_ENTITY);
+ return new ModelAndView("view", HttpStatus.UNPROCESSABLE_ENTITY);
}
@RequestMapping("/exception")
@@ -3355,7 +3364,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@ExceptionHandler(TestException.class)
public ModelAndView handleException() {
- return new ModelAndView("view", new ModelMap(), HttpStatus.UNPROCESSABLE_ENTITY);
+ return new ModelAndView("view", HttpStatus.UNPROCESSABLE_ENTITY);
}
@SuppressWarnings("serial")
@@ -3363,4 +3372,32 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
}
+ public static class DataClass {
+
+ public final String param1;
+
+ public final int param2;
+
+ public int param3;
+
+ @ConstructorProperties({"param1", "param2"})
+ public DataClass(String param1, int p2) {
+ this.param1 = param1;
+ this.param2 = p2;
+ }
+
+ public void setParam3(int param3) {
+ this.param3 = param3;
+ }
+ }
+
+ @RestController
+ public static class DataClassController {
+
+ @RequestMapping("/bind")
+ public String handle(DataClass data) {
+ return data.param1 + "-" + data.param2 + "-" + data.param3;
+ }
+ }
+
}