diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java index 3b49c17743..619252bf7f 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -69,6 +70,7 @@ import org.springframework.web.util.WebUtils; * * @author Arjen Poutsma * @author Rossen Stoyanchev + * @author Brian Clozel * @since 3.1 * @see RequestParamMapMethodArgumentResolver */ @@ -174,6 +176,11 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?"); arg = multipartRequest.getFiles(name); } + else if(isMultipartFileArray(parameter)) { + assertIsMultipartRequest(servletRequest); + Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?"); + arg = multipartRequest.getFiles(name).toArray(new MultipartFile[0]); + } else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) { assertIsMultipartRequest(servletRequest); arg = servletRequest.getPart(name); @@ -182,6 +189,10 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod assertIsMultipartRequest(servletRequest); arg = new ArrayList(servletRequest.getParts()); } + else if (isPartArray(parameter)) { + assertIsMultipartRequest(servletRequest); + arg = RequestPartResolver.resolvePart(servletRequest); + } else { arg = null; if (multipartRequest != null) { @@ -218,6 +229,16 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod return ((collectionType != null) && "javax.servlet.http.Part".equals(collectionType.getName())); } + private boolean isPartArray(MethodParameter parameter) { + Class paramType = parameter.getParameterType().getComponentType(); + return ((paramType != null) && "javax.servlet.http.Part".equals(paramType.getName())); + } + + private boolean isMultipartFileArray(MethodParameter parameter) { + Class paramType = parameter.getParameterType().getComponentType(); + return ((paramType != null) && MultipartFile.class.equals(paramType)); + } + private Class getCollectionParameterType(MethodParameter parameter) { Class paramType = parameter.getParameterType(); if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){ @@ -277,4 +298,11 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod } } + private static class RequestPartResolver { + + public static Object resolvePart(HttpServletRequest servletRequest) throws Exception { + return servletRequest.getParts().toArray(new Part[servletRequest.getParts().size()]); + } + } + } diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java index 7e87dfb891..9230f0fbbd 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -53,6 +53,8 @@ import javax.servlet.http.Part; import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; /** @@ -66,6 +68,7 @@ import org.springframework.util.StringUtils; * @author Mark Fisher * @author Chris Beams * @author Sam Brannen + * @author Brian Clozel * @since 1.0.2 */ public class MockHttpServletRequest implements HttpServletRequest { @@ -196,7 +199,7 @@ public class MockHttpServletRequest implements HttpServletRequest { private boolean requestedSessionIdFromURL = false; - private final Map parts = new LinkedHashMap(); + private final MultiValueMap parts = new LinkedMultiValueMap(); // --------------------------------------------------------------------- @@ -1048,17 +1051,21 @@ public class MockHttpServletRequest implements HttpServletRequest { } public void addPart(Part part) { - this.parts.put(part.getName(), part); + this.parts.add(part.getName(), part); } @Override public Part getPart(String name) throws IOException, IllegalStateException, ServletException { - return this.parts.get(name); + return this.parts.getFirst(name); } @Override public Collection getParts() throws IOException, IllegalStateException, ServletException { - return this.parts.values(); + List result = new LinkedList(); + for(List list : this.parts.values()) { + result.addAll(list); + } + return result; } } 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 a928fc00e6..2619c51fd0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -47,13 +47,13 @@ import org.springframework.web.multipart.MultipartFile; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; -import static org.mockito.Mockito.*; /** * Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}. * * @author Arjen Poutsma * @author Rossen Stoyanchev + * @author Brian Clozel */ public class RequestParamMethodArgumentResolverTests { @@ -62,12 +62,17 @@ public class RequestParamMethodArgumentResolverTests { private MethodParameter paramNamedDefaultValueString; private MethodParameter paramNamedStringArray; private MethodParameter paramNamedMap; - private MethodParameter paramMultiPartFile; + 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 paramMultipartFileList; - private MethodParameter paramPart; + private MethodParameter paramMultipartFileListNotAnnot; + private MethodParameter paramPartNotAnnot; private MethodParameter paramRequestPartAnnot; private MethodParameter paramRequired; private MethodParameter paramNotRequired; @@ -83,26 +88,32 @@ public class RequestParamMethodArgumentResolverTests { ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); Method method = getClass().getMethod("params", String.class, String[].class, - Map.class, MultipartFile.class, Map.class, String.class, - MultipartFile.class, List.class, Part.class, MultipartFile.class, - 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); paramNamedDefaultValueString = new MethodParameter(method, 0); paramNamedStringArray = new MethodParameter(method, 1); paramNamedMap = new MethodParameter(method, 2); - paramMultiPartFile = new MethodParameter(method, 3); - paramMap = new MethodParameter(method, 4); - paramStringNotAnnot = new MethodParameter(method, 5); + paramMultipartFile = new MethodParameter(method, 3); + paramMultipartFileList = new MethodParameter(method, 4); + paramMultipartFileArray = new MethodParameter(method, 5); + paramPart = new MethodParameter(method, 6); + paramPartList = new MethodParameter(method, 7); + paramPartArray = new MethodParameter(method, 8); + paramMap = new MethodParameter(method, 9); + paramStringNotAnnot = new MethodParameter(method, 10); paramStringNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileNotAnnot = new MethodParameter(method, 6); + paramMultipartFileNotAnnot = new MethodParameter(method, 11); paramMultipartFileNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileList = new MethodParameter(method, 7); - paramMultipartFileList.initParameterNameDiscovery(paramNameDiscoverer); - paramPart = new MethodParameter(method, 8); - paramPart.initParameterNameDiscovery(paramNameDiscoverer); - paramRequestPartAnnot = new MethodParameter(method, 9); - paramRequired = new MethodParameter(method, 10); - paramNotRequired = new MethodParameter(method, 11); + paramMultipartFileListNotAnnot = new MethodParameter(method, 12); + paramMultipartFileListNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); + paramPartNotAnnot = new MethodParameter(method, 13); + paramPartNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); + paramRequestPartAnnot = new MethodParameter(method, 14); + paramRequired = new MethodParameter(method, 15); + paramNotRequired = new MethodParameter(method, 16); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); @@ -114,11 +125,16 @@ public class RequestParamMethodArgumentResolverTests { 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("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFile)); + assertTrue("List parameter not supported", resolver.supportsParameter(paramMultipartFileList)); + assertTrue("MultipartFile[] parameter not supported", resolver.supportsParameter(paramMultipartFileArray)); + assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart)); + assertTrue("List 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(paramPart)); + assertTrue("Part parameter not supported", resolver.supportsParameter(paramPartNotAnnot)); resolver = new RequestParamMethodArgumentResolver(null, false); assertFalse(resolver.supportsParameter(paramStringNotAnnot)); @@ -150,16 +166,99 @@ public class RequestParamMethodArgumentResolverTests { @Test public void resolveMultipartFile() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); - MultipartFile expected = new MockMultipartFile("file", "Hello World".getBytes()); + MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes()); request.addFile(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultiPartFile, null, webRequest, null); + Object result = resolver.resolveArgument(paramMultipartFile, 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); + webRequest = new ServletWebRequest(request); + + Object result = resolver.resolveArgument(paramMultipartFileList, 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); + webRequest = new ServletWebRequest(request); + + Object result = resolver.resolveArgument(paramMultipartFileArray, null, webRequest, null); + + assertTrue(result instanceof MultipartFile[]); + MultipartFile[] parts = (MultipartFile[]) result; + 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); + + Object result = resolver.resolveArgument(paramPart, null, webRequest, null); + + assertTrue(result instanceof Part); + assertEquals("Invalid result", expected, result); + } + + @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"); + request.addPart(expected1); + request.addPart(expected2); + webRequest = new ServletWebRequest(request); + + Object result = resolver.resolveArgument(paramPartList, 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); + webRequest = new ServletWebRequest(request); + + Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null); + + assertTrue(result instanceof Part[]); + Part[] parts = (Part[]) result; + assertEquals(parts[0], expected1); + assertEquals(parts[1], expected2); + } + @Test public void resolveMultipartFileNotAnnot() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); @@ -174,7 +273,7 @@ public class RequestParamMethodArgumentResolverTests { } @Test - public void resolveMultipartFileList() throws Exception { + public void resolveMultipartFileListNotAnnotated() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); MultipartFile expected1 = new MockMultipartFile("multipartFileList", "Hello World 1".getBytes()); MultipartFile expected2 = new MockMultipartFile("multipartFileList", "Hello World 2".getBytes()); @@ -182,7 +281,7 @@ public class RequestParamMethodArgumentResolverTests { request.addFile(expected2); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null); + Object result = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null); assertTrue(result instanceof List); assertEquals(Arrays.asList(expected1, expected2), result); @@ -190,7 +289,7 @@ public class RequestParamMethodArgumentResolverTests { @Test(expected = MultipartException.class) public void isMultipartRequest() throws Exception { - resolver.resolveArgument(paramMultiPartFile, null, webRequest, null); + resolver.resolveArgument(paramMultipartFile, null, webRequest, null); fail("Expected exception: request is not a multipart request"); } @@ -204,7 +303,7 @@ public class RequestParamMethodArgumentResolverTests { request.setMethod("PUT"); webRequest = new ServletWebRequest(request); - Object actual = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null); + Object actual = resolver.resolveArgument(paramMultipartFileListNotAnnot, null, webRequest, null); assertTrue(actual instanceof List); assertEquals(expected, ((List) actual).get(0)); @@ -214,12 +313,12 @@ public class RequestParamMethodArgumentResolverTests { public void missingMultipartFile() throws Exception { request.setMethod("POST"); request.setContentType("multipart/form-data"); - resolver.resolveArgument(paramMultiPartFile, null, webRequest, null); + resolver.resolveArgument(paramMultipartFile, null, webRequest, null); fail("Expected exception: request is not MultiPartHttpServletRequest but param is MultipartFile"); } @Test - public void resolvePart() throws Exception { + public void resolvePartNotAnnot() throws Exception { MockPart expected = new MockPart("part", "Hello World".getBytes()); MockHttpServletRequest request = new MockHttpServletRequest(); request.setMethod("POST"); @@ -227,7 +326,7 @@ public class RequestParamMethodArgumentResolverTests { request.addPart(expected); webRequest = new ServletWebRequest(request); - Object result = resolver.resolveArgument(paramPart, null, webRequest, null); + Object result = resolver.resolveArgument(paramPartNotAnnot, null, webRequest, null); assertTrue(result instanceof Part); assertEquals("Invalid result", expected, result); @@ -325,8 +424,13 @@ public class RequestParamMethodArgumentResolverTests { public void params(@RequestParam(value = "name", defaultValue = "bar") String param1, @RequestParam("name") String[] param2, @RequestParam("name") Map param3, - @RequestParam(value = "file") MultipartFile param4, - @RequestParam Map param5, + @RequestParam(value = "mfile") MultipartFile param4, + @RequestParam(value = "mfilelist") List param5, + @RequestParam(value = "mfilearray") MultipartFile[] param6, + @RequestParam(value = "pfile") Part param7, + @RequestParam(value = "pfilelist") List param8, + @RequestParam(value = "pfilearray") Part[] param9, + @RequestParam Map param10, String stringNotAnnot, MultipartFile multipartFileNotAnnot, List multipartFileList, diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java index 9416137710..69fa4ca826 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.List; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; import org.springframework.core.GenericCollectionTypeResolver; import org.springframework.core.MethodParameter; @@ -73,6 +74,7 @@ import org.springframework.web.util.WebUtils; * code returned if {@link DefaultHandlerExceptionResolver} is configured. * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 3.1 */ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver { @@ -131,6 +133,10 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?"); arg = multipartRequest.getFiles(partName); } + else if (isMultipartFileArray(parameter)) { + Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?"); + arg = multipartRequest.getFiles(partName).toArray(new MultipartFile[0]); + } else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) { assertIsMultipartRequest(servletRequest); arg = servletRequest.getPart(partName); @@ -139,6 +145,10 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM assertIsMultipartRequest(servletRequest); arg = new ArrayList(servletRequest.getParts()); } + else if (isPartArray(parameter)) { + assertIsMultipartRequest(servletRequest); + arg = RequestPartResolver.resolvePart(servletRequest); + } else { try { HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, partName); @@ -193,6 +203,16 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM return ((collectionType != null) && "javax.servlet.http.Part".equals(collectionType.getName())); } + private boolean isPartArray(MethodParameter parameter) { + Class paramType = parameter.getParameterType().getComponentType(); + return ((paramType != null) && "javax.servlet.http.Part".equals(paramType.getName())); + } + + private boolean isMultipartFileArray(MethodParameter parameter) { + Class paramType = parameter.getParameterType().getComponentType(); + return ((paramType != null) && MultipartFile.class.equals(paramType)); + } + private Class getCollectionParameterType(MethodParameter parameter) { Class paramType = parameter.getParameterType(); if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){ @@ -235,4 +255,11 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM return !hasBindingResult; } + private static class RequestPartResolver { + + public static Object resolvePart(HttpServletRequest servletRequest) throws Exception { + return servletRequest.getParts().toArray(new Part[servletRequest.getParts().size()]); + } + } + } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java index 46a4c00cc2..8f4c20d00b 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -26,6 +26,7 @@ import javax.servlet.http.Part; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; @@ -53,13 +54,12 @@ import org.springframework.web.multipart.support.RequestPartServletServerHttpReq import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; /** * Test fixture with {@link RequestPartMethodArgumentResolver} and mock {@link HttpMessageConverter}. * * @author Rossen Stoyanchev + * @author Brian Clozel */ public class RequestPartMethodArgumentResolverTests { @@ -75,10 +75,12 @@ public class RequestPartMethodArgumentResolverTests { private MethodParameter paramValidRequestPart; private MethodParameter paramMultipartFile; private MethodParameter paramMultipartFileList; + private MethodParameter paramMultipartFileArray; private MethodParameter paramInt; private MethodParameter paramMultipartFileNotAnnot; private MethodParameter paramPart; private MethodParameter paramPartList; + private MethodParameter paramPartArray; private MethodParameter paramRequestParamAnnot; private NativeWebRequest webRequest; @@ -92,8 +94,9 @@ public class RequestPartMethodArgumentResolverTests { public void setUp() throws Exception { Method method = getClass().getMethod("handle", SimpleBean.class, SimpleBean.class, - SimpleBean.class, MultipartFile.class, List.class, Integer.TYPE, - MultipartFile.class, Part.class, List.class, MultipartFile.class); + SimpleBean.class, MultipartFile.class, List.class, MultipartFile[].class, + Integer.TYPE, MultipartFile.class, Part.class, List.class, + Part[].class, MultipartFile.class); paramRequestPart = new MethodParameter(method, 0); paramRequestPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); @@ -101,13 +104,15 @@ public class RequestPartMethodArgumentResolverTests { paramValidRequestPart = new MethodParameter(method, 2); paramMultipartFile = new MethodParameter(method, 3); paramMultipartFileList = new MethodParameter(method, 4); - paramInt = new MethodParameter(method, 5); - paramMultipartFileNotAnnot = new MethodParameter(method, 6); + paramMultipartFileArray = new MethodParameter(method, 5); + paramInt = new MethodParameter(method, 6); + paramMultipartFileNotAnnot = new MethodParameter(method, 7); paramMultipartFileNotAnnot.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - paramPart = new MethodParameter(method, 7); + paramPart = new MethodParameter(method, 8); paramPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - paramPartList = new MethodParameter(method, 8); - paramRequestParamAnnot = new MethodParameter(method, 9); + paramPartList = new MethodParameter(method, 9); + paramPartArray = new MethodParameter(method, 10); + paramRequestParamAnnot = new MethodParameter(method, 11); messageConverter = mock(HttpMessageConverter.class); given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); @@ -129,6 +134,11 @@ public class RequestPartMethodArgumentResolverTests { assertTrue("RequestPart parameter not supported", resolver.supportsParameter(paramRequestPart)); assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot)); assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart)); + assertTrue("List parameter not supported", resolver.supportsParameter(paramPartList)); + assertTrue("Part[] parameter not supported", resolver.supportsParameter(paramPartArray)); + assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFile)); + assertTrue("List parameter not supported", resolver.supportsParameter(paramMultipartFileList)); + assertTrue("MultipartFile[] parameter not supported", resolver.supportsParameter(paramMultipartFileArray)); assertFalse("non-RequestPart parameter supported", resolver.supportsParameter(paramInt)); assertFalse("@RequestParam args not supported", resolver.supportsParameter(paramRequestParamAnnot)); } @@ -148,6 +158,16 @@ public class RequestPartMethodArgumentResolverTests { assertEquals(Arrays.asList(multipartFile1, multipartFile2), actual); } + @Test + public void resolveMultipartFileArray() throws Exception { + Object actual = resolver.resolveArgument(paramMultipartFileArray, null, webRequest, null); + assertNotNull(actual); + assertTrue(actual instanceof MultipartFile[]); + MultipartFile[] parts = (MultipartFile[]) actual; + assertEquals(parts[0], multipartFile1); + assertEquals(parts[1], multipartFile2); + } + @Test public void resolveMultipartFileNotAnnotArgument() throws Exception { MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); @@ -193,6 +213,26 @@ public class RequestPartMethodArgumentResolverTests { assertEquals(Arrays.asList(part1, part2), result); } + @Test + public void resolvePartArrayArgument() throws Exception { + MockPart part1 = new MockPart("requestPart1", "Hello World 1".getBytes()); + MockPart part2 = new MockPart("requestPart2", "Hello World 2".getBytes()); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("multipart/form-data"); + request.addPart(part1); + request.addPart(part2); + webRequest = new ServletWebRequest(request); + + Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null); + + assertTrue(result instanceof Part[]); + Part[] parts = (Part[]) result; + assertThat(parts, Matchers.arrayWithSize(2)); + assertEquals(parts[0], part1); + assertEquals(parts[1], part2); + } + @Test public void resolveRequestPart() throws Exception { testResolveArgument(new SimpleBean("foo"), paramRequestPart); @@ -296,10 +336,12 @@ public class RequestPartMethodArgumentResolverTests { @Valid @RequestPart("requestPart") SimpleBean validRequestPart, @RequestPart("requestPart") MultipartFile multipartFile, @RequestPart("requestPart") List multipartFileList, + @RequestPart("requestPart") MultipartFile[] multipartFileArray, int i, MultipartFile multipartFileNotAnnot, Part part, - @RequestPart("requestPart") List partList, + @RequestPart("part") List partList, + @RequestPart("part") Part[] partArray, @RequestParam MultipartFile requestParamAnnot) { }