Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I created a file upload service using Spring MVC with apache commons multipart resolver support which specifies that a file should be attached as part of a multipart HTTP Post request. The request also contains a parameter containing an XML string with meta-data about the object. The XML can be marshalled using JAXB.

Other services that are not multipart handle the marshalling transparently, e.g.:

@RequestMapping(value = "/register", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public ModelAndView createUser(@RequestBody CreateUserDTO createUserDTO) throws Exception {
        UserDTO user = userService.createUser(createUserDTO);
        return createModelAndView(user);
    }

Here CreateUserDTO is a JAXB annotated object which is automatically marshalled. In the multipart case I'd like to have the same transparency. Ideally I would like to do the following:

RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public ModelAndView createAttachment(@RequestParam AttachmentDTO attachment,
                                         HttpServletRequest request) throws Exception {

        final MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        AttachmentDTO attachment = null;
        final MultipartFile dataFile = multipartRequest.getFile("data");

        AttachmentDTO createdAttachment = attachmentService.createAttachment(attachment,
                dataFile);

        return createModelAndView(createdAttachment);
}

Unfortunately this does not work. I am able to bind the attachment parameter as String, but the automatic marshalling does not work. My work around is to manually do the marshalling like the following, but I don't like this approach (especially since the parameter may be specified both in JSON and XML form):

    @Autowired
    private Jaxb2Marshaller jaxb2Marshaller;

    @Autowired
    private ObjectMapper jacksonMapper;  

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public ModelAndView createAttachment(@RequestParam(ATTACHMENT_PARAMETER) String attachmentString,
                                                 final HttpServletRequest request) throws Exception {

            final MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            AttachmentDTO attachment = null;
            try {
                attachment = (AttachmentDTO)jaxb2Marshaller.unmarshal(new StreamSource(new StringReader(attachmentString)));
            } catch (XmlMappingException e) {
                //Try JSON
                try {
                    attachment = jacksonMapper.readValue(attachmentString, AttachmentDTO.class);
                } catch (IOException e1) {
                    throw new BadRequestException("Could not interpret attachment parameter, both JSON and XML parsing failed");
                }
            }

Does anyone have a better suggestion for resolving this issue?

For completeness I also specify the relevant Spring config here:

<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1"/>
        <property name="favorPathExtension" value="true"/>
        <property name="ignoreAcceptHeader" value="false"/>
        <property name="mediaTypes">
            <map>
                <entry key="xml" value="application/xml"/>
                <entry key="json" value="application/json"/>
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/"/>
                    <property name="suffix" value=".jsp"/>
                </bean>
            </list>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <property name="modelKey" value="object"/>
                    <property name="marshaller" ref="jaxbMarshaller"/>
                </bean>
                <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                    <property name="objectMapper" ref="jaxbJacksonObjectMapper"/>
                </bean>
            </list>
        </property>
    </bean>

    <!--Use JAXB OXM marshaller to marshall/unmarshall following class-->
    <bean id="jaxbMarshaller"
          class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="contextPath" value="com.behindmedia.btfd.model.dto"/>
    </bean>

    <bean id="jaxbJacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>

    <!-- allows for integration of file upload functionality -->
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
        <property name="maxUploadSize" value="100000000"/>
    </bean>
share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.