How to send an attachment through SOAP using MTOM (Message Transmission Optimization Mechanism) In Java

MTOM or the Message Transmission Optimization Mechanism is a low overhead way of sending attachments in a SOAP message. There are only two things that you have to do in addition to normal SOAP messages in Java, yet it’s a pain in the ass because it’s not properly documented anywhere.

I’ve put together this guide in order to make it more clear.

Assumptions

  • You’re proficient in Java (8) / Spring
  • You can glue together the code snippets I’m listing for you here
  • We are sending a Multipart file to our Java Server which will accept it and transmit it over SOAP protocol in MTOM format.

Let’s Code

  1. Setup Our Boilerplate

Controller accepts the file attachment of type MultipartFile

    @RequestMapping(value = "/attachments/upload", method = RequestMethod.POST)
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public void uploadAttachmentMTOM(@RequestParam MultipartFile file) {        
        attachmentService.uploadAttachmentMTOM(new AttachmentDTO(            
            file.getOriginalFilename(), 
            file.getBytes())
        );
    }

Service converts the MultipartFile DTO into our XML-SOAP WSDL object and sends it into the WebService that activates MTOM

public void uploadAttachmentMTOM(AttachmentDTO attachmentDto) {        
        UploadWSDL uploadRequest = UploadWSDL.from(attachmentDto);
        myWebService.sendAndReceive(uploadRequest, "soapActionFromWSDL");
    }

2. Enabling MTOM

Enable MTOM in Our WebServiceTemplate extension. This will be passed into the “sendAndRecieve” method.

public class MtomClient extends WebServiceTemplate {
    private static Jaxb2Marshaller MARSHALLER   = buildMarshaller("my_context_path");

    private static Jaxb2Marshaller UNMARSHALLER = buildMarshaller("my_context_path_2");

    MtomClient(String contextPath) {
        super(MARSHALLER, UNMARSHALLER);
        // This is the 2nd important thing that allows you to send MTOM
        // Enabling MTOM 
        MARSHALLER.setMtomEnabled(true);
        UNMARSHALLER.setMtomEnabled(true);
    }

    private static Jaxb2Marshaller buildMarshaller(String contextPath) {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath(contextPath);
        return marshaller;
    }

Set a “SoapAction”. God knows what the hell this does, but it is absolutely required or else the JVM will not treat this like an MTOM message and shit will NOT work.

public class MyWebService {    

    /**
    * @param payload WSDL object
    * @param soapAction soapAction taken from WSDL
    */
    public JAXBElement<Object> sendAndReceive(Object payload, String soapAction) throws SoapConnectionException {

        try {                        
            return (JAXBElement<Object>) new MtomClient().marshalSendAndReceive(payload, message -> {

                // important part
                // With MTOM, if Soap Action isn't explicitly defined,
                // You'll get a 404 error 
                try {

                    SoapMessage soapMessage = (SoapMessage) message;                    
                    soapMessage.setSoapAction(soapAction);                    
                } catch (Exception e) {
                    // handle
                    // log error and abort
                }
            });                    
        } catch (final SoapMessageCreationException e) {
            // handle
        } catch (final WebServiceClientException e) {
            // handle
        } catch (final XmlMappingException e) {
            // handle            
        }

    }

}

That’s it. You should now be sending SOAP messages in MTOM format. If you need front-end code examples to go along with the backend code, here’s a github repo of both front and backend code:

https://github.com/sedkis/java-spring-js-MTOM-download

Please leave your comments below! Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *