diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index 3bcd4ba1..3a366203 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -477,6 +477,10 @@ public abstract class AbstractMvcView implements View { } public Object execute(Object source, Object context) throws ConversionExecutionException { + if (!(source instanceof String)) { + // for the case of MultipartFile parameters; nothing to do + return source; + } String formattedValue = (String) source; DefaultMappingContext mappingContext = (DefaultMappingContext) context; Expression target = mappingContext.getCurrentMapping().getTargetExpression(); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java index 902abd21..a9fa285e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Locale; import org.springframework.binding.collection.SharedMapDecorator; +import org.springframework.web.multipart.MultipartFile; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.collection.LocalSharedAttributeMap; @@ -298,6 +299,15 @@ public class MockExternalContext implements ExternalContext { getMockRequestParameterMap().put(parameterName, parameterValues); } + /** + * Puts a MultipartFile request parameter into the mock parameter map. + * @param parameterName the parameter name + * @param parameterValue the parameter value + */ + public void putRequestParameter(String parameterName, MultipartFile parameterValue) { + getMockRequestParameterMap().put(parameterName, parameterValue); + } + /** * Sets the id of the event that should be signaled by this context. For use when resuming a flow. This method * depends on a MockViewFactory being configured for parsing the event id on a resume operation. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockParameterMap.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockParameterMap.java index d97ec97e..18bdbd1c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockParameterMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockParameterMap.java @@ -17,6 +17,7 @@ package org.springframework.webflow.test; import java.util.HashMap; +import org.springframework.web.multipart.MultipartFile; import org.springframework.webflow.core.collection.LocalParameterMap; import org.springframework.webflow.core.collection.ParameterMap; @@ -57,4 +58,16 @@ public class MockParameterMap extends LocalParameterMap { getMapInternal().put(parameterName, parameterValues); return this; } + + /** + * Add a new multi-part file parameter to this map. + * @param parameterName the parameter name + * @param parameterValues the parameter values + * @return this, to support call chaining + */ + public MockParameterMap put(String parameterName, MultipartFile parameterValues) { + getMapInternal().put(parameterName, parameterValues); + return this; + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java index 354a1470..574ed5a0 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestContext.java @@ -17,6 +17,7 @@ package org.springframework.webflow.test; import org.springframework.binding.message.DefaultMessageContext; import org.springframework.binding.message.MessageContext; +import org.springframework.web.multipart.MultipartFile; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.LocalAttributeMap; @@ -264,6 +265,15 @@ public class MockRequestContext implements RequestContext { getMockExternalContext().putRequestParameter(parameterName, parameterValues); } + /** + * Puts a MultipartFile request parameter into the mock parameter map. + * @param parameterName the parameter name + * @param parameterValue the parameter value + */ + public void putRequestParameter(String parameterName, MultipartFile parameterValue) { + getMockExternalContext().putRequestParameter(parameterName, parameterValue); + } + // convenience accessors /** diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java index 5fc8f9ee..9dd3da98 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java @@ -17,8 +17,10 @@ import org.springframework.binding.format.formatters.DateFormatter; import org.springframework.binding.format.registry.DefaultFormatterRegistry; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockServletContext; import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.View; import org.springframework.webflow.action.ViewFactoryActionAdapter; import org.springframework.webflow.engine.EndState; @@ -161,6 +163,7 @@ public class MvcViewTests extends TestCase { context.putRequestParameter("integerProperty", "5"); context.putRequestParameter("dateProperty", "2007-01-01"); context.putRequestParameter("beanProperty.name", "foo"); + context.putRequestParameter("multipartFile", new MockMultipartFile("foo", new byte[0])); BindBean bindBean = new BindBean(); StaticExpression modelObject = new StaticExpression(bindBean); modelObject.setExpressionString("bindBean"); @@ -183,6 +186,7 @@ public class MvcViewTests extends TestCase { cal.set(Calendar.YEAR, 2007); assertEquals(cal.getTime(), bindBean.getDateProperty()); assertEquals("foo", bindBean.getBeanProperty().getName()); + assertEquals("foo", bindBean.getMultipartFile().getName()); } public void testResumeEventModelBindingAllowedFields() throws Exception { @@ -295,6 +299,7 @@ public class MvcViewTests extends TestCase { private Date dateProperty; private boolean booleanProperty = true; private NestedBean beanProperty; + private MultipartFile multipartFile; public BindBean() { Calendar cal = Calendar.getInstance(); @@ -339,6 +344,14 @@ public class MvcViewTests extends TestCase { public NestedBean getBeanProperty() { return beanProperty; } + + public MultipartFile getMultipartFile() { + return multipartFile; + } + + public void setMultipartFile(MultipartFile multipartFile) { + this.multipartFile = multipartFile; + } } public static class NestedBean {