Cross-posted to soapbuilders for input from the pros :-)
>>From: Jarmo Doc [mailto:[EMAIL PROTECTED]
>>Subject: When to use undocumented wsdl2java --wrapArrays?
>>
>>I note that Axis 1.3 wsdl2java supports an undocumented option:
>>--wrapArrays. I can see that it causes MyClass [] to be wrapped as
>>ArrayOfMyClass.
>>
>>When would it be sensible to use this option? I don't see
>>how wrapping an
>>array of trivial things in another class serves any useful purpose.
>>
Here is something I wrote in reply to a question in-house recently. If
anyone disagrees or has an opinion on this (or I've made any mistakes, or
it's just plain wrong!) I'd like to hear it as it is being written up for
our documentation.
In the past there have been some issues around minOccurs="0" and
nillable="true" for array elements. This was an attempt to clear this up
(even where "clearing it up" means pointing out the unresolvable ambiguity
with unwrapped arrays).
------
Arrays may be written in 2 ways which result in slightly different XML. One
way is to wrap the array elements in an outer element which means there is a
single array element which maps to the Java field with an array type. To
show the 2 mappings consider the simple class
public class Test {
public int id;
public String[] names;
public String city;
}
This may be mapped with wrapped arrays as follows
<complexType name="Test">
<sequence>
<element name="id" type="int"/>
<element name="names" type="tns:ArrayOfstring" nillable="true"/>
<element name="city" type="xsd:string" nillable="true"/>
</sequence>
</complexType>
<complexType name="ArrayOfstring">
<sequence>
<element name="name" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" nillable="true"/>
</sequence>
</complexType>
which would lead to an XML document such as
<tns:test>
<id>10</id>
<names>
<name>John</name>
<name>Henry</name>
<name>Ford</name>
</names>
<city>Boston</city>
</tns:test>
Here it is clear to see that the <names> element maps to the "names" Java
field in the Test class. There are other advantages listed later. The
alternative "unwrapped" array approach defines the Test type as
<complexType name="Test">
<sequence>
<element name="id" type="int"/>
<element name="names" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" nillable="true"/>
<element name="city" type="xsd:string" nillable="true"/>
</sequence>
</complexType>
leading to XML such as
<tns:test>
<id>10</id>
<names>John</names>
<names>Henry</names>
<names>Ford</names>
<city>Boston</city>
</tns:test>
Here the <names> elements are at the same level as the other field elements.
Also, the names element are each plural which is not a good mapping as each
should be singular. To fix the pluralization (and perhaps a more natural
schema) you could change this to
<complexType name="Test">
<sequence>
<element name="id" type="int"/>
<element name="name" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" nillable="true"/>
<element name="city" type="xsd:string" nillable="true"/>
</sequence>
</complexType>
leading to XML such as
<tns:test>
<id>10</id>
<name>John</names>
<name>Henry</names>
<name>Ford</names>
<city>Boston</city>
</tns:test>
but then there is not a mapping between
String[] names
and
<element name="name" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" nillable="true"/>
Use of wrapped maps more naturally to object languages. It makes naming the
elements clearer (as the above shows, you can have "String[] names" and
muliple elements called "names" or "String[] name" and multiple elements
named "name" - neither is "correct"), it maps directly from schema element
to Java field, and finally it allows differentiating between a null value of
the array reference and an empty array which is not possible with the
unwrapped approach.
Consider the unwrapped definition with respect to both a null array
reference, null array values and an empty array and the following XML
fragments
Fragment 1a
<tns:test>
<id>10</id>
<names xsi:nil="true"/>
<city>Boston</city>
</tns:test>
Fragment 1b
<tns:test>
<id>10</id>
<city>Boston</city>
</tns:test>
Mapping Fragment 1a to Java maps (surprisingly to some) to
Test[
id = 10
names = { null }
city = 'Boston"
]
Note that "names" is a 1 element array with the names[0] being the null
value.
Fragment 1b has an unresolvable ambiguity. Does the absence of a recurring
value map to the empty array or the null value? Is fragment 1b equivalent to
Test[
id = 10
names = null
city = "Boston"
]
or
Test[
id = 10
names = { }
city = "Boston"
]
The answer is that this depends on the toolkit. This is an either/or
situation as there is no way to use "nillable" to indicate a null array
reference.
With a wrapped array the situation is a little different because of the
extra level of indirection. The outer element may be used to indicate the
null value while the inner elements are used to indicate the array contents
(including no content).
Fragment 2a
<tns:test>
<id>10</id>
<names xsi:nil="true"/>
<city>Boston</city>
</tns:test>
Fragment 2b
<tns:test>
<id>10</id>
<names/>
<city>Boston</city>
</tns:test>
Fragment 2c
<tns:test>
<id>10</id>
<names>
<name xsi:nil="true"/>
</names>
<city>Boston</city>
</tns:test>
In Fragment 2a, the names element is present and is nil. Because this
element maps directly to the Java field (or field of another OO language) it
is clear the intention is to pass the null value.
In Fragment 2b, the names element is present but has no content. The value
is clearly not nil and also clearly has no elements and so must map to the
empty array.
In Fragment 2c it is clear that the <name> element is an item within the
names array and is nil (null).
These examples clearly show that use of wrapped arrays removes the
ambiguities associated with unwrapped arrays.
Personally I recommend the use of wrapped arrays as a programmer.
Pete