WCF service WSDL generated from a programming language such as C# using DataContractSerializer may contain XML Schema constructs which result in JAXBElement<T> in generated code. A JAXBElement<T> type can also sometimes be generated when a WSDL contains advanced XML schema features such as substitution groups or elements that are both optional and nillable. In all such cases, JAXBElement<T> provides roundtripping support of values in XML instances. However, JAXBElement<T> is not natural to a Java developer. So the generateElementProperty customization can be used to generate an alternate developer friendly but lossy binding. The different bindings along with the trade-offs are discussed below.
The following is the default binding of an optional (minOccurs="0") and nillable(nillable="true") element:
//-- XML schema fragment <xs:element name="person" type="Person" <xs:complexType name="Person"> <xs:sequence> <xs:element name="name" type="xs:string" nillable="true" minOccurs="0"/> </xs:sequence> </xs:complexType> ... // Binding public class Person { JAXBElement<String> getName() {...}; public void setName(JAXBElement<String> value) {...} }
Since the XML element name is both optional and nillable, it can be represented in an XML instance in one of following ways:
<!-- Absence of element name--> <person> <-- element name is absent --> </person> <!-- Presence of an element name --> <person> <name xsi:nil="true"/> </person>
The JAXBElement<String> type roundtrips the XML representation of name element across an unmarshal/marshal operation.
When generateElementProperty is false, the binding is changed as follows:
// set JAXB customization generateElementProperty="false" public class Person { String getName() {...} public void setName(String value) {...} }
The above binding is more natural to Java developer than JAXBElement<String>. However, it does not roundtrip the value of name.
JAXB 2.0 allows generateElementProperty to be set:
Globally in <jaxb:globalBindings>
Locally in <jaxb:property> customization
When processing a WCF service WSDL, it is recommended that the generateElementProperty customization be set in <jaxb:globalBindings>:
<jaxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jaxb:bindings schemaLocation="schema-importedby-wcfsvcwsdl" node="/xs:schema"> <jaxb:globalBindings generateElementProperty="false"/> </jaxb:bindings> ...
The generateElementProperty attribute was introduced in JAXB 2.1.
XML Schema Part 2: Datatype defines facilities for defining datatypes for use in XML Schemas. .NET platform introduced the CLR types for some of the XML schema datatypes as described in Table 11–1.
Table 11–1 CLR to XML Schema Type Mapping
CLR Type |
XML Schema Type |
---|---|
byte |
xs:unsignedByte |
uint |
xs:unsignedInt |
ushort |
xs:unsignedShor |
ulong |
xs:unsignedLong |
However, there are no corresponding Java types that map to the XML Schema types listed in Table 11–1. Furthermore, JAXB 2.0 maps these XML schema types to Java types that are natural to Java developer. However, this results in a mapping that is not one-to-one. For example:
xs:int -> int
xs:unsignedShort -> int
The lack of a one-to-one mapping means that when XML Schema types shown in Table 11–1 are used in an xsi:type construct, they won’t be preserved by default across an unmarshal followed by marshal operation. For example:
// C# web method public Object retObject(Object objvalue); // Java web method generated from WCF service WSDL public Object retObject( Object objvalue); }
The following illustrates why xsi:type is not preserved across an unmarshal/marshal operation.
A value of type uint is marshalled by WCF serialization mechanism as:
<objvalue xsi:type="xs:unsignedShort"/>
JAXB 2.0 unmarshaller unmarshals the value as an instance of int and assigns it to parameter objvalue.
The objvalue is marshalled back by JAXB 2.0 marshaller with an xsi:type of xs:int.
<objvalue xsi:type="xs:int"/>
One way to preserve and roundtrip the xsi:type is to use the mapSimpleTypeDef customization. The customization makes the mapping of XML Schema Part 2 datatypes one--to-one by generating additional Java classes. Thus, xs:unsignedShort will be bound to its own class rather than int, as shown:
//Java class to which xs:unsignedShort is bound public class UnsignedShort { ... }
The following illustrates how the xsi:type is preserved across an unmarshal/marshal operation:
A value of type uint is marshalled by WCF serialization mechanism as:
<objvalue xsi:type="xs:unsignedShort"/>
JAXB 2.0 unmarshaller unmarshals the value as an instance of UnsignedShort and assigns it to parameter objvalue.
The objvalue is marshalled back by JAXB 2.0 marshaller with an xsi:type of xs:int.
<objvalue xsi:type="xs:unsignedShort"/>
Guideline: Use the mapSimpleTypedef customization where roundtripping of XML Schema types in Table 11–1 are used in xsi:type. However, it is preferable to avoid the use of CLR types listed in Table 11–1 since they are specific to .NET platform.
The syntax of the mapSimpleTypeDef customization is shown below.
<jaxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jaxb:bindings schemaLocation="schema-importedby-wcfsvcwsdl" node="/xs:schema"> <jaxb:globalBindings mapSimpleTypeDef="true"/> </jaxb:bindings> ....