Spring WS with Axiom: JAXB is inlining MTOM attachments
Asked Answered
V

0

4

I have webservices to receive and send attachments, and I'd like to use JAXB as marshaller, but so far it is not working right, as JAXB inlines any attachment coming in or going out in the message body as base64 strings, consuming a lot of memory and frequently leading to OutOfMemoryError. I'm outlining my setup and fix attempts, and hope someone can help me get it right.

Axiom is my choice over SAAJ as message factory, as I have to handle big attachments. I can successfully use JAXB as a marshaller for parameters and return types of endpoint methods, except when an attachment is involved (inline issue). This is my setup for it:

Webservices config XML:

<beans xmlns=...>

    <context:component-scan base-package="com.example.webservice" />

    <sws:annotation-driven />

    <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>com.example.webservice.oxm.FileTestResponse</value>
                <value>com.example.webservice.oxm.FileTestRequest</value>
            </list>
        </property>
        <property name="mtomEnabled" value="true"/>
    </bean>

    <bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
        <property name="payloadCaching" value="true"/>
        <property name="attachmentCaching" value="true"/>
    </bean>

    <sws:dynamic-wsdl id="fileTest" portTypeName="fileTest" locationUri="/webservice/fileTest/" targetNamespace="http://example.com/webservice/definitions" >
        <sws:xsd location="/WEB-INF/fileTest.xsd" />
    </sws:dynamic-wsdl>

</beans>

Part of my XSD:

<!-- I generate the marshalling classes with XJB, and using
    xmime:expectedContentTypes it correctly creates mtomData field
    with DataHandler type instead of byte[] -->
<xs:element name="fileTestRequest">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="mtomData" type="xs:base64Binary"
                xmime:expectedContentTypes="application/octet-stream"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

My endpoint class:

package com.example.webservice;

import ...

@Endpoint
@Namespace(prefix = "s", uri = FileTestEndpoint.NAMESPACE)
public class FileTestEndpoint {

    public static final String NAMESPACE = "http://example.com/webservice/schemas";

    @PayloadRoot(localPart = "fileTestRequest", namespace = NAMESPACE)
    @ResponsePayload
    public FileTestResponse fileTest(@RequestPayload FileTestRequest req) throws IOException {
        // req.getMtomData() and do something with it
        FileTestResponse resp = new FileTestResponse();
        DataHandler dataHandler = new DataHandler(new ByteArrayDataSource("my file download data".getBytes(), "text/plain"));
        resp.setData(dataHandler);
        return resp;
    }
}

So, this code works, but not as it would with attachments. I'm searching for some time for a workign solution:

Apparently the best help came from this other SO question I posted about this inlining problem happening with WSS4J. Blaise Doughan said that I'd need AttachmentMarshaller and AttachmentUnmarshaller set on the (un)marshaller to get it handled properly, like he posted in his blog.


So, I'm assuming attachment marshallers are the key to solve this issue.

To set them on the (un)marshaller, I saw no other way but extend Jaxb2Marshaller and overide initJaxbMarshaller and initJaxbUnmarshaller, setting attachment marshallers (I copied Doughan's code for them) on the given (un)marshaller.

But my own Jaxb2Marshaller is not being used, not even when setting it manually to sws:annotation-driven:

<sws:annotation-driven marshaller="jaxb2Marshaller" unmarshaller="jaxb2Marshaller"/>

<bean id="jaxb2Marshaller" class="com.example.webservice.MyJaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>com.example.webservice.oxm.FileTestResponse</value>
            <value>com.example.webservice.oxm.FileTestRequest</value>
        </list>
    </property>
    <property name="mtomEnabled" value="true"/>
</bean>

This marshaller class is created but never used, I don't know why, so I still couldn't test if AttachmentMarshallers can solve the issue.

This is all I can say for now. There are quite a few approaches to try:

  • find out why MyJaxb2Marshaller is being ignored, probably the easiest;
  • fix JAXB attachment inlining some other way if AttachmentMarshallers won't solve it, and I don't know what that would be;
  • replace JAXB with other marshaller, that works just as well (mainly Axiom support, possibly WSS4J).

I'm on a long time on this issue, and I must be missing the obvious solution. Any help is most welcome.

Thanks!


Library versions:

  • Spring 3.1.0 (core, beans, oxm and such)
  • Spring WS 2.1.0 (core and Spring XML)
  • StAX2 2.1
  • WoodSToX 3.2.9 (wstx)
  • JAXB 2.2.5-2 (API+impl)
  • Apache Axiom 1.2.13 (API+impl+c14n+dom)
  • Apache Mime4j 0.7.2 (core)

App server is Oracle 11g R1 Patchset 1 with Java 1.6.0u14.

Vancouver answered 19/7, 2012 at 16:8 Comment(7)
Does the following help? #6434262Mariannemariano
@BlaiseDoughan I tried that code, I can successfully add the attachment, but I can't make the data field refer to it with XOP, it inlines the data as always, despite the same data being attached. Old messages (2007 to 2010) on Spring Forums say that MTOM support was available only to SAAJ, which is what was used on the answer you just posted. The code for AxiomSoapMessage.convertToXopPackage is still empty, so it seems untouched ever since. I'm not sure how could I need to patch Axiom on Spring to make attachment response work... maybe it would be needed for attachment requests as well.Vancouver
In a Java EE JAX-WS implementation, the JAX-WS implementation would interact with JAXB directly and set the attachment handlers itself, and then everything automatically works. I'm trying to piece together what Spring WS does.Mariannemariano
Sorry i hadn't replied earlier. I did get it to work eventually. See the update on my other thread (#11316523) . If you are still struggling let me know and i will send you a working copy example via email.Kutzenco
@Kutzenco Thanks for the solution. It works, but only for SAAJ. I'll keep looking for one with Axiom =)Vancouver
@Vancouver Did you manage to solve this problem using axiom? I am also having the same problem.Paddock
@Paddock No, unfortunately not. I've worked around it avoiding any processing in messages with attachments and left it as-is, because I had no more time to dedicate to this issue. I can't tell you exactly what I did because I don't have access to that code anymore. Sorry.Vancouver

© 2022 - 2024 — McMap. All rights reserved.