diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
index 14ee0f808a..26a2547030 100644
--- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
+++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
@@ -243,13 +243,12 @@ public final class ModelFactory {
/**
- * Derive the model attribute name for a method parameter based on:
- *
- * - the parameter {@code @ModelAttribute} annotation value
- *
- the parameter type
- *
+ * Derive the model attribute name for the given method parameter based on
+ * a {@code @ModelAttribute} parameter annotation (if present) or falling
+ * back on parameter type based conventions.
* @param parameter a descriptor for the method parameter
- * @return the derived name (never {@code null} or empty String)
+ * @return the derived name
+ * @see Conventions#getVariableNameForParameter(MethodParameter)
*/
public static String getNameForParameter(MethodParameter parameter) {
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java b/spring-web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java
index 17f8c6da45..500ba2c93e 100644
--- a/spring-web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java
+++ b/spring-web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java
@@ -74,10 +74,7 @@ public class SessionAttributesHandler {
this.attributeNames.addAll(Arrays.asList(annotation.names()));
this.attributeTypes.addAll(Arrays.asList(annotation.types()));
}
-
- for (String attributeName : this.attributeNames) {
- this.knownAttributeNames.add(attributeName);
- }
+ this.knownAttributeNames.addAll(this.attributeNames);
}
/**
@@ -90,7 +87,7 @@ public class SessionAttributesHandler {
/**
* Whether the attribute name or type match the names and types specified
- * via {@code @SessionAttributes} in underlying controller.
+ * via {@code @SessionAttributes} on the underlying controller.
* Attributes successfully resolved through this method are "remembered"
* and subsequently used in {@link #retrieveAttributes(WebRequest)} and
* {@link #cleanupAttributes(WebRequest)}.
diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java
index 06c15bf8d5..9390cc01e0 100644
--- a/spring-web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java
+++ b/spring-web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.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.
@@ -30,12 +30,15 @@ import org.springframework.web.bind.support.SessionAttributeStore;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
-import static java.util.Arrays.*;
-import static org.junit.Assert.*;
+import static java.util.Arrays.asList;
+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;
/**
* Test fixture with {@link SessionAttributesHandler}.
- *
* @author Rossen Stoyanchev
*/
public class SessionAttributesHandlerTests {
@@ -50,10 +53,10 @@ public class SessionAttributesHandlerTests {
@Test
public void isSessionAttribute() throws Exception {
- assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr1", null));
- assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr2", null));
+ assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr1", String.class));
+ assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr2", String.class));
assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("simple", TestBean.class));
- assertFalse(sessionAttributesHandler.isHandlerSessionAttribute("simple", null));
+ assertFalse(sessionAttributesHandler.isHandlerSessionAttribute("simple", String.class));
}
@Test
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java b/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java
index 35ebd661d0..4e0b7cf98c 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/BindingContext.java
@@ -24,7 +24,8 @@ import org.springframework.web.bind.support.WebExchangeDataBinder;
import org.springframework.web.server.ServerWebExchange;
/**
- * Context to assist with processing a request and binding it onto Objects.
+ * Context to assist with binding request data onto Objects and provide access
+ * to a shared {@link Model} with controller-specific attributes.
*
*
Provides methods to create a {@link WebExchangeDataBinder} for a specific
* target, command Object to apply data binding and validation to, or without a
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelInitializer.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelInitializer.java
index 9ec4e889a6..9d7e3ef653 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelInitializer.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelInitializer.java
@@ -30,6 +30,7 @@ import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.reactive.BindingContext;
@@ -73,12 +74,13 @@ class ModelInitializer {
List> resultList = new ArrayList<>();
attributeMethods.forEach(invocable -> resultList.add(invocable.invoke(exchange, bindingContext)));
- return Mono.zip(resultList, objectArray -> {
- return Arrays.stream(objectArray)
- .map(object -> (HandlerResult) object)
- .map(handlerResult -> handleResult(handlerResult, bindingContext))
- .collect(Collectors.toList());
- }).flatMap(completionList -> Mono.when(completionList));
+ return Mono
+ .zip(resultList, objectArray -> {
+ return Arrays.stream(objectArray)
+ .map(object -> handleResult(((HandlerResult) object), bindingContext))
+ .collect(Collectors.toList());
+ })
+ .flatMap(completionList -> Mono.when(completionList));
}
private Mono handleResult(HandlerResult handlerResult, BindingContext bindingContext) {
@@ -86,11 +88,8 @@ class ModelInitializer {
if (value != null) {
ResolvableType type = handlerResult.getReturnType();
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.getRawClass(), value);
- if (adapter != null) {
- Class> attributeType = (adapter.isNoValue() ? Void.class : type.resolveGeneric());
- if (attributeType == Void.class) {
- return Mono.from(adapter.toPublisher(value));
- }
+ if (isAsyncVoidType(type, adapter)) {
+ return Mono.from(adapter.toPublisher(value));
}
String name = getAttributeName(handlerResult.getReturnTypeSource());
bindingContext.getModel().asMap().putIfAbsent(name, value);
@@ -98,6 +97,10 @@ class ModelInitializer {
return Mono.empty();
}
+ private boolean isAsyncVoidType(ResolvableType type, @Nullable ReactiveAdapter adapter) {
+ return adapter != null && (adapter.isNoValue() || type.resolveGeneric() == Void.class);
+ }
+
private String getAttributeName(MethodParameter param) {
return Optional
.ofNullable(AnnotatedElementUtils.findMergedAnnotation(param.getAnnotatedElement(), ModelAttribute.class))
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java
index 9d5f0c3dad..cefa7c44af 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/AbstractView.java
@@ -147,7 +147,6 @@ public abstract class AbstractView implements View, ApplicationContextAware {
* Obtain the ApplicationContext for actual use.
* @return the ApplicationContext (never {@code null})
* @throws IllegalStateException in case of no ApplicationContext set
- * @since 5.0
*/
protected final ApplicationContext obtainApplicationContext() {
ApplicationContext applicationContext = getApplicationContext();
@@ -191,7 +190,9 @@ public abstract class AbstractView implements View, ApplicationContextAware {
* The default implementation creates a combined output Map that includes
* model as well as static attributes with the former taking precedence.
*/
- protected Mono