/* * 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.method.annotation; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; import javax.servlet.http.Part; import org.junit.Before; import org.junit.Test; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.core.MethodParameter; 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.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.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.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.web.method.MvcAnnotationPredicates.requestParam; import static org.springframework.web.method.MvcAnnotationPredicates.requestPart; /** * Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}. * * @author Arjen Poutsma * @author Rossen Stoyanchev * @author Brian Clozel */ public class RequestParamMethodArgumentResolverTests { private RequestParamMethodArgumentResolver resolver; 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); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } @Test public void supportsParameter() { resolver = new RequestParamMethodArgumentResolver(null, true); MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(String[].class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annot(requestParam().name("name")).arg(Map.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(List.class, MultipartFile.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile[].class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(Part.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(List.class, Part.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(Part[].class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annot(requestParam().noName()).arg(Map.class); assertFalse(resolver.supportsParameter(param)); param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotNotPresent().arg(MultipartFile.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotNotPresent(RequestParam.class).arg(List.class, MultipartFile.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotNotPresent(RequestParam.class).arg(Part.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annot(requestPart()).arg(MultipartFile.class); assertFalse(resolver.supportsParameter(param)); param = this.testMethod.annot(requestParam()).arg(String.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annot(requestParam().notRequired()).arg(String.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, Integer.class); assertTrue(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, MultipartFile.class); assertTrue(resolver.supportsParameter(param)); resolver = new RequestParamMethodArgumentResolver(null, false); param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); assertFalse(resolver.supportsParameter(param)); param = this.testMethod.annotPresent(RequestPart.class).arg(MultipartFile.class); assertFalse(resolver.supportsParameter(param)); } @Test public void resolveString() throws Exception { String expected = "foo"; request.addParameter("name", expected); MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String); assertEquals("Invalid result", expected, result); } @Test public void resolveStringArray() throws Exception { String[] expected = new String[] {"foo", "bar"}; request.addParameter("name", expected); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(String[].class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String[]); assertArrayEquals("Invalid result", expected, (String[]) result); } @Test public void resolveMultipartFile() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes()); request.addFile(expected); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultipartFile); assertEquals("Invalid result", expected, result); } @Test public void resolveMultipartFileList() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected1 = new MockMultipartFile("mfilelist", "Hello World 1".getBytes()); MultipartFile expected2 = new MockMultipartFile("mfilelist", "Hello World 2".getBytes()); request.addFile(expected1); request.addFile(expected2); request.addFile(new MockMultipartFile("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(List.class, MultipartFile.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); } @Test public void resolveMultipartFileArray() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected1 = new MockMultipartFile("mfilearray", "Hello World 1".getBytes()); MultipartFile expected2 = new MockMultipartFile("mfilearray", "Hello World 2".getBytes()); request.addFile(expected1); request.addFile(expected2); request.addFile(new MockMultipartFile("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(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); assertEquals(parts[0], expected1); assertEquals(parts[1], expected2); } @Test public void resolvePart() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); MockPart expected = new MockPart("pfile", "Hello World".getBytes()); request.setMethod("POST"); request.setContentType("multipart/form-data"); request.addPart(expected); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Part.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Part); assertEquals("Invalid result", expected, result); } @Test public void resolvePartList() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("POST"); request.setContentType("multipart/form-data"); MockPart expected1 = new MockPart("pfilelist", "Hello World 1".getBytes()); MockPart expected2 = new MockPart("pfilelist", "Hello World 2".getBytes()); request.addPart(expected1); request.addPart(expected2); request.addPart(new MockPart("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(List.class, Part.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); } @Test public void resolvePartArray() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); MockPart expected1 = new MockPart("pfilearray", "Hello World 1".getBytes()); MockPart expected2 = new MockPart("pfilearray", "Hello World 2".getBytes()); request.setMethod("POST"); request.setContentType("multipart/form-data"); request.addPart(expected1); request.addPart(expected2); request.addPart(new MockPart("other", "Hello World 3".getBytes())); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(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); assertEquals(parts[0], expected1); assertEquals(parts[1], expected2); } @Test public void resolveMultipartFileNotAnnot() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected = new MockMultipartFile("multipartFileNotAnnot", "Hello World".getBytes()); request.addFile(expected); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotNotPresent().arg(MultipartFile.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof MultipartFile); assertEquals("Invalid result", expected, result); } @Test public void resolveMultipartFileListNotannot() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected1 = new MockMultipartFile("multipartFileList", "Hello World 1".getBytes()); MultipartFile expected2 = new MockMultipartFile("multipartFileList", "Hello World 2".getBytes()); request.addFile(expected1); request.addFile(expected2); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod .annotNotPresent(RequestParam.class).arg(List.class, MultipartFile.class); 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 { MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile.class); resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: request is not a multipart request"); } @Test // SPR-9079 public void isMultipartRequestHttpPut() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected = new MockMultipartFile("multipartFileList", "Hello World".getBytes()); request.addFile(expected); request.setMethod("PUT"); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod .annotNotPresent(RequestParam.class).arg(List.class, MultipartFile.class); Object actual = resolver.resolveArgument(param, null, webRequest, null); assertTrue(actual instanceof List); assertEquals(expected, ((List<?>) actual).get(0)); } @Test(expected = MultipartException.class) public void noMultipartContent() throws Exception { request.setMethod("POST"); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile.class); resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: no multipart content"); } @Test(expected = MissingServletRequestPartException.class) public void missingMultipartFile() throws Exception { request.setMethod("POST"); request.setContentType("multipart/form-data"); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(MultipartFile.class); resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception: no such part found"); } @Test public void resolvePartNotAnnot() throws Exception { MockPart expected = new MockPart("part", "Hello World".getBytes()); MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("POST"); request.setContentType("multipart/form-data"); request.addPart(expected); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(Part.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof Part); assertEquals("Invalid result", expected, result); } @Test public void resolveDefaultValue() throws Exception { MethodParameter param = this.testMethod.annot(requestParam().notRequired("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 { MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(String[].class); resolver.resolveArgument(param, null, webRequest, null); fail("Expected exception"); } @Test // SPR-10578 public void missingRequestParamEmptyValueConvertedToNull() throws Exception { WebDataBinder binder = new WebRequestDataBinder(null); binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class); given(binderFactory.createBinder(webRequest, null, "stringNotAnnot")).willReturn(binder); this.request.addParameter("stringNotAnnot", ""); MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); Object arg = resolver.resolveArgument(param, null, webRequest, binderFactory); assertNull(arg); } @Test public void missingRequestParamEmptyValueNotRequired() throws Exception { WebDataBinder binder = new WebRequestDataBinder(null); binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class); given(binderFactory.createBinder(webRequest, null, "name")).willReturn(binder); this.request.addParameter("name", ""); MethodParameter param = this.testMethod.annot(requestParam().notRequired()).arg(String.class); Object arg = resolver.resolveArgument(param, null, webRequest, binderFactory); assertNull(arg); } @Test public void resolveSimpleTypeParam() throws Exception { request.setParameter("stringNotAnnot", "plainValue"); MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertTrue(result instanceof String); assertEquals("plainValue", result); } @Test // SPR-8561 public void resolveSimpleTypeParamToNull() throws Exception { MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertNull(result); } @Test // SPR-10180 public void resolveEmptyValueToDefault() throws Exception { this.request.addParameter("name", ""); MethodParameter param = this.testMethod.annot(requestParam().notRequired("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", ""); MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertEquals("", result); } @Test public void resolveEmptyValueRequiredWithoutDefault() throws Exception { this.request.addParameter("name", ""); MethodParameter param = this.testMethod.annot(requestParam().notRequired()).arg(String.class); Object result = resolver.resolveArgument(param, null, webRequest, null); assertEquals("", result); } @Test @SuppressWarnings("rawtypes") public void resolveOptionalParamValue() throws Exception { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, Integer.class); Object result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.empty(), result); this.request.addParameter("name", "123"); result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.class, result.getClass()); assertEquals(123, ((Optional) result).get()); } @Test public void resolveOptionalMultipartFile() throws Exception { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes()); request.addFile(expected); webRequest = new ServletWebRequest(request); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, MultipartFile.class); Object result = resolver.resolveArgument(param, null, webRequest, binderFactory); assertTrue(result instanceof Optional); assertEquals("Invalid result", expected, ((Optional<?>) result).get()); } @Test public void missingOptionalMultipartFile() throws Exception { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); request.setMethod("POST"); request.setContentType("multipart/form-data"); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, MultipartFile.class); Object actual = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.empty(), actual); } @Test public void optionalMultipartFileWithoutMultipartRequest() throws Exception { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); initializer.setConversionService(new DefaultConversionService()); WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer); MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, MultipartFile.class); Object actual = resolver.resolveArgument(param, null, webRequest, binderFactory); assertEquals(Optional.empty(), actual); } @SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"}) public void handle( @RequestParam(name = "name", defaultValue = "bar") String param1, @RequestParam("name") String[] param2, @RequestParam("name") Map<?, ?> param3, @RequestParam("mfile") MultipartFile param4, @RequestParam("mfilelist") List<MultipartFile> param5, @RequestParam("mfilearray") MultipartFile[] param6, @RequestParam("pfile") Part param7, @RequestParam("pfilelist") List<Part> param8, @RequestParam("pfilearray") Part[] param9, @RequestParam Map<?, ?> param10, String stringNotAnnot, MultipartFile multipartFileNotAnnot, List<MultipartFile> multipartFileList, Part part, @RequestPart MultipartFile requestPartAnnot, @RequestParam("name") String paramRequired, @RequestParam(name = "name", required = false) String paramNotRequired, @RequestParam("name") Optional<Integer> paramOptional, @RequestParam("mfile") Optional<MultipartFile> multipartFileOptional) { } }