When working with web services, it is all too often assumed that anything that can be done in a programming language can be done in XML. There are many cases where that is not true. This tip addresses one of those cases: the distinction between an array which is null, and an array which has no elements.
Most programming languages, like the Java language, have the concept of an array: a sequential collection of like elements. XML also has a sequential collection of like elements: an XML schema element with a maxOccurs attribute whose value is greater than 1. So it stands to reason that the Java language's sequential collection of like elements would map nicely to XML's sequential collection of like elements. Listing 1 defines a complexType which contains such an XML schema 'array'.
Listing 1. A complexType containing an 'array'
<complexType name="bean">
<sequence>
<element name="name" type="xsd:string"/>
<element name="array" minOccurs="0" maxOccurs="unbounded"
nillable="true" type="xsd:int"/>
</sequence>
</complexType>
|
This XML "array" is not strictly an array. It is an element with an occurrence constraint, which means that the element is defined to occur a specific number of times, in this case 0 or more times. This does sound a lot like an array, and for most intents and purposes, it is. But the mapping isn't perfect. You should be aware of the shortcomings so they don't catch you by surprise.
Following the JAX-RPC mapping rules, the complexType in Listing 1 would become the Java bean in Listing 2 (actually, the bean would have getters and setters, but we'll keep it simple for this discussion).
Listing 2. A bean containing an array.
public class Bean {
public java.lang.String name;
public java.lang.Integer[] array;
}
|
(Note that Bean's array variable is an array of java.lang.Integer, not an array of int. The array element from the XML schema is nillable. A Java int cannot be null. A java.lang.Integer can be null. So we use java.lang.Integer in this mapping.)
Table 1 shows a number of examples of mapping an instance of the Java Bean to an instance of the corresponding XML. The first row is the Java representation; the second row is the corresponding XML representation.
One obvious thing to note about Table 1 -- and it's the topic of this tip -- is that an empty instance of a Java array and a null instance of a Java array map to the same XML instance. This is not good if you're depending on a distinction between the two.
One easy trap to fall into here is to guess that a null array inside a bean is really represented by the XML in the second column. But as we hope we've shown in the table, that really represents an array with a single element whose value is null, not a null array.
Is there a way around this issue?
Of course! The thing to be aware of is that an array in most programming languages is really made up of two things: there are the contents of the array and there is the array itself -- a wrapper, if you like, around the contents. An XML "array" is only a list of the elements. There is no wrapper.
So the solution is simple: create a wrapper for the array, as shown in Listing 3.
Listing 3. A bean containing a wrappered array.
<complexType name="arrayWrapper">
<sequence>
<element name="el" nillable="true" maxOccurs=
"unbounded" minOccurs="0" type="xsd:int"/>
</sequence>
</complexType>
<complexType name="bean">
<sequence>
<element name="name" type="xsd:string"/>
<element name="array" nillable="true" type="tns:arrayWrapper"/>
</sequence>
</complexType>
|
Table 2 is the array example table for this XML schema.
As you can see, the empty instance and the null instance of the arrayWrapper complexType are distinct from each other.
This solution isn't a cure-all. First of all, it's rather more complex than a simple minOccurs/maxOccurs representation of an array. Secondly, instead of a simple bean containing an array, this XML schema really looks like a bean containing a bean containing an array; and that's likely what you'll end up with if you map this XML schema into Java programming with your favorite JAX-RPC WSDL-to-Java tool. Until standards bodies recognize and map this wrapped array pattern appropriately, this solution is something you should apply only if you really must distinguish a null array from an empty array.
XML "arrays" are not truly arrays in a programming language sense. XML does not distinguish between a null array and an empty array. There is an XML schema pattern that you can follow to get the equivalent distinction, but this pattern is not well recognized by standards bodies and should only be used when absolutely necessary.
- Get the early release of the WebSphere Application Server Technology for Developers, version 6.0, supporting J2EE 1.4.
- Read the Web Services Description Language (WSDL) 1.1, the specification of WSDL.
- Read the XML Schema Primer, an introduction to the XML Schema specification.
- Get the IBM WebSphere SDK for Web Services (WSDK) Version 5.1, an integrated kit for creating, discovering, invoking, and testing web services. From this link you can download WSDK 5.1 and a number of tutorials.
-
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.
Russell Butek is one of the developers of the IBM WebSphere web services engine. He is also an IBM representative on the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces: the portable interceptor task force (of which he was chair), the core task force, and the interoperability task force. You can contact Russell at butek at us.ibm.com.
Richard Scheuerle is one of the developers of the IBM WebSphere web Services engine. He was involved in the implementation of Apache's AXIS SOAP engine. Richard has 10 years of development experience with compiler/language design. Currently he is concentrating on the web service engine performance and API design. Richard has also worked on the development of CORBA tooling and chip validation software. You can contact Richard at scheu@us.ibm.com.



