Search code examples
springrestuploadresttemplatemultipart

Client side code for multipart REST operation


Hi I need to consume a REST operation which accepts a xml payload and a pdf file. Basically a JAXB object is converted to xml string and uploaded in a xml file. So in a multipart request, a xml file and pdf file are uploaded.

The REST operation server side code is as follows:

server side:

public class CompanyType extends MediaType {

public final static final XML_STRING = "applicaiton/company+xml";

}

@POST
@Path("/upload")
@Consumes("multipart/mixed")
@Produces(CompanyType.XML_STRING)
public UploadResponseObject upload(MultiPart multiPart){

UploadRequestObject req = multiPart.getBodyParts().get(0).getEntityAs(UploadRequestObject.class);
            BodyPartEntity bpe = (BodyPartEntity) multiPart.getBodyParts().get(1).getEntity();
            byte[] pdfBytes = IOUtils.toByteArray(bpe.getInputStream());
....
....
}

client side code to consume REST operation:

@Autowired
private RestTemplate rt;

public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
        String url = "http://<host-name>:<port>/service-name/upload");

        MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();

        this.rt = new RestTemplate();
        this.rt.setMessageConverters(getMessageConverter());
        String id = <random number generated from 1 to 50000>;

        // Add xml entity
        org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
        xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
        HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
        mv.add(id + ".xml", xmlFile);

        // Add pdf file     

        org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
        fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
        FileSystemResource fsr = new FileSystemResource(target);
        HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
                fsr, fileHeaders);
        String filename = target.getName();
        mv.add(filename, fileEntity);

        HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
        ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);       
        return res.getBody();
    }

private List<HttpMessageConverter<?>> getMessageConverter() {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
        MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
        List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
        supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
        mhmc.setSupportedMediaTypes(supportedMediaTypes);
        messageConverters.add(mhmc);

        // Add Form and Part converters
        FormHttpMessageConverter fmc = new FormHttpMessageConverter();
        fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
        messageConverters.add(fmc);

        return messageConverters;
    }

When the below line is executed from client code,

ResponseEntity<UploadResponseObject> res= this.rt.postForEntity(url, ereq, UploadResponseObject.class); 

the following exception is thrown

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter 
found for request 
type [org..types.UploadRequestObject] 
and content type [application/company+xml]

Please advise the changes to make the client side code work.


Solution

  • After much trial and error, was able to find the solution for the same.

    Client side code:

    @Autowired
        private RestTemplate rt;
    
    public UploadResponseObject callMultipartUploadOperation(UploadRequestObject req, java.io.File target) throws Exception {
            String url = "http://<host-name>:<port>/service-name/upload");
    
            MultiValueMap<String, Object> mv = new LinkedMultiValueMap<String, Object>();
    
            this.rt = new RestTemplate();
            this.rt.setMessageConverters(getMessageConverter());
            String id = <random number generated from 1 to 50000>;
    
            // Add xml entity
            org.springframework.http.HttpHeaders xmlFileHeaders = new org.springframework.http.HttpHeaders();
            xmlFileHeaders.add(MeditType.CONTENT_TYPE, "applicaiton/company+xml");
            HttpEntity<String> xmlFile = new HttpEntity<String>(createXMLString(req), xmlFileHeaders);
            mv.add(id + ".xml", xmlFile);
    
            // Add pdf file     
    
            org.springframework.http.HttpHeaders fileHeaders = new org.springframework.http.HttpHeaders();
            fileHeaders.add(MediaType.CONTENT_TYPE, "application/pdf");
            FileSystemResource fsr = new FileSystemResource(target);
            HttpEntity<FileSystemResource> fileEntity = new HttpEntity<FileSystemResource>(
                    fsr, fileHeaders);
            String filename = target.getName();
            mv.add(filename, fileEntity);
    
            HttpEntity<UploadRequestObject> ereq = new HttpEntity<UploadRequestObject>(req, getRequestHeaders());
            ResponseEntity<UploadResponseObject> res= this.restTemplate.postForEntity(url, ereq, UploadResponseObject.class);       
            return res.getBody();
        }
    

    Message converters:

    private List<HttpMessageConverter<?>> getMessageConverter() {
                List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
                Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
                jaxb2Marshaller.setClassesToBeBound(UploadResponseObject.class);
                MarshallingHttpMessageConverter mhmc = new MarshallingHttpMessageConverter(jaxb2Marshaller);
                List<org.springframework.http.MediaType> supportedMediaTypes = new ArrayList<org.springframework.http.MediaType>();
                supportedMediaTypes.add(new org.springframework.http.MediaType("application", "company+xml"));
                supportedMediaTypes.add(new org.springframework.http.MediaType("multipart", "form-data"));
                mhmc.setSupportedMediaTypes(supportedMediaTypes);
                messageConverters.add(mhmc);
    
                // Add Form and Part converters
                FormHttpMessageConverter fmc = new FormHttpMessageConverter();
                fmc.addPartConverter(new Jaxb2RootElementHttpMessageConverter());
                fmc.addPartConverter(new ResourceHttpMessageConverter());
                messageConverters.add(fmc);
    
                return messageConverters;
            }
    

    Request headers :

    private org.springframework.http.HttpHeaders getRequestHeaders(String contentType) throws Exception {
                ....
                .....
                org.springframework.http.HttpHeaders httpHeaders = new org.springframework.http.HttpHeaders();
                httpHeaders.set("Accept", "applicaiton/company+xml");
                httpHeaders.set("Content-Type", "multipart/form-data");
                String consumer = "<AppUserId>";
                httpHeaders.set("consumer", consumer);
                String tmStamp= getCurrentTimeStamp();
                httpHeaders.set("timestamp", tmStamp);
                ...
                ...
                return httpHeaders;
            }