Skip to content

Commit 950edf8

Browse files
committed
Support for Map method argument in WebFlux
Issue: SPR-16086
1 parent bec1fc1 commit 950edf8

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.web.reactive.result.method.annotation;
1818

19+
import java.util.Map;
20+
1921
import org.springframework.core.MethodParameter;
2022
import org.springframework.core.ReactiveAdapterRegistry;
2123
import org.springframework.ui.Model;
@@ -26,7 +28,8 @@
2628
import org.springframework.web.server.ServerWebExchange;
2729

2830
/**
29-
* Resolver for the {@link Model} controller method argument.
31+
* Resolver for a controller method argument of type {@link Model} that can
32+
* also be resolved as a {@link java.util.Map}.
3033
*
3134
* @author Rossen Stoyanchev
3235
* @since 5.0
@@ -41,15 +44,25 @@ public ModelArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
4144

4245
@Override
4346
public boolean supportsParameter(MethodParameter parameter) {
44-
return checkParameterTypeNoReactiveWrapper(parameter, Model.class::isAssignableFrom);
47+
return checkParameterTypeNoReactiveWrapper(parameter,
48+
type -> Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type));
4549
}
4650

4751
@Override
48-
public Object resolveArgumentValue(MethodParameter methodParameter, BindingContext context,
52+
public Object resolveArgumentValue(MethodParameter parameter, BindingContext context,
4953
ServerWebExchange exchange) {
5054

51-
Assert.isAssignable(Model.class, methodParameter.getParameterType());
52-
return context.getModel();
55+
Class<?> type = parameter.getParameterType();
56+
if (Model.class.isAssignableFrom(type)) {
57+
return context.getModel();
58+
}
59+
else if (Map.class.isAssignableFrom(type)) {
60+
return context.getModel().asMap();
61+
}
62+
else {
63+
// Should never happen..
64+
throw new IllegalStateException("Unexpected method parameter type: " + type);
65+
}
5366
}
5467

5568
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2002-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.web.reactive.result.method.annotation;
17+
18+
import java.time.Duration;
19+
import java.util.Map;
20+
21+
import org.junit.Test;
22+
23+
import org.springframework.core.MethodParameter;
24+
import org.springframework.core.ReactiveAdapterRegistry;
25+
import org.springframework.mock.web.test.server.MockServerWebExchange;
26+
import org.springframework.ui.Model;
27+
import org.springframework.ui.ModelMap;
28+
import org.springframework.web.method.ResolvableMethod;
29+
import org.springframework.web.reactive.BindingContext;
30+
import org.springframework.web.server.ServerWebExchange;
31+
32+
import static org.junit.Assert.assertFalse;
33+
import static org.junit.Assert.assertSame;
34+
import static org.junit.Assert.assertTrue;
35+
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
36+
37+
/**
38+
* Unit tests for {@link ModelArgumentResolver}.
39+
* @author Rossen Stoyanchev
40+
*/
41+
public class ModelArgumentResolverTests {
42+
43+
private final ModelArgumentResolver resolver = new ModelArgumentResolver(new ReactiveAdapterRegistry());
44+
45+
private final ServerWebExchange exchange = MockServerWebExchange.from(get("/"));
46+
47+
private final ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handle").build();
48+
49+
50+
@Test
51+
public void supportsParameter() throws Exception {
52+
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(Model.class)));
53+
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(Map.class, String.class, Object.class)));
54+
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ModelMap.class)));
55+
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(Object.class)));
56+
}
57+
58+
@Test
59+
public void resolveArgument() throws Exception {
60+
testResolveArgument(this.testMethod.arg(Model.class));
61+
testResolveArgument(this.testMethod.arg(Map.class, String.class, Object.class));
62+
testResolveArgument(this.testMethod.arg(ModelMap.class));
63+
}
64+
65+
private void testResolveArgument(MethodParameter parameter) {
66+
BindingContext context = new BindingContext();
67+
Object result = this.resolver.resolveArgument(parameter, context, this.exchange).block(Duration.ZERO);
68+
assertSame(context.getModel(), result);
69+
}
70+
71+
@SuppressWarnings("unused")
72+
void handle(Model model, Map<String, Object> map, ModelMap modelMap, Object object) {}
73+
74+
}

0 commit comments

Comments
 (0)