Search code examples
spring-mvcjaxbmarshalling

how to write marshaller object to httpresponse object and download it as xml file


I am trying to create an xml file from my data class using JaxB and download it.

I have created marshaller object from java object. However I am unable to return this object as xml file. When I hit that method I get an empty xml file is downloaded. I am newbie to File IO coding, please help me in this regard.

Following is my Controller method

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MyController{

@RequestMapping(value = PRODUCT_CODE_PATH_VARIABLE_PATTERN, method = RequestMethod.GET)
public void downloadProduct(@PathVariable("productCode") @NotNull final String productCode, final HttpServletRequest request, final HttpServletResponse response) throws Exception
    {
        response.setContentType("application/xml");
        response.setHeader("Content-Disposition", "attachment; filename=" + productCode + ".xml");
        final ProductDataJaxb productDataJaxb = getProductJaxObj(productCode);
        final JAXBContext jaxbContext = JAXBContext.newInstance(ProductDataJaxb.class);
        final Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        final OutputStream outputStream = new FileOutputStream(productCode + ".xml");
        marshaller.marshal(productDataJaxb, outputStream);

    }
}

My data class whose xml representation is what I want in downloaded xml file.

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@XmlRootElement(name = "Product")
@XmlType(propOrder ={ "code", "categories", "description" })
public class ProductDataJaxb
{

    private String code;
    private String description;
    private List<String> categories;

    /**
     * @return the code
     */
    @XmlElement
    public String getCode()
    {
        return code;
    }

    /**
     * @param code
     *           the code to set
     */
    public void setCode(final String code)
    {
        this.code = code;
    }

    /**
     * @return the description
     */
    @XmlElement
    public String getDescription()
    {
        return description;
    }

    /**
     * @param description
     *           the description to set
     */
    public void setDescription(final String description)
    {
        this.description = description;
    }

    /**
     * @return the categories
     */
    @XmlElement
    public List<String> getCategories()
    {
        return categories;
    }

    /**
     * @param categories
     *           the categories to set
     */
    public void setCategories(final List<String> categories)
    {
        this.categories = categories;
    }

  }

Solution

  • After some trial and error I got solution to implement my requirement as follows.

    @RequestMapping(value = PRODUCT_CODE_PATH_VARIABLE_PATTERN, method = RequestMethod.GET)
    public void downloadProduct(@PathVariable("productCode") @NotNull final String productCode, final HttpServletRequest request,
            final HttpServletResponse response) throws Exception
    {
        response.setContentType("application/xml");
        response.setHeader("Content-Disposition", "attachment; filename=" + productCode + ".xml");
        final ProductDataJaxb productDataJaxb = getProductJaxObj(productCode);
        final JAXBContext jaxbContext = JAXBContext.newInstance(ProductDataJaxb.class);
        final Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(productDataJaxb, response.getOutputStream());
    
    }
    

    I only had to pass output Stream object of HttpResponse object to marshal method to get this done. Gosh! I seriously need to study IO concepts now.... :)