@MatrixVariable resolvers for WebFlux

The information was already parsed and available in a request attribute
but until now there were no argument resolvers to expose it.

Issue: SPR-16005
This commit is contained in:
Rossen Stoyanchev
2017-10-19 21:01:38 -04:00
parent c7a15260d6
commit ab92754a2e
14 changed files with 865 additions and 136 deletions

View File

@@ -16,7 +16,6 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -26,17 +25,20 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.method.MvcAnnotationPredicates.matrixAttribute;
/**
* Test fixture with {@link MatrixVariableMethodArgumentResolver}.
@@ -53,11 +55,7 @@ public class MatrixVariablesMapMethodArgumentResolverTests {
private MockHttpServletRequest request;
private MethodParameter paramString;
private MethodParameter paramMap;
private MethodParameter paramMultivalueMap;
private MethodParameter paramMapForPathVar;
private MethodParameter paramMapWithName;
private final ResolvableMethod testMethod = ResolvableMethod.on(this.getClass()).named("handle").build();
@Before
@@ -69,107 +67,126 @@ public class MatrixVariablesMapMethodArgumentResolverTests {
Map<String, MultiValueMap<String, String>> params = new LinkedHashMap<>();
this.request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, params);
Method method = getClass().getMethod("handle", String.class,
Map.class, MultiValueMap.class, MultiValueMap.class, Map.class);
this.paramString = new SynthesizingMethodParameter(method, 0);
this.paramMap = new SynthesizingMethodParameter(method, 1);
this.paramMultivalueMap = new SynthesizingMethodParameter(method, 2);
this.paramMapForPathVar = new SynthesizingMethodParameter(method, 3);
this.paramMapWithName = new SynthesizingMethodParameter(method, 4);
}
@Test
public void supportsParameter() {
assertFalse(resolver.supportsParameter(paramString));
assertTrue(resolver.supportsParameter(paramMap));
assertTrue(resolver.supportsParameter(paramMultivalueMap));
assertTrue(resolver.supportsParameter(paramMapForPathVar));
assertFalse(resolver.supportsParameter(paramMapWithName));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
assertTrue(this.resolver.supportsParameter(this.testMethod.annot(matrixAttribute().noName())
.arg(Map.class, String.class, String.class)));
assertTrue(this.resolver.supportsParameter(this.testMethod.annot(matrixAttribute().noPathVar())
.arg(MultiValueMap.class, String.class, String.class)));
assertTrue(this.resolver.supportsParameter(this.testMethod.annot(matrixAttribute().pathVar("cars"))
.arg(MultiValueMap.class, String.class, String.class)));
assertFalse(this.resolver.supportsParameter(this.testMethod.annot(matrixAttribute().name("name"))
.arg(Map.class, String.class, String.class)));
}
@Test
public void resolveArgument() throws Exception {
MultiValueMap<String, String> params = getMatrixVariables("cars");
MultiValueMap<String, String> params = getVariablesFor("cars");
params.add("colors", "red");
params.add("colors", "green");
params.add("colors", "blue");
params.add("year", "2012");
MethodParameter param = this.testMethod.annot(matrixAttribute().noName())
.arg(Map.class, String.class, String.class);
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) this.resolver.resolveArgument(
this.paramMap, this.mavContainer, this.webRequest, null);
Map<String, String> map = (Map<String, String>)
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
assertEquals("red", map.get("colors"));
param = this.testMethod
.annot(matrixAttribute().noPathVar())
.arg(MultiValueMap.class, String.class, String.class);
@SuppressWarnings("unchecked")
MultiValueMap<String, String> multivalueMap = (MultiValueMap<String, String>) this.resolver.resolveArgument(
this.paramMultivalueMap, this.mavContainer, this.webRequest, null);
MultiValueMap<String, String> multivalueMap = (MultiValueMap<String, String>)
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
assertEquals(Arrays.asList("red", "green", "blue"), multivalueMap.get("colors"));
}
@Test
public void resolveArgumentPathVariable() throws Exception {
MultiValueMap<String, String> params1 = getMatrixVariables("cars");
MultiValueMap<String, String> params1 = getVariablesFor("cars");
params1.add("colors", "red");
params1.add("colors", "purple");
MultiValueMap<String, String> params2 = getMatrixVariables("planes");
MultiValueMap<String, String> params2 = getVariablesFor("planes");
params2.add("colors", "yellow");
params2.add("colors", "orange");
MethodParameter param = this.testMethod.annot(matrixAttribute().pathVar("cars"))
.arg(MultiValueMap.class, String.class, String.class);
@SuppressWarnings("unchecked")
Map<String, String> mapForPathVar = (Map<String, String>) this.resolver.resolveArgument(
this.paramMapForPathVar, this.mavContainer, this.webRequest, null);
param, this.mavContainer, this.webRequest, null);
assertEquals(Arrays.asList("red", "purple"), mapForPathVar.get("colors"));
param = this.testMethod.annot(matrixAttribute().noName()).arg(Map.class, String.class, String.class);
@SuppressWarnings("unchecked")
Map<String, String> mapAll = (Map<String, String>) this.resolver.resolveArgument(
this.paramMap, this.mavContainer, this.webRequest, null);
Map<String, String> mapAll = (Map<String, String>)
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
assertEquals("red", mapAll.get("colors"));
}
@Test
public void resolveArgumentNoParams() throws Exception {
MethodParameter param = this.testMethod.annot(matrixAttribute().noName())
.arg(Map.class, String.class, String.class);
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) this.resolver.resolveArgument(
this.paramMap, this.mavContainer, this.webRequest, null);
Map<String, String> map = (Map<String, String>)
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
assertEquals(Collections.emptyMap(), map);
}
@Test
public void resolveArgumentNoMatch() throws Exception {
MultiValueMap<String, String> params2 = getMatrixVariables("planes");
MultiValueMap<String, String> params2 = getVariablesFor("planes");
params2.add("colors", "yellow");
params2.add("colors", "orange");
MethodParameter param = this.testMethod.annot(matrixAttribute().pathVar("cars"))
.arg(MultiValueMap.class, String.class, String.class);
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) this.resolver.resolveArgument(
this.paramMapForPathVar, this.mavContainer, this.webRequest, null);
Map<String, String> map = (Map<String, String>)
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
assertEquals(Collections.emptyMap(), map);
}
@SuppressWarnings("unchecked")
private MultiValueMap<String, String> getMatrixVariables(String pathVarName) {
private MultiValueMap<String, String> getVariablesFor(String pathVarName) {
Map<String, MultiValueMap<String, String>> matrixVariables =
(Map<String, MultiValueMap<String, String>>) this.request.getAttribute(
HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
matrixVariables.put(pathVarName, params);
return params;
}
@SuppressWarnings("unused")
public void handle(
String stringArg,
@MatrixVariable Map<String, String> map,

View File

@@ -16,7 +16,6 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
@@ -25,7 +24,6 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
@@ -34,14 +32,17 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.method.MvcAnnotationPredicates.matrixAttribute;
/**
* Test fixture with {@link MatrixVariableMethodArgumentResolver}.
*
* @author Rossen Stoyanchev
*/
public class MatrixVariablesMethodArgumentResolverTests {
@@ -54,9 +55,7 @@ public class MatrixVariablesMethodArgumentResolverTests {
private MockHttpServletRequest request;
private MethodParameter paramString;
private MethodParameter paramColors;
private MethodParameter paramYear;
private ResolvableMethod testMethod = ResolvableMethod.on(this.getClass()).named("handle").build();
@Before
@@ -68,77 +67,81 @@ public class MatrixVariablesMethodArgumentResolverTests {
Map<String, MultiValueMap<String, String>> params = new LinkedHashMap<>();
this.request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, params);
Method method = getClass().getMethod("handle", String.class, List.class, int.class);
this.paramString = new MethodParameter(method, 0);
this.paramColors = new MethodParameter(method, 1);
this.paramColors.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
this.paramYear = new MethodParameter(method, 2);
}
@Test
public void supportsParameter() {
assertFalse(resolver.supportsParameter(paramString));
assertTrue(resolver.supportsParameter(paramColors));
assertTrue(resolver.supportsParameter(paramYear));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
assertTrue(this.resolver.supportsParameter(
this.testMethod.annot(matrixAttribute().noName()).arg(List.class, String.class)));
assertTrue(this.resolver.supportsParameter(
this.testMethod.annot(matrixAttribute().name("year")).arg(int.class)));
}
@Test
public void resolveArgument() throws Exception {
MultiValueMap<String, String> params = getMatrixVariables("cars");
MultiValueMap<String, String> params = getVariablesFor("cars");
params.add("colors", "red");
params.add("colors", "green");
params.add("colors", "blue");
MethodParameter param = this.testMethod.annot(matrixAttribute().noName()).arg(List.class, String.class);
assertEquals(Arrays.asList("red", "green", "blue"),
this.resolver.resolveArgument(this.paramColors, this.mavContainer, this.webRequest, null));
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null));
}
@Test
public void resolveArgumentPathVariable() throws Exception {
getMatrixVariables("cars").add("year", "2006");
getMatrixVariables("bikes").add("year", "2005");
getVariablesFor("cars").add("year", "2006");
getVariablesFor("bikes").add("year", "2005");
MethodParameter param = this.testMethod.annot(matrixAttribute().name("year")).arg(int.class);
assertEquals("2006", this.resolver.resolveArgument(this.paramYear, this.mavContainer, this.webRequest, null));
assertEquals("2006", this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null));
}
@Test
public void resolveArgumentDefaultValue() throws Exception {
assertEquals("2013", resolver.resolveArgument(this.paramYear, this.mavContainer, this.webRequest, null));
MethodParameter param = this.testMethod.annot(matrixAttribute().name("year")).arg(int.class);
assertEquals("2013", resolver.resolveArgument(param, this.mavContainer, this.webRequest, null));
}
@Test(expected = ServletRequestBindingException.class)
public void resolveArgumentMultipleMatches() throws Exception {
getMatrixVariables("var1").add("colors", "red");
getMatrixVariables("var2").add("colors", "green");
getVariablesFor("var1").add("colors", "red");
getVariablesFor("var2").add("colors", "green");
MethodParameter param = this.testMethod.annot(matrixAttribute().noName()).arg(List.class, String.class);
this.resolver.resolveArgument(this.paramColors, this.mavContainer, this.webRequest, null);
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
}
@Test(expected = ServletRequestBindingException.class)
public void resolveArgumentRequired() throws Exception {
resolver.resolveArgument(this.paramColors, this.mavContainer, this.webRequest, null);
MethodParameter param = this.testMethod.annot(matrixAttribute().noName()).arg(List.class, String.class);
this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null);
}
@Test
public void resolveArgumentNoMatch() throws Exception {
MultiValueMap<String, String> params = getMatrixVariables("cars");
MultiValueMap<String, String> params = getVariablesFor("cars");
params.add("anotherYear", "2012");
MethodParameter param = this.testMethod.annot(matrixAttribute().name("year")).arg(int.class);
assertEquals("2013", this.resolver.resolveArgument(this.paramYear, this.mavContainer, this.webRequest, null));
assertEquals("2013", this.resolver.resolveArgument(param, this.mavContainer, this.webRequest, null));
}
@SuppressWarnings("unchecked")
private MultiValueMap<String, String> getMatrixVariables(String pathVarName) {
private MultiValueMap<String, String> getVariablesFor(String pathVarName) {
Map<String, MultiValueMap<String, String>> matrixVariables =
(Map<String, MultiValueMap<String, String>>) this.request.getAttribute(
HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
matrixVariables.put(pathVarName, params);
return params;
}