WebDataBinder and @MVC request param binding detect and introspect MultipartFile arrays as well (SPR-2784)
This commit is contained in:
parent
5b0448c609
commit
255d1ad434
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
|
@ -107,7 +107,7 @@ public class PortletRequestDataBinder extends WebDataBinder {
|
|||
MutablePropertyValues mpvs = new PortletRequestParameterPropertyValues(request);
|
||||
if (request instanceof MultipartRequest) {
|
||||
MultipartRequest multipartRequest = (MultipartRequest) request;
|
||||
bindMultipartFiles(multipartRequest.getFileMap(), mpvs);
|
||||
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
|
||||
}
|
||||
doBind(mpvs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
|||
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockMultipartHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
|
||||
|
|
@ -119,6 +121,7 @@ import org.springframework.web.context.WebApplicationContext;
|
|||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.multipart.support.StringMultipartFileEditor;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
|
@ -1699,6 +1702,43 @@ public class ServletAnnotationControllerTests {
|
|||
assertEquals("test-{foo=bar}", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartFileAsSingleString() throws Exception {
|
||||
initServlet(MultipartController.class);
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.setRequestURI("/singleString");
|
||||
request.addFile(new MockMultipartFile("content", "Juergen".getBytes()));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("Juergen", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartFileAsStringArray() throws Exception {
|
||||
initServlet(MultipartController.class);
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.setRequestURI("/stringArray");
|
||||
request.addFile(new MockMultipartFile("content", "Juergen".getBytes()));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("Juergen", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipartFilesAsStringArray() throws Exception {
|
||||
initServlet(MultipartController.class);
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.setRequestURI("/stringArray");
|
||||
request.addFile(new MockMultipartFile("content", "Juergen".getBytes()));
|
||||
request.addFile(new MockMultipartFile("content", "Eva".getBytes()));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("Juergen,Eva", response.getContentAsString());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Controllers
|
||||
|
|
@ -2922,4 +2962,23 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
}
|
||||
|
||||
@Controller
|
||||
public static class MultipartController {
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
|
||||
}
|
||||
|
||||
@RequestMapping("/singleString")
|
||||
public void processMultipart(@RequestParam("content") String content, HttpServletResponse response) throws IOException {
|
||||
response.getWriter().write(content);
|
||||
}
|
||||
|
||||
@RequestMapping("/stringArray")
|
||||
public void processMultipart(@RequestParam("content") String[] content, HttpServletResponse response) throws IOException {
|
||||
response.getWriter().write(StringUtils.arrayToCommaDelimitedString(content));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
|
@ -105,7 +105,7 @@ public class ServletRequestDataBinder extends WebDataBinder {
|
|||
MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
|
||||
if (request instanceof MultipartRequest) {
|
||||
MultipartRequest multipartRequest = (MultipartRequest) request;
|
||||
bindMultipartFiles(multipartRequest.getFileMap(), mpvs);
|
||||
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
|
||||
}
|
||||
doBind(mpvs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.bind;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
|
|
@ -276,7 +277,10 @@ public class WebDataBinder extends DataBinder {
|
|||
* @param mpvs the property values to be bound (can be modified)
|
||||
* @see org.springframework.web.multipart.MultipartFile
|
||||
* @see #setBindEmptyMultipartFiles
|
||||
* @deprecated as of Spring 3.0, in favor of {@link #bindMultipart} which binds
|
||||
* all multipart files, even if more than one sent for the same name
|
||||
*/
|
||||
@Deprecated
|
||||
protected void bindMultipartFiles(Map<String, MultipartFile> multipartFiles, MutablePropertyValues mpvs) {
|
||||
for (Map.Entry<String, MultipartFile> entry : multipartFiles.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
|
|
@ -287,4 +291,30 @@ public class WebDataBinder extends DataBinder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind all multipart files contained in the given request, if any
|
||||
* (in case of a multipart request).
|
||||
* <p>Multipart files will only be added to the property values if they
|
||||
* are not empty or if we're configured to bind empty multipart files too.
|
||||
* @param multipartFiles Map of field name String to MultipartFile object
|
||||
* @param mpvs the property values to be bound (can be modified)
|
||||
* @see org.springframework.web.multipart.MultipartFile
|
||||
* @see #setBindEmptyMultipartFiles
|
||||
*/
|
||||
protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, MutablePropertyValues mpvs) {
|
||||
for (Map.Entry<String, List<MultipartFile>> entry : multipartFiles.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
List<MultipartFile> values = entry.getValue();
|
||||
if (values.size() == 1) {
|
||||
MultipartFile value = values.get(0);
|
||||
if (isBindEmptyMultipartFiles() || !value.isEmpty()) {
|
||||
mpvs.add(key, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mpvs.add(key, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import org.springframework.web.bind.support.WebBindingInitializer;
|
|||
import org.springframework.web.bind.support.WebRequestDataBinder;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartRequest;
|
||||
|
||||
/**
|
||||
|
|
@ -153,7 +154,7 @@ public class HandlerMethodInvoker {
|
|||
if (debug) {
|
||||
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
|
||||
}
|
||||
String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value();
|
||||
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
|
||||
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -381,7 +382,7 @@ public class HandlerMethodInvoker {
|
|||
boolean debug = logger.isDebugEnabled();
|
||||
for (Method initBinderMethod : initBinderMethods) {
|
||||
Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod);
|
||||
String[] targetNames = AnnotationUtils.findAnnotation(methodToInvoke, InitBinder.class).value();
|
||||
String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value();
|
||||
if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) {
|
||||
Object[] initBinderArgs =
|
||||
resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest);
|
||||
|
|
@ -481,15 +482,25 @@ public class HandlerMethodInvoker {
|
|||
Object paramValue = null;
|
||||
MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class);
|
||||
if (multipartRequest != null) {
|
||||
paramValue = multipartRequest.getFile(paramName);
|
||||
List<MultipartFile> files = multipartRequest.getFiles(paramName);
|
||||
if (!files.isEmpty()) {
|
||||
if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) {
|
||||
paramValue = files.get(0);
|
||||
}
|
||||
else {
|
||||
paramValue = files;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paramValue == null) {
|
||||
String[] paramValues = webRequest.getParameterValues(paramName);
|
||||
if (paramValues != null && !paramType.isArray()) {
|
||||
paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues);
|
||||
}
|
||||
else {
|
||||
paramValue = paramValues;
|
||||
if (paramValues != null) {
|
||||
if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) {
|
||||
paramValue = paramValues[0];
|
||||
}
|
||||
else {
|
||||
paramValue = paramValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paramValue == null) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class WebRequestDataBinder extends WebDataBinder {
|
|||
if (request instanceof NativeWebRequest) {
|
||||
MultipartRequest multipartRequest = ((NativeWebRequest) request).getNativeRequest(MultipartRequest.class);
|
||||
if (multipartRequest != null) {
|
||||
bindMultipartFiles(multipartRequest.getFileMap(), mpvs);
|
||||
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
|
||||
}
|
||||
}
|
||||
doBind(mpvs);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
|
@ -64,7 +64,6 @@ public interface MultipartRequest {
|
|||
* Return a {@link java.util.Map} of the multipart files contained in this request.
|
||||
* @return a map containing the parameter names as keys, and the
|
||||
* {@link MultipartFile} objects as values
|
||||
* @see MultipartFile
|
||||
*/
|
||||
Map<String, MultipartFile> getFileMap();
|
||||
|
||||
|
|
@ -72,7 +71,6 @@ public interface MultipartRequest {
|
|||
* Return a {@link MultiValueMap} of the multipart files contained in this request.
|
||||
* @return a map containing the parameter names as keys, and a list of
|
||||
* {@link MultipartFile} objects as values
|
||||
* @see MultipartFile
|
||||
* @since 3.0
|
||||
*/
|
||||
MultiValueMap<String, MultipartFile> getMultiFileMap();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
|
@ -29,8 +29,11 @@ import org.springframework.beans.PropertyValue;
|
|||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.TestBean;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockMultipartHttpServletRequest;
|
||||
import org.springframework.web.bind.ServletRequestParameterPropertyValues;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.multipart.support.StringMultipartFileEditor;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -187,6 +190,46 @@ public class WebRequestDataBinderTests {
|
|||
assertEquals(MyEnum.FOO, target.getMyEnum());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipartFileAsString() {
|
||||
TestBean target = new TestBean();
|
||||
WebRequestDataBinder binder = new WebRequestDataBinder(target);
|
||||
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.addFile(new MockMultipartFile("name", "Juergen".getBytes()));
|
||||
binder.bind(new ServletWebRequest(request));
|
||||
assertEquals("Juergen", target.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipartFileAsStringArray() {
|
||||
TestBean target = new TestBean();
|
||||
WebRequestDataBinder binder = new WebRequestDataBinder(target);
|
||||
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.addFile(new MockMultipartFile("stringArray", "Juergen".getBytes()));
|
||||
binder.bind(new ServletWebRequest(request));
|
||||
assertEquals(1, target.getStringArray().length);
|
||||
assertEquals("Juergen", target.getStringArray()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipartFilesAsStringArray() {
|
||||
TestBean target = new TestBean();
|
||||
WebRequestDataBinder binder = new WebRequestDataBinder(target);
|
||||
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
|
||||
|
||||
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
|
||||
request.addFile(new MockMultipartFile("stringArray", "Juergen".getBytes()));
|
||||
request.addFile(new MockMultipartFile("stringArray", "Eva".getBytes()));
|
||||
binder.bind(new ServletWebRequest(request));
|
||||
assertEquals(2, target.getStringArray().length);
|
||||
assertEquals("Juergen", target.getStringArray()[0]);
|
||||
assertEquals("Eva", target.getStringArray()[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoPrefix() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -213,26 +256,6 @@ public class WebRequestDataBinderTests {
|
|||
doTestTony(pvs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoParameters() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request);
|
||||
assertTrue("Found no parameters", pvs.getPropertyValues().length == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleValuesForParameter() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
String[] original = new String[] {"Tony", "Rod"};
|
||||
request.addParameter("forname", original);
|
||||
|
||||
ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request);
|
||||
assertTrue("Found 1 parameter", pvs.getPropertyValues().length == 1);
|
||||
assertTrue("Found array value", pvs.getPropertyValue("forname").getValue() instanceof String[]);
|
||||
String[] values = (String[]) pvs.getPropertyValue("forname").getValue();
|
||||
assertEquals("Correct values", Arrays.asList(values), Arrays.asList(original));
|
||||
}
|
||||
|
||||
/**
|
||||
* Must contain: forname=Tony surname=Blair age=50
|
||||
*/
|
||||
|
|
@ -258,6 +281,26 @@ public class WebRequestDataBinderTests {
|
|||
assertTrue("Map size is 0", m.size() == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoParameters() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request);
|
||||
assertTrue("Found no parameters", pvs.getPropertyValues().length == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleValuesForParameter() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
String[] original = new String[] {"Tony", "Rod"};
|
||||
request.addParameter("forname", original);
|
||||
|
||||
ServletRequestParameterPropertyValues pvs = new ServletRequestParameterPropertyValues(request);
|
||||
assertTrue("Found 1 parameter", pvs.getPropertyValues().length == 1);
|
||||
assertTrue("Found array value", pvs.getPropertyValue("forname").getValue() instanceof String[]);
|
||||
String[] values = (String[]) pvs.getPropertyValue("forname").getValue();
|
||||
assertEquals("Correct values", Arrays.asList(values), Arrays.asList(original));
|
||||
}
|
||||
|
||||
|
||||
public static class EnumHolder {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue