Skip to content

Commit 803779d

Browse files
committed
Support List<Part> method arguments
Issue: SPR-10591
1 parent 481aeee commit 803779d

File tree

4 files changed

+82
-27
lines changed

4 files changed

+82
-27
lines changed

spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.web.method.annotation;
1818

1919
import java.beans.PropertyEditor;
20+
import java.util.ArrayList;
2021
import java.util.Collection;
2122
import java.util.List;
2223
import java.util.Map;
@@ -161,6 +162,10 @@ else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName()
161162
assertIsMultipartRequest(servletRequest);
162163
arg = servletRequest.getPart(name);
163164
}
165+
else if (isPartCollection(parameter)) {
166+
assertIsMultipartRequest(servletRequest);
167+
arg = new ArrayList(servletRequest.getParts());
168+
}
164169
else {
165170
arg = null;
166171
if (multipartRequest != null) {
@@ -188,14 +193,24 @@ private void assertIsMultipartRequest(HttpServletRequest request) {
188193
}
189194

190195
private boolean isMultipartFileCollection(MethodParameter parameter) {
196+
Class<?> collectionType = getCollectionParameterType(parameter);
197+
return ((collectionType != null) && collectionType.equals(MultipartFile.class));
198+
}
199+
200+
private boolean isPartCollection(MethodParameter parameter) {
201+
Class<?> collectionType = getCollectionParameterType(parameter);
202+
return ((collectionType != null) && "javax.servlet.http.Part".equals(collectionType.getName()));
203+
}
204+
205+
private Class<?> getCollectionParameterType(MethodParameter parameter) {
191206
Class<?> paramType = parameter.getParameterType();
192207
if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
193208
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
194-
if (valueType != null && valueType.equals(MultipartFile.class)) {
195-
return true;
209+
if (valueType != null) {
210+
return valueType;
196211
}
197212
}
198-
return false;
213+
return null;
199214
}
200215

201216
@Override

spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class RequestParamMethodArgumentResolverTests {
6868
private MethodParameter paramStringNotAnnot;
6969
private MethodParameter paramMultipartFileNotAnnot;
7070
private MethodParameter paramMultipartFileList;
71-
private MethodParameter paramServlet30Part;
71+
private MethodParameter paramPart;
7272
private MethodParameter paramRequestPartAnnot;
7373
private MethodParameter paramRequired;
7474
private MethodParameter paramNotRequired;
@@ -99,8 +99,8 @@ public void setUp() throws Exception {
9999
paramMultipartFileNotAnnot.initParameterNameDiscovery(paramNameDiscoverer);
100100
paramMultipartFileList = new MethodParameter(method, 7);
101101
paramMultipartFileList.initParameterNameDiscovery(paramNameDiscoverer);
102-
paramServlet30Part = new MethodParameter(method, 8);
103-
paramServlet30Part.initParameterNameDiscovery(paramNameDiscoverer);
102+
paramPart = new MethodParameter(method, 8);
103+
paramPart.initParameterNameDiscovery(paramNameDiscoverer);
104104
paramRequestPartAnnot = new MethodParameter(method, 9);
105105
paramRequired = new MethodParameter(method, 10);
106106
paramNotRequired = new MethodParameter(method, 11);
@@ -119,7 +119,7 @@ public void supportsParameter() {
119119
assertFalse("non-@RequestParam parameter supported", resolver.supportsParameter(paramMap));
120120
assertTrue("Simple type params supported w/o annotations", resolver.supportsParameter(paramStringNotAnnot));
121121
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot));
122-
assertTrue("Part parameter not supported", resolver.supportsParameter(paramServlet30Part));
122+
assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart));
123123

124124
resolver = new RequestParamMethodArgumentResolver(null, false);
125125
assertFalse(resolver.supportsParameter(paramStringNotAnnot));
@@ -220,15 +220,15 @@ public void missingMultipartFile() throws Exception {
220220
}
221221

222222
@Test
223-
public void resolveServlet30Part() throws Exception {
224-
MockPart expected = new MockPart("servlet30Part", "Hello World".getBytes());
223+
public void resolvePart() throws Exception {
224+
MockPart expected = new MockPart("part", "Hello World".getBytes());
225225
MockHttpServletRequest request = new MockHttpServletRequest();
226226
request.setMethod("POST");
227227
request.setContentType("multipart/form-data");
228228
request.addPart(expected);
229229
webRequest = new ServletWebRequest(request);
230230

231-
Object result = resolver.resolveArgument(paramServlet30Part, null, webRequest, null);
231+
Object result = resolver.resolveArgument(paramPart, null, webRequest, null);
232232

233233
assertTrue(result instanceof Part);
234234
assertEquals("Invalid result", expected, result);
@@ -331,7 +331,7 @@ public void params(@RequestParam(value = "name", defaultValue = "bar") String pa
331331
String stringNotAnnot,
332332
MultipartFile multipartFileNotAnnot,
333333
List<MultipartFile> multipartFileList,
334-
Part servlet30Part,
334+
Part part,
335335
@RequestPart MultipartFile requestPartAnnot,
336336
@RequestParam(value = "name") String paramRequired,
337337
@RequestParam(value = "name", required=false) String paramNotRequired) {

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
1717
package org.springframework.web.servlet.mvc.method.annotation;
1818

1919
import java.lang.annotation.Annotation;
20+
import java.util.ArrayList;
2021
import java.util.Collection;
2122
import java.util.List;
23+
2224
import javax.servlet.http.HttpServletRequest;
2325

2426
import org.springframework.core.GenericCollectionTypeResolver;
@@ -130,8 +132,13 @@ else if (isMultipartFileCollection(parameter)) {
130132
arg = multipartRequest.getFiles(partName);
131133
}
132134
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
135+
assertIsMultipartRequest(servletRequest);
133136
arg = servletRequest.getPart(partName);
134137
}
138+
else if (isPartCollection(parameter)) {
139+
assertIsMultipartRequest(servletRequest);
140+
arg = new ArrayList(servletRequest.getParts());
141+
}
135142
else {
136143
try {
137144
HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, partName);
@@ -177,14 +184,24 @@ private String getPartName(MethodParameter parameter) {
177184
}
178185

179186
private boolean isMultipartFileCollection(MethodParameter parameter) {
187+
Class<?> collectionType = getCollectionParameterType(parameter);
188+
return ((collectionType != null) && collectionType.equals(MultipartFile.class));
189+
}
190+
191+
private boolean isPartCollection(MethodParameter parameter) {
192+
Class<?> collectionType = getCollectionParameterType(parameter);
193+
return ((collectionType != null) && "javax.servlet.http.Part".equals(collectionType.getName()));
194+
}
195+
196+
private Class<?> getCollectionParameterType(MethodParameter parameter) {
180197
Class<?> paramType = parameter.getParameterType();
181198
if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
182199
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
183-
if (valueType != null && valueType.equals(MultipartFile.class)) {
184-
return true;
200+
if (valueType != null) {
201+
return valueType;
185202
}
186203
}
187-
return false;
204+
return null;
188205
}
189206

190207
private void validate(WebDataBinder binder, MethodParameter parameter) throws MethodArgumentNotValidException {

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353

5454
import static org.junit.Assert.*;
5555
import static org.mockito.BDDMockito.*;
56+
import static org.mockito.Matchers.*;
57+
import static org.mockito.Mockito.*;
5658

5759
/**
5860
* Test fixture with {@link RequestPartMethodArgumentResolver} and mock {@link HttpMessageConverter}.
@@ -75,7 +77,8 @@ public class RequestPartMethodArgumentResolverTests {
7577
private MethodParameter paramMultipartFileList;
7678
private MethodParameter paramInt;
7779
private MethodParameter paramMultipartFileNotAnnot;
78-
private MethodParameter paramServlet30Part;
80+
private MethodParameter paramPart;
81+
private MethodParameter paramPartList;
7982
private MethodParameter paramRequestParamAnnot;
8083

8184
private NativeWebRequest webRequest;
@@ -88,8 +91,9 @@ public class RequestPartMethodArgumentResolverTests {
8891
@Before
8992
public void setUp() throws Exception {
9093

91-
Method method = getClass().getMethod("handle", SimpleBean.class, SimpleBean.class, SimpleBean.class,
92-
MultipartFile.class, List.class, Integer.TYPE, MultipartFile.class, Part.class, MultipartFile.class);
94+
Method method = getClass().getMethod("handle", SimpleBean.class, SimpleBean.class,
95+
SimpleBean.class, MultipartFile.class, List.class, Integer.TYPE,
96+
MultipartFile.class, Part.class, List.class, MultipartFile.class);
9397

9498
paramRequestPart = new MethodParameter(method, 0);
9599
paramRequestPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
@@ -100,9 +104,10 @@ public void setUp() throws Exception {
100104
paramInt = new MethodParameter(method, 5);
101105
paramMultipartFileNotAnnot = new MethodParameter(method, 6);
102106
paramMultipartFileNotAnnot.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
103-
paramServlet30Part = new MethodParameter(method, 7);
104-
paramServlet30Part.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
105-
paramRequestParamAnnot = new MethodParameter(method, 8);
107+
paramPart = new MethodParameter(method, 7);
108+
paramPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
109+
paramPartList = new MethodParameter(method, 8);
110+
paramRequestParamAnnot = new MethodParameter(method, 9);
106111

107112
messageConverter = mock(HttpMessageConverter.class);
108113
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
@@ -123,7 +128,7 @@ public void setUp() throws Exception {
123128
public void supportsParameter() {
124129
assertTrue("RequestPart parameter not supported", resolver.supportsParameter(paramRequestPart));
125130
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot));
126-
assertTrue("Part parameter not supported", resolver.supportsParameter(paramServlet30Part));
131+
assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart));
127132
assertFalse("non-RequestPart parameter supported", resolver.supportsParameter(paramInt));
128133
assertFalse("@RequestParam args not supported", resolver.supportsParameter(paramRequestParamAnnot));
129134
}
@@ -157,20 +162,37 @@ public void resolveMultipartFileNotAnnotArgument() throws Exception {
157162
}
158163

159164
@Test
160-
public void resolveServlet30PartArgument() throws Exception {
161-
MockPart expected = new MockPart("servlet30Part", "Hello World".getBytes());
165+
public void resolvePartArgument() throws Exception {
166+
MockPart expected = new MockPart("part", "Hello World".getBytes());
162167
MockHttpServletRequest request = new MockHttpServletRequest();
163168
request.setMethod("POST");
164169
request.setContentType("multipart/form-data");
165170
request.addPart(expected);
166171
webRequest = new ServletWebRequest(request);
167172

168-
Object result = resolver.resolveArgument(paramServlet30Part, null, webRequest, null);
173+
Object result = resolver.resolveArgument(paramPart, null, webRequest, null);
169174

170175
assertTrue(result instanceof Part);
171176
assertEquals("Invalid result", expected, result);
172177
}
173178

179+
@Test
180+
public void resolvePartListArgument() throws Exception {
181+
MockPart part1 = new MockPart("requestPart1", "Hello World 1".getBytes());
182+
MockPart part2 = new MockPart("requestPart2", "Hello World 2".getBytes());
183+
MockHttpServletRequest request = new MockHttpServletRequest();
184+
request.setMethod("POST");
185+
request.setContentType("multipart/form-data");
186+
request.addPart(part1);
187+
request.addPart(part2);
188+
webRequest = new ServletWebRequest(request);
189+
190+
Object result = resolver.resolveArgument(paramPartList, null, webRequest, null);
191+
192+
assertTrue(result instanceof List);
193+
assertEquals(Arrays.asList(part1, part2), result);
194+
}
195+
174196
@Test
175197
public void resolveRequestPart() throws Exception {
176198
testResolveArgument(new SimpleBean("foo"), paramRequestPart);
@@ -276,7 +298,8 @@ public void handle(@RequestPart SimpleBean requestPart,
276298
@RequestPart("requestPart") List<MultipartFile> multipartFileList,
277299
int i,
278300
MultipartFile multipartFileNotAnnot,
279-
Part servlet30Part,
301+
Part part,
302+
@RequestPart("requestPart") List<Part> partList,
280303
@RequestParam MultipartFile requestParamAnnot) {
281304
}
282305

0 commit comments

Comments
 (0)