Consistent java.util.Optional resolution, lenient handling of optional multipart files, correct Servlet 3.0 Part list/array selection
Issue: SPR-13418 Issue: SPR-13849 Issue: SPR-13850 Issue: SPR-13893
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -37,6 +37,7 @@ 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;
|
||||
@@ -49,6 +50,7 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
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.*;
|
||||
@@ -82,22 +84,18 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
private MethodParameter paramRequired;
|
||||
private MethodParameter paramNotRequired;
|
||||
private MethodParameter paramOptional;
|
||||
private MethodParameter multipartFileOptional;
|
||||
|
||||
private NativeWebRequest webRequest;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resolver = new RequestParamMethodArgumentResolver(null, true);
|
||||
|
||||
ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
Method method = getClass().getMethod("params", String.class, String[].class,
|
||||
Map.class, MultipartFile.class, List.class, MultipartFile[].class,
|
||||
Part.class, List.class, Part[].class, Map.class,
|
||||
String.class, MultipartFile.class, List.class, Part.class,
|
||||
MultipartFile.class, String.class, String.class, Optional.class);
|
||||
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
|
||||
|
||||
paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 0);
|
||||
paramNamedStringArray = new SynthesizingMethodParameter(method, 1);
|
||||
@@ -121,27 +119,35 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
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("String parameter not supported", resolver.supportsParameter(paramNamedDefaultValueString));
|
||||
assertTrue("String array parameter not supported", resolver.supportsParameter(paramNamedStringArray));
|
||||
assertTrue("Named map not parameter supported", resolver.supportsParameter(paramNamedMap));
|
||||
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFile));
|
||||
assertTrue("List<MultipartFile> parameter not supported", resolver.supportsParameter(paramMultipartFileList));
|
||||
assertTrue("MultipartFile[] parameter not supported", resolver.supportsParameter(paramMultipartFileArray));
|
||||
assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart));
|
||||
assertTrue("List<Part> parameter not supported", resolver.supportsParameter(paramPartList));
|
||||
assertTrue("Part[] parameter not supported", resolver.supportsParameter(paramPartArray));
|
||||
assertFalse("non-@RequestParam parameter supported", resolver.supportsParameter(paramMap));
|
||||
assertTrue("Simple type params supported w/o annotations", resolver.supportsParameter(paramStringNotAnnot));
|
||||
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot));
|
||||
assertTrue("Part parameter not supported", resolver.supportsParameter(paramPartNotAnnot));
|
||||
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));
|
||||
|
||||
resolver = new RequestParamMethodArgumentResolver(null, false);
|
||||
assertFalse(resolver.supportsParameter(paramStringNotAnnot));
|
||||
@@ -154,18 +160,16 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
request.addParameter("name", expected);
|
||||
|
||||
Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof String);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveStringArray() throws Exception {
|
||||
String[] expected = new String[]{"foo", "bar"};
|
||||
String[] expected = new String[] {"foo", "bar"};
|
||||
request.addParameter("name", expected);
|
||||
|
||||
Object result = resolver.resolveArgument(paramNamedStringArray, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof String[]);
|
||||
assertArrayEquals("Invalid result", expected, (String[]) result);
|
||||
}
|
||||
@@ -178,7 +182,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof MultipartFile);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
}
|
||||
@@ -190,10 +193,10 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
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);
|
||||
|
||||
Object result = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof List);
|
||||
assertEquals(Arrays.asList(expected1, expected2), result);
|
||||
}
|
||||
@@ -205,12 +208,13 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
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);
|
||||
|
||||
Object result = resolver.resolveArgument(paramMultipartFileArray, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof MultipartFile[]);
|
||||
MultipartFile[] parts = (MultipartFile[]) result;
|
||||
assertEquals(2, parts.length);
|
||||
assertEquals(parts[0], expected1);
|
||||
assertEquals(parts[1], expected2);
|
||||
}
|
||||
@@ -225,7 +229,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramPart, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof Part);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
}
|
||||
@@ -233,16 +236,16 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void resolvePartList() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockPart expected1 = new MockPart("pfilelist", "Hello World 1".getBytes());
|
||||
MockPart expected2 = new MockPart("pfilelist", "Hello World 2".getBytes());
|
||||
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);
|
||||
|
||||
Object result = resolver.resolveArgument(paramPartList, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof List);
|
||||
assertEquals(Arrays.asList(expected1, expected2), result);
|
||||
}
|
||||
@@ -256,12 +259,13 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
request.setContentType("multipart/form-data");
|
||||
request.addPart(expected1);
|
||||
request.addPart(expected2);
|
||||
request.addPart(new MockPart("other", "Hello World 3".getBytes()));
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof Part[]);
|
||||
Part[] parts = (Part[]) result;
|
||||
assertEquals(2, parts.length);
|
||||
assertEquals(parts[0], expected1);
|
||||
assertEquals(parts[1], expected2);
|
||||
}
|
||||
@@ -274,7 +278,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramMultipartFileNotAnnot, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof MultipartFile);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
}
|
||||
@@ -289,7 +292,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof List);
|
||||
assertEquals(Arrays.asList(expected1, expected2), result);
|
||||
}
|
||||
@@ -300,9 +302,7 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
fail("Expected exception: request is not a multipart request");
|
||||
}
|
||||
|
||||
// SPR-9079
|
||||
|
||||
@Test
|
||||
@Test // SPR-9079
|
||||
public void isMultipartRequestHttpPut() throws Exception {
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
MultipartFile expected = new MockMultipartFile("multipartFileList", "Hello World".getBytes());
|
||||
@@ -311,17 +311,23 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object actual = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null);
|
||||
|
||||
assertTrue(actual instanceof List);
|
||||
assertEquals(expected, ((List<?>) actual).get(0));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test(expected = MultipartException.class)
|
||||
public void noMultipartContent() throws Exception {
|
||||
request.setMethod("POST");
|
||||
resolver.resolveArgument(paramMultipartFile, 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");
|
||||
resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
|
||||
fail("Expected exception: request is not MultiPartHttpServletRequest but param is MultipartFile");
|
||||
fail("Expected exception: no such part found");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -334,7 +340,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(paramPartNotAnnot, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof Part);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
}
|
||||
@@ -342,7 +347,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void resolveDefaultValue() throws Exception {
|
||||
Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
|
||||
|
||||
assertTrue(result instanceof String);
|
||||
assertEquals("Invalid result", "bar", result);
|
||||
}
|
||||
@@ -353,11 +357,8 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
fail("Expected exception");
|
||||
}
|
||||
|
||||
// SPR-10578
|
||||
|
||||
@Test
|
||||
@Test // SPR-10578
|
||||
public void missingRequestParamEmptyValueConvertedToNull() throws Exception {
|
||||
|
||||
WebDataBinder binder = new WebRequestDataBinder(null);
|
||||
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
|
||||
|
||||
@@ -367,13 +368,11 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
this.request.addParameter("stringNotAnnot", "");
|
||||
|
||||
Object arg = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
|
||||
|
||||
assertNull(arg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingRequestParamEmptyValueNotRequired() throws Exception {
|
||||
|
||||
WebDataBinder binder = new WebRequestDataBinder(null);
|
||||
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
|
||||
|
||||
@@ -383,7 +382,6 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
this.request.addParameter("name", "");
|
||||
|
||||
Object arg = resolver.resolveArgument(paramNotRequired, null, webRequest, binderFactory);
|
||||
|
||||
assertNull(arg);
|
||||
}
|
||||
|
||||
@@ -396,17 +394,13 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
assertEquals("plainValue", result);
|
||||
}
|
||||
|
||||
// SPR-8561
|
||||
|
||||
@Test
|
||||
@Test // SPR-8561
|
||||
public void resolveSimpleTypeParamToNull() throws Exception {
|
||||
Object result = resolver.resolveArgument(paramStringNotAnnot, null, webRequest, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
// SPR-10180
|
||||
|
||||
@Test
|
||||
@Test // SPR-10180
|
||||
public void resolveEmptyValueToDefault() throws Exception {
|
||||
this.request.addParameter("name", "");
|
||||
Object result = resolver.resolveArgument(paramNamedDefaultValueString, null, webRequest, null);
|
||||
@@ -429,13 +423,12 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void resolveOptional() throws Exception {
|
||||
public void resolveOptionalParamValue() throws Exception {
|
||||
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
|
||||
initializer.setConversionService(new DefaultConversionService());
|
||||
WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
|
||||
|
||||
Object result = resolver.resolveArgument(paramOptional, null, webRequest, binderFactory);
|
||||
assertEquals(Optional.class, result.getClass());
|
||||
assertEquals(Optional.empty(), result);
|
||||
|
||||
this.request.addParameter("name", "123");
|
||||
@@ -444,8 +437,46 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
assertEquals(123, ((Optional) result).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveOptionalMultipartFile() throws Exception {
|
||||
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
|
||||
initializer.setConversionService(new DefaultConversionService());
|
||||
WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
|
||||
|
||||
public void params(@RequestParam(name = "name", defaultValue = "bar") String param1,
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes());
|
||||
request.addFile(expected);
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
Object result = resolver.resolveArgument(multipartFileOptional, 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");
|
||||
assertEquals(Optional.empty(), resolver.resolveArgument(multipartFileOptional, null, webRequest, binderFactory));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionalMultipartFileWithoutMultipartRequest() throws Exception {
|
||||
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
|
||||
initializer.setConversionService(new DefaultConversionService());
|
||||
WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
|
||||
|
||||
assertEquals(Optional.empty(), resolver.resolveArgument(multipartFileOptional, null, webRequest, binderFactory));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void handle(
|
||||
@RequestParam(name = "name", defaultValue = "bar") String param1,
|
||||
@RequestParam("name") String[] param2,
|
||||
@RequestParam("name") Map<?, ?> param3,
|
||||
@RequestParam("mfile") MultipartFile param4,
|
||||
@@ -462,7 +493,8 @@ public class RequestParamMethodArgumentResolverTests {
|
||||
@RequestPart MultipartFile requestPartAnnot,
|
||||
@RequestParam("name") String paramRequired,
|
||||
@RequestParam(name = "name", required = false) String paramNotRequired,
|
||||
@RequestParam("name") Optional<Integer> paramOptional) {
|
||||
@RequestParam("name") Optional<Integer> paramOptional,
|
||||
@RequestParam("mfile") Optional<MultipartFile> multipartFileOptional) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user