The Sorry State of SAAJ
When I started working on Spring Web Services some three years ago, I needed a way to represent a SOAP message. I was a good boy and used J2EE, or more specifically: the SOAP with Attachments API for Java™, also know as SAAJ, also known as the package javax.xml.soap. Founding Spring-WS on a specification seemed like the Proper Thing To Do, and gave me a warm fuzzy feeling inside.
Over time, I found out that SAAJ is quite possibly the worst implemented piece of J2EE Java EE out there. Now I’m sharing the pain with you in this post because, well, sharing is the first step in acceptance.
A Bit Of History
SAAJ started out as being part of the Java™ API for XML Messaging (JAXM). JAXM actually was quite nice: none of this “look ma, it’s just a method call!” nonsense that JAX-RPC offered. Unfortunately, JAXM was pulled in favor of JAX-RPC. Some of JAXM survived, namely the representation of a SOAP message, and was rebranded SAAJ 1.1.
SAAJ 1.1 basically offered a DOM-like representation of a SOAP message: SOAPEnvelope has a SOAPBody, and an optional SOAPHeader, and so on. All elements extended SOAPElement, which in turn extended Node. javax.xml.soap.Node, that is, not org.w3c.dom.Node, which - coincidentally - was the main problem with SAAJ 1.1: there was no easy way to integrate SAAJ with existing JAXP code. Even though SAAJ was similar to org.w3c.dom, there was no clear conversion path, besides writing the whole message to a buffer and reading that with JAXP. Yay.
The wise folks at the JCP decided to change that in SAAJ 1.2: in this version, all SAAJ classes extend their W3C DOM counterparts. So javax.xml.soap.Node extends org.w3c.dom.Node, SOAPElement extends Element, and so on, and so forth. Not everybody thought this was a clever idea; clearly Hani was not among those in favor. At this point, SAAJ was added to J2EE 1.4. Some J2EE vendors seem to agree with Hani as to whether this was a good idea, more about that later.
SAAJ 1.3 introduced some more stuff: support for SOAP 1.2, MTOM, and more. As a result of this plethora of features, SAAJ graduated from Java EE to Java SE in version 6. I think this was probably more a side-effect of SUN putting JAX-WS in Java 6, which is subject to a different rant altogether (short rant preview: had I implemented JAX-WS, I would be pretty pissed at SUN. Aren’t there laws against this sort of bundling?)
The SAAJ Saga continues
So, as of SAAJ 1.2, a SOAPElement isa W3C DOM Element. This makes sense, because now you can use JAXP to put XML content into the some message. For instance, you can use standard XML-DSIG or XML-ENC libraries to sign or decrypt a SOAP message, handy when doing WS-Security. Or, you can read a bit of XML from a file, and dump that into the SOAP body as a payload. The only caveat mentioned in the javax.xml.soap javadoc is that:
an application that starts to use SAAJ APIs on a tree after manipulating it using DOM APIs must assume that the tree has been translated into an all SAAJ tree and that any references to objects within the tree that were obtained using DOM APIs are no longer valid.
No problem, we can do that. Just don’t keep any references dangling around. So we might write something like:
MessageFactory messageFactory = MessageFactory.newInstance();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
SOAPMessage message = messageFactory.createMessage();
Document document = createDocument();
SOAPBody body = message.getSOAPBody();
transformer.transform(new DOMSource(document), new DOMResult(body));
body = message.getSOAPBody();
transformer.transform(new DOMSource(body), new StreamResult(System.out));
message.writeTo(System.out);
Here, we create a new SAAJ message using the MessageFactory. Next, we create a W3C DOM document, and we use a javax.xml.transform.Transformer to transform the document to the SOAP body. As a result the root element of the document should be appended to the SOAP body, it will become the payload of the message. Next, we write the body to the console, and finally we write the whole message to the console. Simple enough, and conforming to the spec.
Yet, this simple program does not work on the majority of Java EE servers.
The Acid Test
I created a simple Servlet which basically does the above, and ran it in a wide variety of Java EE application servers. Here is an overview, all J2EE 1.4 or higher (with the exception of Tomcat, of course, I used that as a baseline and to test the Axis 1 SAAJ implementation). I’ve listed the name, the MessageFactory implementation provided by the server, the test result, and the exception given - if any. Finally, I’ve submitted bugs where possible, because I am a Good Citizen.
| Application Server | MessageFactory | Result | Exception | Bug |
|---|---|---|---|---|
| Geronimo 2.1.2 with Jetty | org.apache.geronimo.webservices.saaj.GeronimoMessageFactory |
✔ | ||
| Geronimo 2.0.2 with Tomcat | org.apache.geronimo.webservices.saaj.GeronimoMessageFactory |
✘ | TransformerException when transforming Document to SOAPBody |
GERONIMO-4029 |
| GlassFish v2ur1 | com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl |
✔ | ||
| JBoss 4.2.2 | org.jboss.ws.core.soap.MessageFactoryImpl |
✘ | IndexOutOfBoundsException when transforming SOAPBody to stream |
|
| OC4J 10.1.3.1 | oracle.j2ee.ws.saaj.soap.MessageFactoryImpl |
✘ | TransformerException when transforming Document to SOAPBody |
|
| Tomcat 6.0.16 with SAAJ RI | com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl |
✔ | ||
| Tomcat 6.0.16 with Axis 1.4 SAAJ | org.apache.axis.soap.MessageFactoryImpl |
✔ | ||
| WebLogic 9.2 | weblogic.webservice.core.soap.MessageFactoryImpl |
✘ | UnsupportedOperationException when getting SOAPBody |
|
| WebLogic 10.0 | weblogic.webservice.core.soap.MessageFactoryImpl |
✘ | UnsupportedOperationException when getting SOAPBody |
|
| WebSphere 6.1 | com.ibm.ws.webservices.engine.soap.MessageFactoryImpl |
✔ |
Of this bunch, WebLogic is the clear winner. Every time you call SOAPMessage.getBody(), WebLogic barfs up a UnsupportedOperationException, saying that “This class does not support SAAJ 1.1″! The thing is: it supports SAAJ 1.1 just fine, it just doesn’t do SAAJ 1.2. You know, J2EE 1.4 and all that.
You Can Help!
Obviously, I am missing WebSphere in this overview. Because I run OS X, I can’t install WebSphere. So if you want to be a Good Citizen too, you can run my little test program on WebSphere, or any other app server I have missed. Update: craig has given me the info for WebSphere, and I’ve updated the table accordingly. Thanks! I’m still interested in any other J2EE 1.4+ app servers I’ve missed, though.
Or if you don’t trust me, you can test it yourself. Just deploy the WAR, and let me know in a comment below.
If you don’t trust me at all, you can get the sources. It has a build.xml and all:
Let’s hope that this post solves the issues with SAAJ, because I Want To Believe.

Some time ago, I have heard a developer say something like: