diff --git a/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java b/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java index 707f95f703a..103b10465ba 100644 --- a/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java +++ b/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java @@ -42,7 +42,7 @@ import org.springframework.core.MethodIntrospector; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.objenesis.ObjenesisException; import org.springframework.objenesis.SpringObjenesis; import org.springframework.util.Assert; @@ -83,7 +83,7 @@ import org.springframework.util.ReflectionUtils; * on(TestController.class).annotated(ResponseBody.class).resolveReturnType(Bar.class); * * // Annotation not present - * on(TestController.class).isNotAnnotated(ResponseBody.class).resolveReturnType(); + * on(TestController.class).notAnnotated(ResponseBody.class).resolveReturnType(); * * // Annotation properties * on(TestController.class) @@ -145,7 +145,7 @@ public class ResolvableMethod { * Return the declared return type of the resolved method. */ public MethodParameter returnType() { - return new MethodParameter(this.method, -1); + return new SynthesizingMethodParameter(this.method, -1); } /** @@ -262,9 +262,17 @@ public class ResolvableMethod { /** * Filter on methods not annotated with the given annotation type. */ - public final Builder isNotAnnotated(Class annotationType) { - String message = "notAnnotated=" + annotationType.getName(); - addFilter(message, m -> AnnotationUtils.findAnnotation(m, annotationType) == null); + public final Builder notAnnotated(Class... annotationTypes) { + String message = "notAnnotated=" + Arrays.toString(annotationTypes); + addFilter(message, method -> { + if (annotationTypes.length != 0) { + return Arrays.stream(annotationTypes).noneMatch(annotType -> + AnnotatedElementUtils.findMergedAnnotation(method, annotType) != null); + } + else { + return method.getAnnotations().length == 0; + } + }); return this; } @@ -505,7 +513,10 @@ public class ResolvableMethod { */ @SafeVarargs public final ArgResolver notAnnotated(Class... annotationTypes) { - this.filters.add(p -> Arrays.stream(annotationTypes).noneMatch(p::hasParameterAnnotation)); + this.filters.add(param -> + (annotationTypes.length != 0) ? + Arrays.stream(annotationTypes).noneMatch(param::hasParameterAnnotation) : + param.getParameterAnnotations().length == 0); return this; } @@ -550,7 +561,7 @@ public class ResolvableMethod { private List applyFilters() { List matches = new ArrayList<>(); for (int i = 0; i < method.getParameterCount(); i++) { - MethodParameter param = new MethodParameter(method, i); + MethodParameter param = new SynthesizingMethodParameter(method, i); if (this.filters.stream().allMatch(p -> p.test(param))) { matches.add(param); } diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java index 1d60508c0e3..33af8850bb5 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java @@ -16,15 +16,14 @@ package org.springframework.web.method.annotation; -import java.lang.reflect.Method; import java.util.Collections; import java.util.Map; +import java.util.function.Predicate; 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; @@ -32,6 +31,7 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.method.ResolvableMethod; import static org.junit.Assert.*; @@ -45,29 +45,17 @@ public class RequestParamMapMethodArgumentResolverTests { private RequestParamMapMethodArgumentResolver resolver; - private MethodParameter paramMap; - - private MethodParameter paramMultiValueMap; - - private MethodParameter paramNamedMap; - - private MethodParameter paramMapWithoutAnnot; - private NativeWebRequest webRequest; private MockHttpServletRequest request; + private ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handle").build(); + @Before public void setUp() throws Exception { resolver = new RequestParamMapMethodArgumentResolver(); - Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, Map.class, Map.class); - paramMap = new SynthesizingMethodParameter(method, 0); - paramMultiValueMap = new SynthesizingMethodParameter(method, 1); - paramNamedMap = new SynthesizingMethodParameter(method, 2); - paramMapWithoutAnnot = new SynthesizingMethodParameter(method, 3); - request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } @@ -75,10 +63,17 @@ public class RequestParamMapMethodArgumentResolverTests { @Test public void supportsParameter() { - assertTrue("Map parameter not supported", resolver.supportsParameter(paramMap)); - assertTrue("MultiValueMap parameter not supported", resolver.supportsParameter(paramMultiValueMap)); - assertFalse("Map with name supported", resolver.supportsParameter(paramNamedMap)); - assertFalse("non-@RequestParam map supported", resolver.supportsParameter(paramMapWithoutAnnot)); + MethodParameter param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(MultiValueMap.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("name")).arg(Map.class); + assertFalse(resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(Map.class); + assertFalse(resolver.supportsParameter(param)); } @Test @@ -88,7 +83,8 @@ public class RequestParamMapMethodArgumentResolverTests { request.addParameter(name, value); Map expected = Collections.singletonMap(name, value); - Object result = resolver.resolveArgument(paramMap, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Map); assertEquals("Invalid result", expected, result); @@ -99,23 +95,29 @@ public class RequestParamMapMethodArgumentResolverTests { String name = "foo"; String value1 = "bar"; String value2 = "baz"; - request.addParameter(name, new String[]{value1, value2}); + request.addParameter(name, value1, value2); MultiValueMap expected = new LinkedMultiValueMap<>(1); expected.add(name, value1); expected.add(name, value2); - Object result = resolver.resolveArgument(paramMultiValueMap, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultiValueMap.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultiValueMap); assertEquals("Invalid result", expected, result); } + private Predicate name(String name) { + return a -> name.equals(a.name()); + } + - public void params(@RequestParam Map param1, - @RequestParam MultiValueMap param2, - @RequestParam("name") Map param3, - Map param4) { + public void handle( + @RequestParam Map param1, + @RequestParam MultiValueMap param2, + @RequestParam("name") Map param3, + Map param4) { } } diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java index f77ce2bc65f..21f0e731118 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java @@ -16,11 +16,11 @@ package org.springframework.web.method.annotation; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; import javax.servlet.http.Part; import org.junit.Before; @@ -29,31 +29,37 @@ import org.junit.Test; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockMultipartFile; import org.springframework.mock.web.test.MockMultipartHttpServletRequest; import org.springframework.mock.web.test.MockPart; -import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.DefaultDataBinderFactory; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.bind.support.WebRequestDataBinder; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.method.ResolvableMethod; import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.support.MissingServletRequestPartException; -import static org.junit.Assert.*; -import static org.mockito.BDDMockito.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.mock; +import static org.springframework.core.ResolvableType.forClassWithGenerics; /** * Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}. @@ -66,92 +72,87 @@ public class RequestParamMethodArgumentResolverTests { private RequestParamMethodArgumentResolver resolver; - private MethodParameter paramNamedDefaultValueString; - private MethodParameter paramNamedStringArray; - private MethodParameter paramNamedMap; - private MethodParameter paramMultipartFile; - private MethodParameter paramMultipartFileList; - private MethodParameter paramMultipartFileArray; - private MethodParameter paramPart; - private MethodParameter paramPartList; - private MethodParameter paramPartArray; - private MethodParameter paramMap; - private MethodParameter paramStringNotAnnot; - private MethodParameter paramMultipartFileNotAnnot; - private MethodParameter paramMultipartFileListNotAnnot; - private MethodParameter paramPartNotAnnot; - private MethodParameter paramRequestPartAnnot; - private MethodParameter paramRequired; - private MethodParameter paramNotRequired; - private MethodParameter paramOptional; - private MethodParameter multipartFileOptional; - private NativeWebRequest webRequest; private MockHttpServletRequest request; + private ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handle").build(); @Before public void setUp() throws Exception { resolver = new RequestParamMethodArgumentResolver(null, true); - ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class[]) null); - - paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 0); - paramNamedStringArray = new SynthesizingMethodParameter(method, 1); - paramNamedMap = new SynthesizingMethodParameter(method, 2); - paramMultipartFile = new SynthesizingMethodParameter(method, 3); - paramMultipartFileList = new SynthesizingMethodParameter(method, 4); - paramMultipartFileArray = new SynthesizingMethodParameter(method, 5); - paramPart = new SynthesizingMethodParameter(method, 6); - paramPartList = new SynthesizingMethodParameter(method, 7); - paramPartArray = new SynthesizingMethodParameter(method, 8); - paramMap = new SynthesizingMethodParameter(method, 9); - paramStringNotAnnot = new SynthesizingMethodParameter(method, 10); - paramStringNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileNotAnnot = new SynthesizingMethodParameter(method, 11); - paramMultipartFileNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileListNotAnnot = new SynthesizingMethodParameter(method, 12); - paramMultipartFileListNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramPartNotAnnot = new SynthesizingMethodParameter(method, 13); - paramPartNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramRequestPartAnnot = new SynthesizingMethodParameter(method, 14); - paramRequired = new SynthesizingMethodParameter(method, 15); - paramNotRequired = new SynthesizingMethodParameter(method, 16); - paramOptional = new SynthesizingMethodParameter(method, 17); - multipartFileOptional = new SynthesizingMethodParameter(method, 18); - request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } - @Test public void supportsParameter() { resolver = new RequestParamMethodArgumentResolver(null, true); - assertTrue(resolver.supportsParameter(paramNamedDefaultValueString)); - assertTrue(resolver.supportsParameter(paramNamedStringArray)); - assertTrue(resolver.supportsParameter(paramNamedMap)); - assertTrue(resolver.supportsParameter(paramMultipartFile)); - assertTrue(resolver.supportsParameter(paramMultipartFileList)); - assertTrue(resolver.supportsParameter(paramMultipartFileArray)); - assertTrue(resolver.supportsParameter(paramPart)); - assertTrue(resolver.supportsParameter(paramPartList)); - assertTrue(resolver.supportsParameter(paramPartArray)); - assertFalse(resolver.supportsParameter(paramMap)); - assertTrue(resolver.supportsParameter(paramStringNotAnnot)); - assertTrue(resolver.supportsParameter(paramMultipartFileNotAnnot)); - assertTrue(resolver.supportsParameter(paramMultipartFileListNotAnnot)); - assertTrue(resolver.supportsParameter(paramPartNotAnnot)); - assertFalse(resolver.supportsParameter(paramRequestPartAnnot)); - assertTrue(resolver.supportsParameter(paramRequired)); - assertTrue(resolver.supportsParameter(paramNotRequired)); - assertTrue(resolver.supportsParameter(paramOptional)); - assertTrue(resolver.supportsParameter(multipartFileOptional)); + + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("name")).arg(Map.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(List.class, MultipartFile.class)); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile[].class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(Part.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(List.class, Part.class)); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(Part[].class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + assertFalse(resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated().arg(MultipartFile.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(forClassWithGenerics(List.class, MultipartFile.class)); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(Part.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestPart.class).arg(MultipartFile.class); + assertFalse(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, required(), value("")).arg(String.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, required().negate()).arg(String.class); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(Optional.class, Integer.class)); + assertTrue(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(Optional.class, MultipartFile.class)); + assertTrue(resolver.supportsParameter(param)); resolver = new RequestParamMethodArgumentResolver(null, false); - assertFalse(resolver.supportsParameter(paramStringNotAnnot)); - assertFalse(resolver.supportsParameter(paramRequestPartAnnot)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + assertFalse(resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestPart.class).arg(MultipartFile.class); + assertFalse(resolver.supportsParameter(param)); } @Test @@ -159,7 +160,8 @@ public class RequestParamMethodArgumentResolverTests { String expected = "foo"; request.addParameter("name", expected); - Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String); assertEquals("Invalid result", expected, result); } @@ -169,7 +171,8 @@ public class RequestParamMethodArgumentResolverTests { String[] expected = new String[] {"foo", "bar"}; request.addParameter("name", expected); - Object result = resolver.resolveArgument(paramNamedStringArray, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String[]); assertArrayEquals("Invalid result", expected, (String[]) result); } @@ -181,7 +184,8 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFile, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultipartFile); assertEquals("Invalid result", expected, result); } @@ -196,7 +200,11 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(new MockMultipartFile("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null); + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(List.class, MultipartFile.class)); + + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); } @@ -211,7 +219,8 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(new MockMultipartFile("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFileArray, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile[].class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultipartFile[]); MultipartFile[] parts = (MultipartFile[]) result; assertEquals(2, parts.length); @@ -228,7 +237,8 @@ public class RequestParamMethodArgumentResolverTests { request.addPart(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramPart, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(Part.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Part); assertEquals("Invalid result", expected, result); } @@ -245,7 +255,11 @@ public class RequestParamMethodArgumentResolverTests { request.addPart(new MockPart("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramPartList, null, webRequest, null); + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(List.class, Part.class)); + + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); } @@ -262,7 +276,8 @@ public class RequestParamMethodArgumentResolverTests { request.addPart(new MockPart("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(Part[].class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Part[]); Part[] parts = (Part[]) result; assertEquals(2, parts.length); @@ -277,7 +292,10 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFileNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod.notAnnotated().arg(MultipartFile.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultipartFile); assertEquals("Invalid result", expected, result); } @@ -291,14 +309,20 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(expected2); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod + .notAnnotated(RequestParam.class) + .arg(forClassWithGenerics(List.class, MultipartFile.class)); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); } @Test(expected = MultipartException.class) public void isMultipartRequest() throws Exception { - resolver.resolveArgument(paramMultipartFile, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class); + resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: request is not a multipart request"); } @@ -310,7 +334,12 @@ public class RequestParamMethodArgumentResolverTests { request.setMethod("PUT"); webRequest = new ServletWebRequest(request); - Object actual = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod + .notAnnotated(RequestParam.class) + .arg(forClassWithGenerics(List.class, MultipartFile.class)); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + + Object actual = resolver.resolveArgument(param, null, webRequest, null); assertTrue(actual instanceof List); assertEquals(expected, ((List) actual).get(0)); } @@ -318,7 +347,8 @@ public class RequestParamMethodArgumentResolverTests { @Test(expected = MultipartException.class) public void noMultipartContent() throws Exception { request.setMethod("POST"); - resolver.resolveArgument(paramMultipartFile, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class); + resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: no multipart content"); } @@ -326,7 +356,8 @@ public class RequestParamMethodArgumentResolverTests { public void missingMultipartFile() throws Exception { request.setMethod("POST"); request.setContentType("multipart/form-data"); - resolver.resolveArgument(paramMultipartFile, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class); + resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: no such part found"); } @@ -339,21 +370,25 @@ public class RequestParamMethodArgumentResolverTests { request.addPart(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramPartNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(Part.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Part); assertEquals("Invalid result", expected, result); } @Test public void resolveDefaultValue() throws Exception { - Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String); assertEquals("Invalid result", "bar", result); } @Test(expected = MissingServletRequestParameterException.class) public void missingRequestParam() throws Exception { - resolver.resolveArgument(paramNamedStringArray, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception"); } @@ -367,7 +402,9 @@ public class RequestParamMethodArgumentResolverTests { this.request.addParameter("stringNotAnnot", ""); - Object arg = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object arg = resolver.resolveArgument(param, null, webRequest, binderFactory); assertNull(arg); } @@ -381,14 +418,18 @@ public class RequestParamMethodArgumentResolverTests { this.request.addParameter("name", ""); - Object arg = resolver.resolveArgument(paramNotRequired, null, webRequest, binderFactory); + MethodParameter param = this.testMethod.annotated(RequestParam.class, required().negate()).arg(String.class); + Object arg = resolver.resolveArgument(param, null, webRequest, binderFactory); assertNull(arg); } @Test public void resolveSimpleTypeParam() throws Exception { request.setParameter("stringNotAnnot", "plainValue"); - Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object result = resolver.resolveArgument(param, null, webRequest, null); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); assertTrue(result instanceof String); assertEquals("plainValue", result); @@ -396,28 +437,34 @@ public class RequestParamMethodArgumentResolverTests { @Test // SPR-8561 public void resolveSimpleTypeParamToNull() throws Exception { - Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertNull(result); } @Test // SPR-10180 public void resolveEmptyValueToDefault() throws Exception { this.request.addParameter("name", ""); - Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertEquals("bar", result); } @Test public void resolveEmptyValueWithoutDefault() throws Exception { this.request.addParameter("stringNotAnnot", ""); - Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertEquals("", result); } @Test public void resolveEmptyValueRequiredWithoutDefault() throws Exception { this.request.addParameter("name", ""); - Object result = resolver.resolveArgument(paramRequired, null, webRequest, null); + MethodParameter param = this.testMethod.annotated(RequestParam.class, required(), value("")).arg(String.class); + Object result = resolver.resolveArgument(param, null, webRequest, null); assertEquals("", result); } @@ -428,11 +475,15 @@ public class RequestParamMethodArgumentResolverTests { initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); - Object result = resolver.resolveArgument(paramOptional, null, webRequest, binderFactory); + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(Optional.class, Integer.class)); + + Object result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.empty(), result); this.request.addParameter("name", "123"); - result = resolver.resolveArgument(paramOptional, null, webRequest, binderFactory); + result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.class, result.getClass()); assertEquals(123, ((Optional) result).get()); } @@ -448,7 +499,11 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(multipartFileOptional, null, webRequest, binderFactory); + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(Optional.class, MultipartFile.class)); + + Object result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertTrue(result instanceof Optional); assertEquals("Invalid result", expected, ((Optional) result).get()); } @@ -461,7 +516,12 @@ public class RequestParamMethodArgumentResolverTests { request.setMethod("POST"); request.setContentType("multipart/form-data"); - assertEquals(Optional.empty(), resolver.resolveArgument(multipartFileOptional, null, webRequest, binderFactory)); + + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(Optional.class, MultipartFile.class)); + + assertEquals(Optional.empty(), resolver.resolveArgument(param, null, webRequest, binderFactory)); } @Test @@ -470,10 +530,29 @@ public class RequestParamMethodArgumentResolverTests { initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); - assertEquals(Optional.empty(), resolver.resolveArgument(multipartFileOptional, null, webRequest, binderFactory)); + MethodParameter param = this.testMethod + .annotated(RequestParam.class) + .arg(forClassWithGenerics(Optional.class, MultipartFile.class)); + + assertEquals(Optional.empty(), resolver.resolveArgument(param, null, webRequest, binderFactory)); + } + + private Predicate name(String name) { + return a -> name.equals(a.name()); + } + + private Predicate required() { + return RequestParam::required; + } + + private Predicate value(String value) { + return !value.isEmpty() ? + requestParam -> value.equals(requestParam.defaultValue()) : + requestParam -> ValueConstants.DEFAULT_NONE.equals(requestParam.defaultValue()); } + @SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"}) public void handle( @RequestParam(name = "name", defaultValue = "bar") String param1, @RequestParam("name") String[] param2, diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java index 82fc522d17d..5e48428ddf1 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java @@ -16,22 +16,22 @@ package org.springframework.web.reactive.result.method.annotation; -import java.lang.reflect.Method; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.function.Predicate; import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.MediaType; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.method.ResolvableMethod; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -47,50 +47,51 @@ public class RequestParamMapMethodArgumentResolverTests { private RequestParamMapMethodArgumentResolver resolver; - private MethodParameter paramMap; - private MethodParameter paramMultiValueMap; - private MethodParameter paramNamedMap; - private MethodParameter paramMapWithoutAnnot; + private ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handle").build(); @Before public void setup() throws Exception { this.resolver = new RequestParamMapMethodArgumentResolver(); - - Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, Map.class, Map.class); - this.paramMap = new SynthesizingMethodParameter(method, 0); - this.paramMultiValueMap = new SynthesizingMethodParameter(method, 1); - this.paramNamedMap = new SynthesizingMethodParameter(method, 2); - this.paramMapWithoutAnnot = new SynthesizingMethodParameter(method, 3); } @Test public void supportsParameter() { - assertTrue(this.resolver.supportsParameter(this.paramMap)); - assertTrue(this.resolver.supportsParameter(this.paramMultiValueMap)); - assertFalse(this.resolver.supportsParameter(this.paramNamedMap)); - assertFalse(this.resolver.supportsParameter(this.paramMapWithoutAnnot)); + MethodParameter param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(MultiValueMap.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("name")).arg(Map.class); + assertFalse(this.resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(Map.class); + assertFalse(this.resolver.supportsParameter(param)); } @Test public void resolveMapArgumentWithQueryString() throws Exception { - Object result= resolve(this.paramMap, exchangeWithQuery("foo=bar")); + MethodParameter param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + Object result= resolve(param, exchangeWithQuery("foo=bar")); assertTrue(result instanceof Map); assertEquals(Collections.singletonMap("foo", "bar"), result); } @Test public void resolveMapArgumentWithFormData() throws Exception { - Object result= resolve(this.paramMap, exchangeWithFormData("foo=bar")); + MethodParameter param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + Object result= resolve(param, exchangeWithFormData("foo=bar")); assertTrue(result instanceof Map); assertEquals(Collections.singletonMap("foo", "bar"), result); } @Test public void resolveMultiValueMapArgument() throws Exception { + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(MultiValueMap.class); ServerWebExchange exchange = exchangeWithQuery("foo=bar&foo=baz"); - Object result= resolve(this.paramMultiValueMap, exchange); + Object result= resolve(param, exchange); assertTrue(result instanceof MultiValueMap); assertEquals(Collections.singletonMap("foo", Arrays.asList("bar", "baz")), result); @@ -113,12 +114,17 @@ public class RequestParamMapMethodArgumentResolverTests { return this.resolver.resolveArgument(parameter, null, exchange).blockMillis(0); } + private Predicate name(String name) { + return a -> name.equals(a.name()); + } + @SuppressWarnings("unused") - public void params(@RequestParam Map param1, - @RequestParam MultiValueMap param2, - @RequestParam("name") Map param3, - Map param4) { + public void handle( + @RequestParam Map param1, + @RequestParam MultiValueMap param2, + @RequestParam("name") Map param3, + Map param4) { } -} +} \ No newline at end of file diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java index 8eee1b4146e..c47b8a44ef0 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java @@ -16,10 +16,10 @@ package org.springframework.web.reactive.result.method.annotation; -import java.lang.reflect.Method; import java.net.URISyntaxException; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; import org.junit.Before; import org.junit.Test; @@ -28,21 +28,25 @@ import reactor.test.StepVerifier; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.http.MediaType; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; -import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ValueConstants; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; +import org.springframework.web.method.ResolvableMethod; import org.springframework.web.reactive.BindingContext; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; import org.springframework.web.server.adapter.DefaultServerWebExchange; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.core.ResolvableType.forClassWithGenerics; /** * Unit tests for {@link RequestParamMethodArgumentResolver}. @@ -53,34 +57,15 @@ public class RequestParamMethodArgumentResolverTests { private RequestParamMethodArgumentResolver resolver; - private MethodParameter paramNamedDefaultValueString; - private MethodParameter paramNamedStringArray; - private MethodParameter paramNamedMap; - private MethodParameter paramMap; - private MethodParameter paramStringNotAnnot; - private MethodParameter paramRequired; - private MethodParameter paramNotRequired; - private MethodParameter paramOptional; - private BindingContext bindContext; + private ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handle").build(); + @Before public void setup() throws Exception { - this.resolver = new RequestParamMethodArgumentResolver(null, true); - ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class[]) null); - - this.paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 0); - this.paramNamedStringArray = new SynthesizingMethodParameter(method, 1); - this.paramNamedMap = new SynthesizingMethodParameter(method, 2); - this.paramMap = new SynthesizingMethodParameter(method, 3); - this.paramStringNotAnnot = new SynthesizingMethodParameter(method, 4); - this.paramStringNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - this.paramRequired = new SynthesizingMethodParameter(method, 5); - this.paramNotRequired = new SynthesizingMethodParameter(method, 6); - this.paramOptional = new SynthesizingMethodParameter(method, 7); + this.resolver = new RequestParamMethodArgumentResolver(null, true); ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); initializer.setConversionService(new DefaultFormattingConversionService()); @@ -91,47 +76,64 @@ public class RequestParamMethodArgumentResolverTests { @Test public void supportsParameter() { this.resolver = new RequestParamMethodArgumentResolver(null, true); - assertTrue(this.resolver.supportsParameter(this.paramNamedDefaultValueString)); - assertTrue(this.resolver.supportsParameter(this.paramNamedStringArray)); - assertTrue(this.resolver.supportsParameter(this.paramNamedMap)); - assertFalse(this.resolver.supportsParameter(this.paramMap)); - assertTrue(this.resolver.supportsParameter(this.paramStringNotAnnot)); - assertTrue(this.resolver.supportsParameter(this.paramRequired)); - assertTrue(this.resolver.supportsParameter(this.paramNotRequired)); - assertTrue(this.resolver.supportsParameter(this.paramOptional)); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("name")).arg(Map.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, name("")).arg(Map.class); + assertFalse(this.resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, required(), value("")).arg(String.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.annotated(RequestParam.class, required().negate()).arg(String.class); + assertTrue(this.resolver.supportsParameter(param)); + + param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); this.resolver = new RequestParamMethodArgumentResolver(null, false); - assertFalse(this.resolver.supportsParameter(this.paramStringNotAnnot)); + assertFalse(this.resolver.supportsParameter(param)); } @Test public void resolveWithQueryString() throws Exception { - assertEquals("foo", resolve(this.paramNamedDefaultValueString, exchangeWithQuery("name=foo"))); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + assertEquals("foo", resolve(param, exchangeWithQuery("name=foo"))); } @Test public void resolveWithFormData() throws Exception { - assertEquals("foo", resolve(this.paramNamedDefaultValueString, exchangeWithFormData("name=foo"))); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + assertEquals("foo", resolve(param, exchangeWithFormData("name=foo"))); } @Test public void resolveStringArray() throws Exception { - Object result = resolve(this.paramNamedStringArray, exchangeWithQuery("name=foo&name=bar")); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + Object result = resolve(param, exchangeWithQuery("name=foo&name=bar")); assertTrue(result instanceof String[]); assertArrayEquals(new String[] {"foo", "bar"}, (String[]) result); } @Test public void resolveDefaultValue() throws Exception { - Object result = resolve(this.paramNamedDefaultValueString, exchange()); - assertEquals("bar", result); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + assertEquals("bar", resolve(param, exchange())); } @Test public void missingRequestParam() throws Exception { - Mono mono = this.resolver.resolveArgument( - this.paramNamedStringArray, this.bindContext, exchange()); + MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(String[].class); + Mono mono = this.resolver.resolveArgument(param, this.bindContext, exchange()); StepVerifier.create(mono) .expectNextCount(0) @@ -142,40 +144,52 @@ public class RequestParamMethodArgumentResolverTests { @Test public void resolveSimpleTypeParam() throws Exception { ServerWebExchange exchange = exchangeWithQuery("stringNotAnnot=plainValue"); - Object result = resolve(this.paramStringNotAnnot, exchange); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + Object result = resolve(param, exchange); assertEquals("plainValue", result); } @Test // SPR-8561 public void resolveSimpleTypeParamToNull() throws Exception { - assertNull(resolve(this.paramStringNotAnnot, exchange())); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + assertNull(resolve(param, exchange())); } @Test // SPR-10180 public void resolveEmptyValueToDefault() throws Exception { ServerWebExchange exchange = exchangeWithQuery("name="); - Object result = resolve(this.paramNamedDefaultValueString, exchange); + MethodParameter param = this.testMethod.annotated(RequestParam.class, value("bar")).arg(String.class); + Object result = resolve(param, exchange); assertEquals("bar", result); } @Test public void resolveEmptyValueWithoutDefault() throws Exception { - assertEquals("", resolve(this.paramStringNotAnnot, exchangeWithQuery("stringNotAnnot="))); + MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class); + param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); + assertEquals("", resolve(param, exchangeWithQuery("stringNotAnnot="))); } @Test public void resolveEmptyValueRequiredWithoutDefault() throws Exception { - assertEquals("", resolve(this.paramRequired, exchangeWithQuery("name="))); + MethodParameter param = this.testMethod + .annotated(RequestParam.class, required(), value("")) + .arg(String.class); + + assertEquals("", resolve(param, exchangeWithQuery("name="))); } @Test public void resolveOptionalParamValue() throws Exception { ServerWebExchange exchange = exchange(); - Object result = resolve(this.paramOptional, exchange); + MethodParameter param = this.testMethod.arg(forClassWithGenerics(Optional.class, Integer.class)); + Object result = resolve(param, exchange); assertEquals(Optional.empty(), result); exchange = exchangeWithQuery("name=123"); - result = resolve(this.paramOptional, exchange); + result = resolve(param, exchange); assertEquals(Optional.class, result.getClass()); Optional value = (Optional) result; @@ -205,6 +219,20 @@ public class RequestParamMethodArgumentResolverTests { return this.resolver.resolveArgument(parameter, this.bindContext, exchange).blockMillis(0); } + private Predicate name(String name) { + return a -> name.equals(a.name()); + } + + private Predicate required() { + return RequestParam::required; + } + + private Predicate value(String value) { + return !value.isEmpty() ? + requestParam -> value.equals(requestParam.defaultValue()) : + requestParam -> ValueConstants.DEFAULT_NONE.equals(requestParam.defaultValue()); + } + @SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"}) public void handle(