SOAP with Attachments API for Java (SAAJ)
The JAX-RPC specification relies on SAAJ for its handling of SOAP messages. SAAJ defines classes and interfaces for all of the pieces of a SOAP message. This begins with the javax.xml.soap.SOAPMessage class, which gives you access to the javax.xml.soap.SOAPEnvelope instance, which in turn lets you retrieve the javax.xml.soap.SOAPHeader and javax.xml.soap.SOAPBody instances, and so forth. All of them extend and inherit the javax.xml.soap.SOAPElement interface, which itself extends the W3C DOM Node interface.
In other words, SAAJ provides you with an XML-centric view of the elements of a SOAP message. JAX-RPC delegates all handling of messages to SAAJ. Note that I am not trying to offer a comprehensive view of SAAJ here, I just cover it as much as is needed for the topic of this tip.
The <xsd:any/> element is an element that represents arbitrary XML content within an XML document. It is what its name indicates: any kind of XML. This lets you create complex type definitions in an XML Schema without describing what the exact structure of certain parts of the complex type is. Here is an example (see Listing 1) that shows the definition of a type called Order. It contains two regular elements and one <xsd:any/> element.
Listing 1. XML Schema with <xsd:any/>
<schema elementFormDefault="qualified"
targetNamespace="http://anytip.webservices.ibm.com"
xmlns="http://www.w3.org/2001/XMLSchema">
<complexType name="Order">
<sequence>
<element name="createDate" nillable="true" type="xsd:dateTime"/>
<element name="customer" nillable="true" type="xsd:string"/>
<xsd:any maxOccurs="unbounded"/>
</sequence>
</complexType>
</schema>
|
An instance of this type can contain any number of additional XML elements without violating the schema definition. This way, you can add additional information to an Order element without defining its format in the schema.
So how does JAX-RPC handle an XML Schema that contains an <xsd:any/> element? The recently published JAX-RPC 1.1 specification defines that this element is mapped to the SAAJ's javax.xml.soap.SOAPElement interface (see Resources). This means that the Service Endpoint Interface will contain a parameter or return value of type javax.xml.soap.SOAPElement for each place in the schema where <xsd:any/> was used and, respectively, javax.xml.soap.SOAPElement[] if the maxOccurs attribute is bigger than 1.
Therefore, a JAX-RPC tool will generate the following class (see Listing 2) from the sample schema above (as usual, this sample does not make a lot of sense and only shows the concept; and also as usual, you can find the complete source for this article in the Resources section):
Listing 2. The generated Order class
public class Order implements java.io.Serializable {
private java.util.Calendar createDate;
private java.lang.String customer;
private javax.xml.soap.SOAPElement[] _any;
...
}
|
What does all of this have to do with custom serialization? Assume that your Web service uses some data that you don't want to be mapped into a Java class, but rather want to let the JAX-RPC engine hand it to the implementation in its XML form. The implementation could then parse it or simply pass it on as XML for further processing in the backend application. Similarly, you can create a client proxy that lets you pass in a SOAPElement rather than a mapped Java object.
This example also works in cases where you know the structure of the XML data beforehand. Imagine you use an OrderManager Web service which returns Order data based on some search criteria. Each Order instance contains a number of line items. Here is an extract of the WSDL in Listing3. Assuming that this is a pretty straightforward Web service, we will only look at the <types> section here.
Listing 3. WSDL for the Web service
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...>
<wsdl:types>
<schema elementFormDefault="qualified"
targetNamespace="http://any.webservices.ibm.com"
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="getOrder">
<complexType>
<sequence>
<element name="searchCriteria"
nillable="true" type="xsd:string"/>
</sequence>
</complexType>
</element>
<complexType name="Order">
<sequence>
<element name="createDate" nillable="true" type="xsd:dateTime"/>
<element name="customer" nillable="true" type="xsd:string"/>
<element name="lineItems" nillable="true" type="impl:LineItem"
maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="LineItem">
<sequence>
<element name="itemDesc" nillable="true" type="xsd:string"/>
<element name="itemNumber" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
<element name="getOrderResponse">
<complexType>
<sequence>
<element name="getOrderReturn"
nillable="true" type="impl:Order"/>
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>
...
</definitions>
|
Now imagine that you don't want the JAX-RPC engine to generate a LineItem Java class that maps the structure as defined in the XML Schema, but rather want to deal with the XML yourself (maybe because you directly store it as XML in a database, so that parsing it is not necessary at all). Therefore, before generating the client code for this Web service, you change the WSDL file and replace the element representing the lineItems with the <xsd:any/> element. The Order complex type will now look exactly like what you had seen earlier. The JAX-RPC tools will now generate a client side Order class that contains the SOAPElement property, instead of a lineItem class. The example above has already shown what this class looks like.
Now you can create client code that will retrieve an Order from the Web service, and use the line item information in its XML form. Here is an example test client in Listing 4, generated using WebSphere Application Server V5.0.2, which shows you what this could look like:
Listing 4. Sample client code
public class TestMain {
public static void main(String[] args) throws Exception {
OrderManager om =
new OrderManagerServiceLocator().getOrderManager();
Order order = om.getOrder("whatever");
SOAPElement lineItem = order.get_any()[0];
System.out.println("Line item is : "+lineItem.toString());
}
}
|
This client application will retrieve the Order as a Java object, but the line item information is returned in XML form, as an array of SOAPElements.
JAX-RPC provides a Java-centric view on Web services. If you want to do your own processing of some of the XML artifacts in a SOAP message, you can use the SAAJ API together with the <xsd:any/> element to do so. You can expect future versions of JAX-RPC engines to make this even easier. In fact, the JAX-RPC 1.1 specification mandates that compliant tools offer you for each type the option to map it either to a Java class or to a javax.xml.soap.SOAPElement.
| Name | Size | Download method |
|---|---|---|
| ws-xsdany.ear | 43.0 KB | HTTP |
Information about download methods
- Find the SOAP specification describing how SOAP headers are represented at the W3C SOAP 1.1 Web site.
- The W3C WSDL 1.1 Web site contains the WSDL specification with a description of how to add headers to the SOAP binding.
- Download the source code used in this article.
- Read "Developer's Introduction to JAX-RPC, Part 1" and "Developer's Introduction to JAX-RPC, Part 2" (developerWorks, January 2003), which offer a great introduction into the JAX-RPC standard.
- The WebSphere SDK for Web Services (WSDK) provides you with an easy entry into Web services programming.
-
Java API for XML-Based RPC (JAX-RPC) Downloads & Specifications provides links to the JAX-RPC 1.1 specification itself, as well as javadocs, class files, and Sun's JAX-RPC reference implementation.
Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps the IBM Strategic Alliance partners integrate their applications with WebSphere. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible.
Comments (Undergoing maintenance)





