javaspring-webflow-2

Spring Webflow 2.4.5 multipart/form-data binding problems


I have the multipart resolver configured for the project:

@EnableWebMvc
@ComponentScan({"com.dg"})
@Configuration
@SuppressWarnings("deprecation")
public class AppConfig extends AbstractFlowConfiguration {

    @Bean
    public CommonsMultipartResolver fileResolver() {
        CommonsMultipartResolver cr = new CommonsMultipartResolver();
        cr.setDefaultEncoding("UTF-8");
        cr.setMaxUploadSize(26214400);
        return cr;
    }

}

I am using a serializable object as the model:

public class NewRequestModel implements Serializable {

    private static final long serialVersionUID = -5372803991673351564L;

    private String entry;

    private transient MultipartFile attachment;

    ... // getters and setters

}

When the page loads, I initialize the model:

WEBFLOW

<var name="requestModel" class="com.dg.model.request.NewRequestModel" />

    <on-start>
        <evaluate expression="newRequestAction.initTestRequest" />
    </on-start>

ACTION

public Event initTestRequest(RequestContext context) {
        NewRequestModel model = (NewRequestModel)context.getFlowScope().get("requestModel");
        if (model==null) {
            model = new NewRequestModel();
        }
        context.getFlowScope().put("requestModel", model);
        return new Event(this, "DONE");
    }

I bind the values in the JSP:

<form:form id="actionForm" method="POST" modelAttribute="requestModel" enctype="multipart/form-data">

    <div class="panel-heading">
        Test Request
    </div>

    <div class="panel-body">

        <div class="form-group">
            <form:input path="entry" />
        </div>

        <div class="form-group">
            <form:input type="file" path="attachment" />
        </div>

        <div>
            <button type="button" class="btn btn-primary" onclick="app.submitEvent({formSelector: '#actionForm',event: 'submitAndValidate'});">
                Submit Request
            </button>
        </div>

    </div>

</form:form>

When the button is clicked, the form is submitted with event "submitAndValidate"

 <view-state id="start" view="request/test/test-request" model="requestModel">
        <transition on="submitAndValidate" to="submitAndValidate" />
    </view-state>

    <action-state id="submitAndValidate">
        <evaluate expression="newRequestAction.testRequest" />
        <transition to="start" />
    </action-state>

When I debug into the Action class, testRequest method, The model does not retain the values submitted with the form.

public Event testRequest(RequestContext context) {
        NewRequestModel model = (NewRequestModel)context.getFlowScope().get("requestModel");
        String entry= model.getEntry();
        MultipartFile file = model.getAttachment();
        if (entry==null) {
            // is null when enctype is included on form
            // is populated when enctype is not included on form
        } 
        if (file==null) {
            // always null for some reason
        }
        return new Event(this, "DONE");
    }

If I remove enctype="multipart/form-data" from the form, the binding works for the "entry" variable. Of course, this won't allow for uploading a document. So I need to be able to include the enctype on the form.

I've gone over this and looked up answers and read the guides and I just am not seeing why this would fail. I appreciate any help in finding the offending configuration/code.


Solution

  • The problem was in my MultipartResolver bean configuration. Spring is looking specifically for a bean named "multipartResolver." Therefore I had 2 options to fix this:

    OPTION 1 - specify the name in the @Bean annotation

    @Bean(name="multipartResolver")
    public CommonsMultipartResolver fileResolver() {
        CommonsMultipartResolver cr = new CommonsMultipartResolver();
        cr.setDefaultEncoding("UTF-8");
        cr.setMaxUploadSize(26214400);
        return cr;
    }
    

    OPTION 2 - rename the method

    @Bean 
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver cr = new CommonsMultipartResolver();
        cr.setDefaultEncoding("UTF-8");
        cr.setMaxUploadSize(26214400);
        return cr;
    }
    

    For most people, the above change will likely resolve the issue. However, I also needed to add Apache Commons IO to my project due to ClassNotFoundException errors that appeared after making the above change.

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>
    

    With these updates in place, the form now binds properly. My issues are resolved.