View Javadoc
1   /*
2    * Copyright 2002-2014 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  
17  package org.springframework.web.method.annotation;
18  
19  import java.lang.reflect.Method;
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Optional;
24  import javax.servlet.http.Part;
25  
26  import org.junit.Before;
27  import org.junit.Test;
28  
29  import org.springframework.beans.propertyeditors.StringTrimmerEditor;
30  import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
31  import org.springframework.core.MethodParameter;
32  import org.springframework.core.ParameterNameDiscoverer;
33  import org.springframework.core.convert.support.DefaultConversionService;
34  import org.springframework.mock.web.test.MockHttpServletRequest;
35  import org.springframework.mock.web.test.MockHttpServletResponse;
36  import org.springframework.mock.web.test.MockMultipartFile;
37  import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
38  import org.springframework.mock.web.test.MockPart;
39  import org.springframework.web.bind.MissingServletRequestParameterException;
40  import org.springframework.web.bind.WebDataBinder;
41  import org.springframework.web.bind.annotation.RequestParam;
42  import org.springframework.web.bind.annotation.RequestPart;
43  import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
44  import org.springframework.web.bind.support.DefaultDataBinderFactory;
45  import org.springframework.web.bind.support.WebDataBinderFactory;
46  import org.springframework.web.bind.support.WebRequestDataBinder;
47  import org.springframework.web.context.request.NativeWebRequest;
48  import org.springframework.web.context.request.ServletWebRequest;
49  import org.springframework.web.multipart.MultipartException;
50  import org.springframework.web.multipart.MultipartFile;
51  
52  import static org.junit.Assert.*;
53  import static org.mockito.BDDMockito.*;
54  
55  /**
56   * Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
57   *
58   * @author Arjen Poutsma
59   * @author Rossen Stoyanchev
60   * @author Brian Clozel
61   */
62  public class RequestParamMethodArgumentResolverTests {
63  
64  	private RequestParamMethodArgumentResolver resolver;
65  
66  	private MethodParameter paramNamedDefaultValueString;
67  	private MethodParameter paramNamedStringArray;
68  	private MethodParameter paramNamedMap;
69  	private MethodParameter paramMultipartFile;
70  	private MethodParameter paramMultipartFileList;
71  	private MethodParameter paramMultipartFileArray;
72  	private MethodParameter paramPart;
73  	private MethodParameter paramPartList;
74  	private MethodParameter paramPartArray;
75  	private MethodParameter paramMap;
76  	private MethodParameter paramStringNotAnnot;
77  	private MethodParameter paramMultipartFileNotAnnot;
78  	private MethodParameter paramMultipartFileListNotAnnot;
79  	private MethodParameter paramPartNotAnnot;
80  	private MethodParameter paramRequestPartAnnot;
81  	private MethodParameter paramRequired;
82  	private MethodParameter paramNotRequired;
83  	private MethodParameter paramOptional;
84  
85  	private NativeWebRequest webRequest;
86  
87  	private MockHttpServletRequest request;
88  
89  	@Before
90  	public void setUp() throws Exception {
91  		resolver = new RequestParamMethodArgumentResolver(null, true);
92  
93  		ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
94  
95  		Method method = getClass().getMethod("params", String.class, String[].class,
96  				Map.class, MultipartFile.class, List.class, MultipartFile[].class,
97  				Part.class, List.class, Part[].class, Map.class,
98  				String.class, MultipartFile.class, List.class, Part.class,
99  				MultipartFile.class, String.class, String.class, Optional.class);
100 
101 		paramNamedDefaultValueString = new MethodParameter(method, 0);
102 		paramNamedStringArray = new MethodParameter(method, 1);
103 		paramNamedMap = new MethodParameter(method, 2);
104 		paramMultipartFile = new MethodParameter(method, 3);
105 		paramMultipartFileList = new MethodParameter(method, 4);
106 		paramMultipartFileArray = new MethodParameter(method, 5);
107 		paramPart = new MethodParameter(method, 6);
108 		paramPartList  = new MethodParameter(method, 7);
109 		paramPartArray  = new MethodParameter(method, 8);
110 		paramMap = new MethodParameter(method, 9);
111 		paramStringNotAnnot = new MethodParameter(method, 10);
112 		paramStringNotAnnot.initParameterNameDiscovery(paramNameDiscoverer);
113 		paramMultipartFileNotAnnot = new MethodParameter(method, 11);
114 		paramMultipartFileNotAnnot.initParameterNameDiscovery(paramNameDiscoverer);
115 		paramMultipartFileListNotAnnot = new MethodParameter(method, 12);
116 		paramMultipartFileListNotAnnot.initParameterNameDiscovery(paramNameDiscoverer);
117 		paramPartNotAnnot = new MethodParameter(method, 13);
118 		paramPartNotAnnot.initParameterNameDiscovery(paramNameDiscoverer);
119 		paramRequestPartAnnot = new MethodParameter(method, 14);
120 		paramRequired = new MethodParameter(method, 15);
121 		paramNotRequired = new MethodParameter(method, 16);
122 		paramOptional = new MethodParameter(method, 17);
123 
124 		request = new MockHttpServletRequest();
125 		webRequest = new ServletWebRequest(request, new MockHttpServletResponse());
126 	}
127 
128 	@Test
129 	public void supportsParameter() {
130 		resolver = new RequestParamMethodArgumentResolver(null, true);
131 		assertTrue("String parameter not supported", resolver.supportsParameter(paramNamedDefaultValueString));
132 		assertTrue("String array parameter not supported", resolver.supportsParameter(paramNamedStringArray));
133 		assertTrue("Named map not parameter supported", resolver.supportsParameter(paramNamedMap));
134 		assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFile));
135 		assertTrue("List<MultipartFile> parameter not supported", resolver.supportsParameter(paramMultipartFileList));
136 		assertTrue("MultipartFile[] parameter not supported", resolver.supportsParameter(paramMultipartFileArray));
137 		assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart));
138 		assertTrue("List<Part> parameter not supported", resolver.supportsParameter(paramPartList));
139 		assertTrue("Part[] parameter not supported", resolver.supportsParameter(paramPartArray));
140 		assertFalse("non-@RequestParam parameter supported", resolver.supportsParameter(paramMap));
141 		assertTrue("Simple type params supported w/o annotations", resolver.supportsParameter(paramStringNotAnnot));
142 		assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot));
143 		assertTrue("Part parameter not supported", resolver.supportsParameter(paramPartNotAnnot));
144 
145 		resolver = new RequestParamMethodArgumentResolver(null, false);
146 		assertFalse(resolver.supportsParameter(paramStringNotAnnot));
147 		assertFalse(resolver.supportsParameter(paramRequestPartAnnot));
148 	}
149 
150 	@Test
151 	public void resolveString() throws Exception {
152 		String expected = "foo";
153 		request.addParameter("name", expected);
154 
155 		Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
156 
157 		assertTrue(result instanceof String);
158 		assertEquals("Invalid result", expected, result);
159 	}
160 
161 	@Test
162 	public void resolveStringArray() throws Exception {
163 		String[] expected = new String[]{"foo", "bar"};
164 		request.addParameter("name", expected);
165 
166 		Object result = resolver.resolveArgument(paramNamedStringArray, null, webRequest, null);
167 
168 		assertTrue(result instanceof String[]);
169 		assertArrayEquals("Invalid result", expected, (String[]) result);
170 	}
171 
172 	@Test
173 	public void resolveMultipartFile() throws Exception {
174 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
175 		MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes());
176 		request.addFile(expected);
177 		webRequest = new ServletWebRequest(request);
178 
179 		Object result = resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
180 
181 		assertTrue(result instanceof MultipartFile);
182 		assertEquals("Invalid result", expected, result);
183 	}
184 
185 	@Test
186 	public void resolveMultipartFileList() throws Exception {
187 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
188 		MultipartFile expected1 = new MockMultipartFile("mfilelist", "Hello World 1".getBytes());
189 		MultipartFile expected2 = new MockMultipartFile("mfilelist", "Hello World 2".getBytes());
190 		request.addFile(expected1);
191 		request.addFile(expected2);
192 		webRequest = new ServletWebRequest(request);
193 
194 		Object result = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null);
195 
196 		assertTrue(result instanceof List);
197 		assertEquals(Arrays.asList(expected1, expected2), result);
198 	}
199 
200 	@Test
201 	public void resolveMultipartFileArray() throws Exception {
202 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
203 		MultipartFile expected1 = new MockMultipartFile("mfilearray", "Hello World 1".getBytes());
204 		MultipartFile expected2 = new MockMultipartFile("mfilearray", "Hello World 2".getBytes());
205 		request.addFile(expected1);
206 		request.addFile(expected2);
207 		webRequest = new ServletWebRequest(request);
208 
209 		Object result = resolver.resolveArgument(paramMultipartFileArray, null, webRequest, null);
210 
211 		assertTrue(result instanceof MultipartFile[]);
212 		MultipartFile[] parts = (MultipartFile[]) result;
213 		assertEquals(parts[0], expected1);
214 		assertEquals(parts[1], expected2);
215 	}
216 
217 	@Test
218 	public void resolvePart() throws Exception {
219 		MockHttpServletRequest request = new MockHttpServletRequest();
220 		MockPart expected = new MockPart("pfile", "Hello World".getBytes());
221 		request.setMethod("POST");
222 		request.setContentType("multipart/form-data");
223 		request.addPart(expected);
224 		webRequest = new ServletWebRequest(request);
225 
226 		Object result = resolver.resolveArgument(paramPart, null, webRequest, null);
227 
228 		assertTrue(result instanceof Part);
229 		assertEquals("Invalid result", expected, result);
230 	}
231 
232 	@Test
233 	public void resolvePartList() throws Exception {
234 		MockHttpServletRequest request = new MockHttpServletRequest();
235 		MockPart expected1 = new MockPart("pfilelist", "Hello World 1".getBytes());
236 		MockPart expected2 = new MockPart("pfilelist", "Hello World 2".getBytes());
237 		request.setMethod("POST");
238 		request.setContentType("multipart/form-data");
239 		request.addPart(expected1);
240 		request.addPart(expected2);
241 		webRequest = new ServletWebRequest(request);
242 
243 		Object result = resolver.resolveArgument(paramPartList, null, webRequest, null);
244 
245 		assertTrue(result instanceof List);
246 		assertEquals(Arrays.asList(expected1, expected2), result);
247 	}
248 
249 	@Test
250 	public void resolvePartArray() throws Exception {
251 		MockHttpServletRequest request = new MockHttpServletRequest();
252 		MockPart expected1 = new MockPart("pfilearray", "Hello World 1".getBytes());
253 		MockPart expected2 = new MockPart("pfilearray", "Hello World 2".getBytes());
254 		request.setMethod("POST");
255 		request.setContentType("multipart/form-data");
256 		request.addPart(expected1);
257 		request.addPart(expected2);
258 		webRequest = new ServletWebRequest(request);
259 
260 		Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null);
261 
262 		assertTrue(result instanceof Part[]);
263 		Part[] parts = (Part[]) result;
264 		assertEquals(parts[0], expected1);
265 		assertEquals(parts[1], expected2);
266 	}
267 
268 	@Test
269 	public void resolveMultipartFileNotAnnot() throws Exception {
270 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
271 		MultipartFile expected = new MockMultipartFile("multipartFileNotAnnot", "Hello World".getBytes());
272 		request.addFile(expected);
273 		webRequest = new ServletWebRequest(request);
274 
275 		Object result = resolver.resolveArgument(paramMultipartFileNotAnnot, null, webRequest, null);
276 
277 		assertTrue(result instanceof MultipartFile);
278 		assertEquals("Invalid result", expected, result);
279 	}
280 
281 	@Test
282 	public void resolveMultipartFileListNotAnnotated() throws Exception {
283 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
284 		MultipartFile expected1 = new MockMultipartFile("multipartFileList", "Hello World 1".getBytes());
285 		MultipartFile expected2 = new MockMultipartFile("multipartFileList", "Hello World 2".getBytes());
286 		request.addFile(expected1);
287 		request.addFile(expected2);
288 		webRequest = new ServletWebRequest(request);
289 
290 		Object result = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null);
291 
292 		assertTrue(result instanceof List);
293 		assertEquals(Arrays.asList(expected1, expected2), result);
294 	}
295 
296 	@Test(expected = MultipartException.class)
297 	public void isMultipartRequest() throws Exception {
298 		resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
299 		fail("Expected exception: request is not a multipart request");
300 	}
301 
302 	// SPR-9079
303 
304 	@Test
305 	public void isMultipartRequestHttpPut() throws Exception {
306 		MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
307 		MultipartFile expected = new MockMultipartFile("multipartFileList", "Hello World".getBytes());
308 		request.addFile(expected);
309 		request.setMethod("PUT");
310 		webRequest = new ServletWebRequest(request);
311 
312 		Object actual = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null);
313 
314 		assertTrue(actual instanceof List);
315 		assertEquals(expected, ((List<?>) actual).get(0));
316 	}
317 
318 	@Test(expected = IllegalArgumentException.class)
319 	public void missingMultipartFile() throws Exception {
320 		request.setMethod("POST");
321 		request.setContentType("multipart/form-data");
322 		resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
323 		fail("Expected exception: request is not MultiPartHttpServletRequest but param is MultipartFile");
324 	}
325 
326 	@Test
327 	public void resolvePartNotAnnot() throws Exception {
328 		MockPart expected = new MockPart("part", "Hello World".getBytes());
329 		MockHttpServletRequest request = new MockHttpServletRequest();
330 		request.setMethod("POST");
331 		request.setContentType("multipart/form-data");
332 		request.addPart(expected);
333 		webRequest = new ServletWebRequest(request);
334 
335 		Object result = resolver.resolveArgument(paramPartNotAnnot, null, webRequest, null);
336 
337 		assertTrue(result instanceof Part);
338 		assertEquals("Invalid result", expected, result);
339 	}
340 
341 	@Test
342 	public void resolveDefaultValue() throws Exception {
343 		Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
344 
345 		assertTrue(result instanceof String);
346 		assertEquals("Invalid result", "bar", result);
347 	}
348 
349 	@Test(expected = MissingServletRequestParameterException.class)
350 	public void missingRequestParam() throws Exception {
351 		resolver.resolveArgument(paramNamedStringArray, null, webRequest, null);
352 		fail("Expected exception");
353 	}
354 
355 	// SPR-10578
356 
357 	@Test
358 	public void missingRequestParamEmptyValueConvertedToNull() throws Exception {
359 
360 		WebDataBinder binder = new WebRequestDataBinder(null);
361 		binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
362 
363 		WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
364 		given(binderFactory.createBinder(webRequest, null, "stringNotAnnot")).willReturn(binder);
365 
366 		this.request.addParameter("stringNotAnnot", "");
367 
368 		Object arg = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
369 
370 		assertNull(arg);
371 	}
372 
373 	@Test
374 	public void missingRequestParamEmptyValueNotRequired() throws Exception {
375 
376 		WebDataBinder binder = new WebRequestDataBinder(null);
377 		binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
378 
379 		WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
380 		given(binderFactory.createBinder(webRequest, null, "name")).willReturn(binder);
381 
382 		this.request.addParameter("name", "");
383 
384 		Object arg = resolver.resolveArgument(paramNotRequired, null, webRequest, binderFactory);
385 
386 		assertNull(arg);
387 	}
388 
389 	@Test
390 	public void resolveSimpleTypeParam() throws Exception {
391 		request.setParameter("stringNotAnnot", "plainValue");
392 		Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null);
393 
394 		assertTrue(result instanceof String);
395 		assertEquals("plainValue", result);
396 	}
397 
398 	// SPR-8561
399 
400 	@Test
401 	public void resolveSimpleTypeParamToNull() throws Exception {
402 		Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null);
403 		assertNull(result);
404 	}
405 
406 	// SPR-10180
407 
408 	@Test
409 	public void resolveEmptyValueToDefault() throws Exception {
410 		this.request.addParameter("name", "");
411 		Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
412 		assertEquals("bar", result);
413 	}
414 
415 	@Test
416 	public void resolveEmptyValueWithoutDefault() throws Exception {
417 		this.request.addParameter("stringNotAnnot", "");
418 		Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null);
419 		assertEquals("", result);
420 	}
421 
422 	@Test
423 	public void resolveEmptyValueRequiredWithoutDefault() throws Exception {
424 		this.request.addParameter("name", "");
425 		Object result = resolver.resolveArgument(paramRequired, null, webRequest, null);
426 		assertEquals("", result);
427 	}
428 
429 	@Test
430 	public void resolveOptional() throws Exception {
431 		ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
432 		initializer.setConversionService(new DefaultConversionService());
433 		WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
434 
435 		Object result = resolver.resolveArgument(paramOptional, null, webRequest, binderFactory);
436 		assertEquals(Optional.class, result.getClass());
437 		assertEquals(Optional.empty(), result);
438 
439 		this.request.addParameter("name", "123");
440 		result = resolver.resolveArgument(paramOptional, null, webRequest, binderFactory);
441 		assertEquals(Optional.class, result.getClass());
442 		assertEquals(123, ((Optional) result).get());
443 	}
444 
445 
446 	public void params(@RequestParam(value = "name", defaultValue = "bar") String param1,
447 			@RequestParam("name") String[] param2,
448 			@RequestParam("name") Map<?, ?> param3,
449 			@RequestParam(value = "mfile") MultipartFile param4,
450 			@RequestParam(value = "mfilelist") List<MultipartFile> param5,
451 			@RequestParam(value = "mfilearray") MultipartFile[] param6,
452 			@RequestParam(value = "pfile") Part param7,
453 			@RequestParam(value = "pfilelist") List<Part> param8,
454 			@RequestParam(value = "pfilearray") Part[] param9,
455 			@RequestParam Map<?, ?> param10,
456 			String stringNotAnnot,
457 			MultipartFile multipartFileNotAnnot,
458 			List<MultipartFile> multipartFileList,
459 			Part part,
460 			@RequestPart MultipartFile requestPartAnnot,
461 			@RequestParam(value = "name") String paramRequired,
462 			@RequestParam(value = "name", required=false) String paramNotRequired,
463 			@RequestParam(value = "name") Optional<Integer> paramOptional) {
464 	}
465 
466 }