Skip to main content
Chapter 16. Data ContractsLinks: Table of Contents | Single HTML | Single PDF

Chapter 16. Data Contracts

16.1. Web Service - Start from Java

This section provides guidelines for designing an XML schema exported by a Java web service designed starting from Java. Jakarta XML Binding provides a rich set of annotations and types for mapping Java classes to different XML Schema constructs. The guidelines provide guidance on using Jakarta XML Binding annotations and types so that developer friendly bindings may be generated by XML serialization mechanisms (svcutil) on WCF client.

Not all Jakarta XML Binding annotations are included here; not all are relevant from an interoperability standpoint. For example, the annotation @XmlAccessorType provides control over default serialization of fields and properties in a Java class but otherwise has no effect on the on-the-wire XML representation or the XML schema generated from a Java class. Select Jakarta XML Binding annotations are therefore not included here in the guidance.

The guidance includes several examples, which use the following conventions:

  • The prefix xs: is used to represent XML Schema namespace.

  • Jakarta XML Binding annotations are defined in jakarta.xml.bind.annotation package but, for brevity, the package name has been omitted.

16.1.1. Data Types

This section covers the following topics:

16.1.1.1. Primitives and Wrappers

Guideline: Java primitive and wrapper classes map to slightly different XML schema representations. Therefore, .NET bindings will vary accordingly.

Example 16.1. A Java primitive type and its corresponding wrapper class

//-- Java code fragment
public class StockItem{
    public Double wholeSalePrice;
    public double retailPrice;
}

//--Schema fragment
<xs:complexType name="stockItem">
    <xs:sequence>
        <xs:element name="wholeSalePrice" type="xs:double" minOccurs="0"/>
        <xs:element name="retailPrice" type="xs:double"/>
    </xs:sequence>
</xs:complexType>

//-- .NET C# auto generated code from schema
public partial class stockItem
{
    private double wholeSalePrice;
    private bool wholeSalePriceFieldSpecified;
    private double retailPrice;

    public double wholeSalePrice
    {
        get{ return this.wholeSalePrice;}
        set{this.wholeSalePrice=value}
    }

    public bool wholeSalePriceSpecified
    {
        get{ return this.wholeSalePriceFieldSpecified;}
        set{this.wholeSalePriceFieldSpecified=value}
    }

    public double retailPrice
    {
        get{ return this.retailPrice;}
        set{this.retailPrice=value}
    }
}

//-- C# code fragment
stockItem s = new stockItem();
s.wholeSalePrice = Double.parse("198.92");
s.wholeSalePriceSpecified = true;
s.retailPrice = Double.parse("300.25");

16.1.1.2. BigDecimal Type

Guideline: Limit decimal values to the range and precision of .NET's System.decimal.

java.math.BigDecimal maps to xs:decimal. .NET maps xs:decimal to System.decimal. These two data types support different range and precision. java.math.BigDecimal supports arbitrary precision. System.decimal does not. For interoperability use only values within the range and precision of System.decimal. (See System.decimal.Minvalue and System.decimal.Maxvalue.) Any values outside of this range require a customized .NET client.

Example 16.2. BigDecimal usage

//--- Java code fragment
public class RetBigDecimal {
    private BigDecimal arg0;

    public BigDecimal getArg0() { return this.arg0; }
    public void setArg0(BigDecimal arg0) { this.arg0 = arg0; }
}

//--- Schema fragment
<xs:complexType name="retBigDecimal">
    <xs:sequence>
        <xs:element name="arg0" type="xs:decimal" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//--- .NET auto generated code from schema
public partial class retBigDecimal{
    private decimal arg0Field;
    private bool arg0FieldSpecified;

    public decimal arg0 {
        get { return this.arg0Field;}
        set { this.arg0Field = value;}
    }

    public bool arg0Specified {
        get { return this.arg0FieldSpecified;}
        set { this.arg0FieldSpecified = value;}
    }
}

//--- C# code fragment
System.CultureInfo engCulture = new System.CultureInfo("en-US");
retBigDecimal bd = new retBigDecimal();
bd.arg0 = System.decimal.MinValue;

retBigDecimal negBd = new retBigDecimal();
negBd = System.decimal.Parse("-0.0", engCulture);

16.1.1.3. java.net.URI Type

Guideline: Use the @XmlSchemaType annotation for a strongly typed binding to a .NET client generated with the DataContractSerializer.

java.net.URI maps to xs:string. .NET maps xs:string to System.string. Annotation @XmlSchemaType can be used to define a more strongly typed binding to a .NET client generated with the DataContractSerializer. @XmlSchemaType can be used to map java.net.URI to xs:anyURI. .NET's DataContractSerializer and XmlSerializer bind xs:anyURI differently:

  • DataContractSerializer binds xs:anyURI to .NET type System.Uri.

  • XmlSerializer binds xs:anyURI to .NET type System.string.

Thus, the above technique only works if the WSDL is processed using DataContractSerializer.

Example 16.3. @XmlSchemaType and DataContractSerializer

// Java code fragment
public class PurchaseOrder
{
    @XmlSchemaType(name="anyURI")
     public java.net.URI uri;
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="uri" type="xs:anyURI" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//--- .NET auto generated code from schema
//--- Using svcutil.exe /serializer:DataContractSerializer <wsdl file>
public partial class purchaseOrder : object,
        System.Runtime.Serialization.IExtensibleDataObject
{

    private System.Uri uriField;

    //-- ..... other generated code ........
    public System.Uri uri
    {
        get { return this.uriField; }
        set { this.uriField = value; }
    }
}

//--- C# code fragment
purchaseOrder tmpU = new purchaseOrder()
tmpU.uri = new System.Uri("../Hello", System.UriKind.Relative);

Example 16.4. @XmlSchemaType and XmlSerializer

// Java code fragment
public class PurchaseOrder
{
    @XmlSchemaType(name="anyURI")
    public java.net.URI uri;
}

//--- .NET auto generated code from schema
//--- Using svcutil.exe /serializer:XmlSerializer <wsdl file>
public partial class purchaseOrder
{
    private string uriField;
    public string uri
    {
        get { return this.uriField; }
        set { this.uriField = value; }
    }
}

//--- C# code fragment
purchaseOrder tmpU = new purchaseOrder()
tmpU.uri = "mailto:mailto:mduerst@ifi.unizh.ch";

16.1.1.4. Duration

Guideline: Use .NET's System.Xml.XmlConvert to generate a lexical representation of xs:duration when the binding is to a type of System.string.

javax.xml.datatype.Duration maps to xs:duration. .NET maps xs:duration to a different datatype for DataContractSerializer and XmlSerializer.

  • DataContractSerializer binds xs:duration to .NET System.TimeSpan.

  • XmlSerializer binds xs:duration to .NET System.string.

When xs:duration is bound to .NET System.string, the string value must be a lexical representation for xs:duration. .NET provides utility System.Xml.XmlConvert for this purpose.

Example 16.5. Mapping xs:duration using DataContactSerializer

//-- Java code fragment
public class PurchaseReport {
     public javax.xml.datatype.Duration period;
}

//-- Schema fragment
<xs:complexType name="purchaseReport">
    <xs:sequence>
        <xs:element name="period" type="xs:duration" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//-- .NET auto generated code from schema
//-- Using svcutil.exe /serializer:DataContractSerializer <wsdl file>
public partial class purchaseReport: object,
        System.Runtime.Serialization.IExtensibleDataObject
{
    private System.TimeSpan periodField;
    //-- ..... other generated code ........
    public System.TimeSpan period
    {
        get { return this.periodField; }
        set { this.periodField = value; }
    }
}

//-- C# code fragment
purchaseReport tmpR = new purchaseReport();
tmpR.period = new System.TimeSpan.MaxValue;

Example 16.6. Mapping xs:duration using XmlSerializer

//-- .NET auto generated code from schema
//-- Using svcutil.exe /serializer:XmlSerializer <wsdl file>
public partial class purchaseReport
{
    private string periodField;
    public string period
    {
        get { return this.periodField; }
        set { this.periodField = value; }
    }
}

//-- C# code fragment
purchaseReport tmpR = new purchaseReport();
tmpR.period = System.Xml.XmlConvert.ToString(new System.TimeSpan(23, 0,0));

16.1.1.5. Binary Types

Guideline: java.awt.Image, javax.xml.transform.Source, and jakarta.activation.DataHandler map to xs:base64Binary. .NET maps xs:base64Binary to byte[].

Jakarta XML Binding provides the annotation @XmlMimeType, which supports specifying the content type, but .NET ignores this information.

Example 16.7. Mapping java.awt.Image without @XmlMimeType

//-- Java code fragment
public class Claim {
    public java.awt.Image photo;
}

//-- Schema fragment
<xs:complexType name="claim">
    <xs:sequence>
        <xs:element name="photo" type="xs:base64Binary" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//-- .NET auto generated code from schema
public partial class claim : object,
        System.Runtime.Serialization.IExtensibleDataObject
{
    private byte[] photoField;
    //-- ..... other generated code .......
    public byte[] photo
    {
        get { return this.photoField; }
        set { this.photoField = value; }
    }
}

//-- C# code fragment
try
{
    claim tmpC = new claim();

    System.IO.FileStream f = new System.IO.FileStream(
        "C:\\icons\\circleIcon.gif", System.IO.FileMode.Open);
    int cnt = (int)f.Length;
    tmpC.photo = new byte[cnt];
    int rCnt = f.Read(tmpC.photo, 0, cnt);

}
catch (Exception e)
{
    Console.WriteLine(e.ToString());
}

Example 16.8. Mapping java.awt.Image with @XmlMimeType

//-- Java code fragment
public class Claim {
    @XmlMimeType("image/gif")
    public java.awt.Image photo;
}

//-- Schema fragment
<xs:complexType name="claim">
    <xs:sequence>
        <xs:element name="photo" ns1:expectedContentTypes="image/gif"
                    type="xs:base64Binary" minOccurs="0"
                    xmlns:ns1="http://www.w3.org/2005/05/xmlmime"/>
    </xs:sequence>
</xs:complexType>

//-- Using the @XmlMimeType annotation doesn't change .NET
//--auto generated code
public partial class claim : object,
        System.Runtime.Serialization.IExtensibleDataObject
{
    private byte[] photoField;
    //-- ..... other generated code .......
    public byte[] photo
    {
        get { return this.photoField; }
        set { this.photoField = value; }
    }
}

//-- This code is unchanged by the different schema
//-- C# code fragment
try
{
    claim tmpC = new claim();

    System.IO.FileStream f = new System.IO.FileStream(
        "C:\\icons\\circleIcon.gif", System.IO.FileMode.Open);
    int cnt = (int)f.Length;
    tmpC.photo = new byte[cnt];
    int rCnt = f.Read(tmpC.photo, 0, cnt);
}
catch (Exception e)
{
    Console.WriteLine(e.ToString());
}

16.1.1.6. XMLGregorianCalendar Type

Guideline: Use java.xml.datatype.XMLGregorianCalendar instead of java.util.Date and java.util.Calendar.

XMLGregorianCalendar supports the following XML schema calendar types: xs:date, xs:time, xs:dateTime, xs:gYearMonth, xs:gMonthDay, xs:gYear, xs:gMonth, and xs:gDay. It is statically mapped to xs:anySimpleType, the common schema type from which all the XML schema calendar types are dervived. .NET maps xs:anySimpleType to System.string.

java.util.Date and java.util.Calendar map to xs:dateTime, but don't provide as complete XML support as XMLGregorianCalendar does.

Guideline: Use the annotation @XmlSchemaType for a strongly typed binding of XMLGregorianCalendar to one of the XML schema calendar types.

Example 16.9. XmlGregorianCalendar without @XmlSchemaType

//-- Java code fragment
public class PurchaseOrder {
    public javax.xml.datatype.XMLGregorianCalendar orderDate;
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="orderDate" type="xs:anySimpleType" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//-- .NET auto generated code from schema
public partial class purchaseOrder
{
    private string orderDateField;
    public string orderDate
    {
        get { return this.orderDateField; }
        set { this.orderDateField = value; }
    }
}

//-- C# code fragment
purchaseOrder tmpP = new purchaseOrder();
tmpP.orderDate = System.Xml.XmlConvert.ToString(
   System.DateTime.Now, System.Xml.XmlDateTimeSerializerMode.RoundtripKind);

Example 16.10. XMLGregorianCalendar with @XmlSchemaType

//-- Java code fragment
public class PurchaseOrder {
    @XmlSchemaType(name="dateTime")
    public javax.xml.datatype.XMLGregorianCalendar orderDate;
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="orderDate" type="xs:dateTime" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//-- .NET auto generated code from schema
public partial class purchaseOrder : object,
        System.Runtime.Serialization.IExtensibleDataObject
{
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
    private System.DateTime orderDateField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
        get { return this.extensionDataField; }
        set { this.extensionDataField = value; }
    }

    public System.DateTime orderDate
    {
        get { return this.orderDateField; }
        set { this.orderDateField = value; }
    }
}

//-- C# code fragment
purchaseOrder tmpP = new purchaseOrder();
tmpP.orderDate = System.DateTime.Now;

16.1.1.7. UUID Type

Guideline: Use Leach-Salz variant of UUID at runtime.

java.util.UUID maps to schema type xs:string. .NET maps xs:string to System.string. The constructors in java.util.UUID allow any variant of UUID to be created. Its methods are for manipulation of the Leach-Salz variant.

Example 16.11. Mapping UUID

//-- Java code fragment
public class ReportUid {
    public java.util.UUID uuid;
}

//-- Schema fragment
<xs:complexType name="reportUid">
    <xs:sequence>
        <xs:element name="uuid" type="xs:string" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

//-- .NET auto generated code from schema
public partial class reportUid: object,
        System.Runtime.Serialization.IExtensibleDataObject
{
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
    private string uuidField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData
    {
        get { return this.extensionDataField; }
        set { this.extensionDataField = value; }
    }

    public string uuid
    {
        get { return this.uuidField; }
        set { this.uuidField = value; }
    }
}

//-- C# code fragment
reportUid tmpU = new reportUid();
System.Guid guid = new System.Guid("06b7857a-05d8-4c14-b7fa-822e2aa6053f");
tmpU.uuid = guid.ToString();

16.1.1.8. Typed Variables

Guideline: A typed variable maps to xs:anyType. .NET maps xs:anyType to System.Object.

Example 16.12. Using a typed variable

// Java class
public class Shape <T>
{
    private T xshape;

    public Shape() {};
    public Shape(T f)
    {
        xshape = f;
    }
}

//-- Schema fragment
<xs:complexType name="shape">
    <xs:sequence>
        <xs:element name="xshape" type="xs:anyType" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

// C# code generated by svcutil
public partial class shape
{
    private object xshapeField;

    public object xshape
    {
        get { return this.xshapeField; }
        set { this.xshapeField = value; }
    }
}

16.1.1.9. Collections Types

Java collections types (java.util.Collection and its subtypes, array, List, and parameterized collection types such as List<Integer>) can be mapped to XML schema in different ways and can be serialized in different ways. The following examples show .NET bindings.

16.1.1.9.1. List of Nillable Elements

Guideline: By default, a collection type such as List<Integer> maps to an XML schema construct that is a repeating unbounded occurrence of an optional and nillable element. .NET binds the XML schema construct to System.Nullable<int>[]. The element is optional and nillable. However, when marshalling Jakarta XML Binding marshaller will always marshal a null value using xsi:nil.

Example 16.13. Collection to a list of nillable elements

//-- Java code fragment
@XmlRootElement(name="po")
public PurchaseOrder {
    public List<Integer> items;
}

//-- Schema fragment
<xs:element name="po" type="purchaseOrder">
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="items" type="xs:int" nillable="true"
                    minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>
...

//--- Jakarta XML Binding XML serialization
<po>
    <items> 1 </items>
    <items> 2 </items>
    <items> 3 </items>
</po>

<po>
    <items> 1 </items>
    <items xsi:nil=true/>
    <items> 3 </items>
</po>

//-- .NET auto generated code from schema
partial class purchaseOrder {
        private System.Nullable<int>[] itemsField;

    public System.Nullable<int>[] items
    {
        get { return this.itemsField; }
        set { this.itemsField = value; }
    }
}

16.1.1.9.2. List of Optional Elements

Guideline: This is the same as above except that a collection type such as List<Integer> maps to a repeating unbounded occurrence of an optional (minOccurs="0") but not nillable element. This in turn binds to .NET type int[]. This is more developer friendly. However, when marshalling, Jakarta XML Binding will marshal a null value within the List<Integer> as a value that is absent from the XML instance.

Example 16.14. Collection to a list of optional elements

//-- Java code fragment
@XmlRootElement(name="po")
public PurchaseOrder {
    @XmlElement(nillable=false)
    public List<Integer> items;
}

//-- Schema fragment
<xs:element name="po" type="purchaseOrder">
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="items" type="xs:int"
                    minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>
...

// .NET auto generated code from schema
partial class purchaseOrder {
    private int[] itemsField;

    public int[] items
    {
        get { return this.itemsField; }
        set { this.itemsField = value; }
    }
}

16.1.1.9.3. List of Values

Guideline: A collection such as List<Integer> can be mapped to a list of XML values (that is, an XML schema list simple type) using annotation @XmlList. .NET maps a list simple type to a .NET System.string.

Example 16.15. Collection to a list of values using @XmlList

//-- Java code fragment
@XmlRootElement(name="po")
public PurchaseOrder {
    @XmlList public List<Integer> items;
}

//-- Schema fragment
<xs:element name="po" type="purchaseOrder">
<xs:complexType name="purchaseOrder">
    <xs:element name="items" minOccurs="0">
        <xs:simpleType>
            <xs:list itemType="xs:int"/>
        </xs:simpleType>
    </xs:element>
</xs:complexType>
...

//-- XML serialization
<po>
    <items> 1 2 3 </items>
</po>

// .NET auto generated code from schema
partial class purchaseOrder {
    private string itemsField;

    public string items
    {
        get { return this.itemsField; }
        set { this.itemsField = value; }
    }
}

16.1.1.10. Array Types

Example 16.16. Single and multidimensional arrays

//-- Java code fragment
public class FamilyTree {
    public Person[] persons;
    public Person[][] family;
}

// .NET auto generated code from schema
public partial class familyTree
{
    private person[] persons;
    private person[][] families;

    public person[] persons
    {
        get { return this.membersField; }
        set { this.membersField = value; }
    }

    public person[][] families
    {
        get { return this.familiesField; }
        set { this.familiesField = value; }
    }
}

16.1.2. Fields and Properties

The following guidelines apply to mapping of JavaBeans properties and Java fields, but for brevity Java fields are used.

16.1.2.1. @XmlElement Annotation

Guideline: The @XmlElement annotation maps a property or field to an XML element. This is also the default mapping in the absence of any other Jakarta XML Binding annotations. The annotation parameters in @XmlElement can be used to specify whether the element is optional or required, nillable or not. The following examples illustrate the corresponding bindings in the .NET client.

Example 16.17. Map a field or property to a nillable element

//-- Java code fragment
public class PurchaseOrder {

    // Map a field to a nillable XML element
    @jakarta.xml.bind.annotation.XmlElement(nillable=true)
    public java.math.BigDecimal price;
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="price" type="xs:decimal"
                    nillable="true" minOccurs="0" />
    </xs:sequence>
</xs:complexType>

// .NET auto generated code from schema
public partial class purchaseOrder {
    private System.Nullable<decimal> priceField;
    private bool priceFieldSpecified;

    public decimal price
    {
        get { return this.priceField; }
        set { this.priceField = value; }
    }

    public bool priceSpecified {
    {
        get { return this.priceFieldSpecified; }
        set { this.priceFieldSpecified = value;}
    }
}

Example 16.18. Map a property or field to a nillable, required element

//-- Java code fragment
public class PurchaseOrder {

    // Map a field to a nillable XML element
    @XmlElement(nillable=true, required=true)
    public java.math.BigDecimal price;
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="price" type="xs:decimal"
                    nillable="true" minOccurs="1" />
    </xs:sequence>
</xs:complexType>

// .NET auto generated code from schema
public partial class purchaseOrder {
    private System.Nullable<decimal> priceField;

    public decimal price
    {
        get { return this.priceField; }
        set { this.priceField = value; }
    }
}

16.1.2.2. @XmlAttribute Annotation

Guideline: A property or field can be mapped to an XML attribute using @XmlAttribute annotation. .NET binds an XML attribute to a property.

Example 16.19. Mapping a field or property to an XML attribute

//-- Java code fragment
public class UKAddress extends Address {
    @XmlAttribute
    public int exportCode;
}

//-- Schema fragment
<! XML Schema fragment -->
<xs:complexType name="ukAddress">
    <xs:complexContent>
        <xs:extension base="tns:address">
            <xs:sequence/>
            <xs:attribute name="exportCode" type="xs:int"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

// .NET auto generated code from schema
public partial class ukAddress : address
{
    private int exportCodeField;
    public int exportCode
    {
        get { return this.exportCodeField; }
        set { this.exportCodeField = value; }
    }
}

16.1.2.3. @XmlElementRefs Annotation

Guideline: @XmlElementRefs maps to a xs:choice. This binds to a property with name item in the C# class. If there is another field/property named item in the Java class, there will be a name clash that .NET will resolve by generating name. To avoid the name clash, either change the name or use customization, for example @XmlElement(name="foo").

Example 16.20. Mapping a field or property using @XmlElementRefs

//-- Java code fragment
public class PurchaseOrder {
    @XmlElementRefs({
        @XmlElementRef(name="plane", type=PlaneType.class),
        @XmlElementRef(name="auto", type=AutoType.class)})
    public TransportType shipBy;
}

@XmlRootElement(name="plane")
public class PlaneType extends TransportType {}

@XmlRootElement(name="auto")
public class AutoType extends TransportType { }

@XmlRootElement
public class TransportType { ... }

//-- Schema fragment
<!-- XML schema generated by wsgen -->
<xs:complexType name="purchaseOrder">
    <xs:choice>
        <xs:element ref="plane"/>
        <xs:element ref="auto"/>
    </xs:choice>
</xs:complexType>

<!-- XML global elements -->
<xs:element name="plane" type="autoType" />
<xs:element name="auto" type="planeType" />

<xs:complexType name="autoType">
    <!-- content omitted - details not relevant to example -->
</xs:complexType>

</xs:complexType name="planeType">
    <!-- content omitted - details not relevant to example -->
</xs:complexType>

// .NET auto generated code from schema
public partial class purchaseOrder {
    private transportType itemField;

    [System.Xml.Serialization.XmlElementAttribute("auto", typeof(autoType), Order=4)]
    [System.Xml.Serialization.XmlElementAttribute("plane", typeof(planeType), Order=4)]
    public transportType Item
    {
        get { return this.itemField; }
        set { this.itemField = value; }
    }

public partial class planeType { ... } ;
public partial class autoType { ... } ;

16.1.3. Java Classes

A Java class can be mapped to different XML schema type and/or an XML element. The following guidelines apply to the usage of annotations at the class level.

16.1.3.1. @XmlType Annotation - Anonymous Type

Guideline: Prefer mapping class to named XML schema type rather than an anonymous type for a better .NET type binding.

The @XmlType annotation is used to customize the mapping of a Java class to an anonymous type. .NET binds an anonymous type to a .NET class - one per reference to the anonymous type. Thus, each Java class mapped to an anonymous type can generate multiple classes on the .NET client.

Example 16.21. Mapping a Java class to an anonymous type using @XmlType

//-- Java code fragment
public class PurchaseOrder {
    public java.util.List<Item> item;
}
@XmlType(name="")
public class Item {
    public String productName;
    ...
}

//-- Schema fragment
<xs:complexType name="purchaseOrder">
    <xs:sequence>
        <xs:element name="item">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="productName" type="xs:string"/>
                </xs:sequence>
            </xs:complexType
>        </xs:element>
    </xs:sequence>
</xs:complexType>

// C# code generated by svcutil
public partial class purchaseOrder
{
    private purchaseOrderItem[] itemField;
    System.Xml.Serialization.XmlElementAttribute("item",
        Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true, Order=0)]
    public purchaseOrderItem[] item
    {
        get {
            return this.itemField;
        }

        set {
            this.itemField = value;
        }
    }
}

// .NET auto generated code from schema
public partial class purchaseOrderItem
{
    private string productNameField;
    public string productName {
        get { return this.productNameField; }
        set { this.productNameField = value; }
    }
}

16.1.3.2. @XmlType Annotation - xs:all

Guideline: Avoid using XmlType(propOrder=:{}).

@XmlType(propOrder={}) maps a Java class to an XML Schema complex type with xs:all content model. Since XML Schema places severe restrictions on xs:all, the use of @XmlType(propOrder={}) is therefore not recommended. So, the following example shows the mapping of a Java class to xs:all, but the corresponding .NET code generated by svcutil is omitted.

Example 16.22. Mapping a class to xs:all using @XmlType

//-- Java code fragment
@XmlType(propOrder={})
public class USAddress {
    public String name;
    public String street;
}

//-- Schema fragment
<xs:complexType name="USAddress">
    <xs:all>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="street" type="xs:string"/>
        ...
    </xs:all>
</xs:complexType>

16.1.3.3. @XmlType Annotation - Simple Content

Guideline: A class can be mapped to a complexType with a simpleContent using @XmlValue annotation. .NET binds the Java property annotated with @XmlValue to a property with name "value".

Example 16.23. Class to complexType with simpleContent

//-- Java code fragment
public class InternationalPrice
{
    @XmlValue
    public java.math.BigDecimal price;

    @XmlAttribute public String currency;
}

//-- Schema fragment
<xs:complexType name="internationalPrice">
    <xs:simpleContent>
        <xs:extension base="xs:decimal">
            xs:attribute name="currency" type="xs:string"/>
        </xs:extension>
    </xs:simpleContent>
 </xs:complexType>

// .NET auto generated code from schema
public partial class internationalPrice
{
    private string currencyField;
    private decimal valueField;
    public string currency
    {
        get { return this.currencyField; }
        set { this.currencyField = value;}
    }

    public decimal Value
    {
        get { return this.valueField; }
        set { this.valueField = value;}
    }
}

16.1.4. Open Content

Jakarta XML Binding supports the following annotations for defining open content. (Open content allows content not statically defined in XML schema to occur in an XML instance):

  • The @XmlAnyElement annotation maps to xs:any, which binds to the .NET type System.Xml.XmlElement[].

  • The @XmlAnyAttribute annotation maps to xs:anyAttribute, which binds to the .NET type System.Xml.XmlAttribute[].

Example 16.24. Using @XmlAnyElement for open content

//-- Java code fragment
@XmlType(propOrder={"name", "age", "oc"})
public class OcPerson {
    @XmlElement(required=true)
    public String name;
    public int age;

    // Define open content
    @XmlAnyElement
    public List<Object> oc;
}

//-- Schema fragment
<xs:complexType name="ocPerson">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="age" type="xs:int"/>
        <xs:any minOccurs="0" maxOccurs="unbounded">
    </xs:sequence>
</xs:complexType>

// .NET auto generated code from schema
public class ocPerson
{
    private String name;
    private int age;
    private System.Xml.XmlElement[] anyField;<

    public String name { ... }
    public int age { ... }

    public System.Xml.XmlElement[] Any {
    {
        get { return this.anyField; }
        set { this.anyField = value; }
    }
}

Example 16.25. Using @XmlAnyAttribute for open content

//-- Java code fragment
@XmlType(propOrder={"name", "age"}
public class OcPerson {
    public String name;
    public int age;

    // Define open content
    @XmlAnyAttribute
    public java.util.Map oc;
}

//-- Schema fragment
<xs:complexType name="ocPerson">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="age" type="xs:int"/>
    </xs:sequence>
    <xs:anyAttribute/>
</xs:complexType>

// .NET auto generated code from schema
public class ocPerson
{
    private String name;
    private double age;
    private System.Xml.XmlAttribute[] anyAttrField;<

    public String name { ... }
    public double age { ... }

    public System.Xml.XmlElement[] anyAttr {
    {
        get { return this.anyAttrField; }
        set { this.anyAttrField = value; }
    }
}

16.1.5. Enum Type

Guideline: A Java enum type maps to an XML schema type constrained by enumeration facets. This, in turn, binds to the .NET type enum type.

Example 16.26. Java enumxs:simpleType (with enum facets) ↔ .NET enum

//-- Java code fragment
public enum USState {MA, NH}

//-- Schema fragment
<xs:simpleType name="usState">
    <xs:restriction base="xs:string">
        <xs:enumeration value="NH" />
        <xs:enumeration value="MA" />
    </xs:restriction>
</xs:simpleType>

// .NET auto generated code from schema
public enum usState { NH, MA }

16.1.6. Package-level Annotations

The following package-level Jakarta XML Binding annotations are relevant from an interoperability standpoint:

  • @XmlSchema - customizes the mapping of package to XML namespace.

  • @XmlSchemaType - customizes the mapping of XML schema built-in type. The @XmlSchemaType annotation can also be used at the property/field level, as was seen in the example XMLGregorianCalendar Type.

16.1.6.1. @XmlSchema Annotation

A package is mapped to an XML namespace. The following attributes of the XML namespace can be customized using the @XmlSchema annotation parameters:

  • elementFormDefault using @XmlSchema.elementFormDefault()

  • attributeFormDefault using @XmlSchema.attributeFormDefault()

  • targetNamespace using @XmlSchema.namespace()

  • Associate namespace prefixes with the XML namespaces using the @XmlSchema.ns() annotation

These XML namespace attributes are bound to .NET serialization attributes (for example, XmlSerializer attributes).

16.1.6.2. Not Recommended Annotations

Any Jakarta XML Binding annotation can be used, but the following are not recommended:

  • The jakarta.xml.bind.annotation.XmlElementDecl annotation is used to provide complete XML schema support.

  • The @XmlID and @XmlIDREF annotations are used for XML object graph serialization, which is not well supported.

16.2. Web Service - Start from WSDL

The following guidelines apply when designing a Java web service starting from a WSDL:

  1. If the WSDL was generated by DataContractSerializer, enable Jakarta XML Binding customizations described in Customizations for WCF Service WSDL. The rationale for the Jakarta XML Binding customizations is described in the same section.

  2. If the WSDL is a result of contract first approach, verify that the WSDL can be processed by either the DataContractSerializer or XmlSerializer mechanisms.

    The purpose of this step is to ensure that the WSDL uses only the set of XML schema features supported by Jakarta XML Binding or .NET serialization mechanisms. Jakarta XML Binding was designed to support all the XML schema features. The WCF serialization mechanisms, DataContractSerializer and XmlSerializer, provide different levels of support for XML schema features. Thus, the following step will ensure that the WSDL/schema file can be consumed by the WCF serialization mechanisms.

    svcutil wsdl-file

    The svcutil.exe tool, by default, uses DataContractSerializer but falls back to XmlSerializer if it encounters an XML schema construct not supported by XmlFormatter.

16.3. Customizations for WCF Service WSDL

When developing either a Java web service or a Java client from a WCF service WSDL generated using DataContractSerializer, the following Jakarta XML Binding 2.0 customizations are useful and/or required.

  • generateElementProperty attribute

  • mapSimpleTypeDef attribute

The following sections explain the use and rationale of these customizations.

16.3.1. generateElementProperty Attribute

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.

16.3.1.1. Default Binding

The following is the default binding of an optional (minOccurs="0") and nillable(nillable="true") element:

Example 16.27. 

<!-- 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>
...

Example 16.28. 

// 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:

Example 16.29. 

<!-- 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.

16.3.1.2. Customized Binding

When generateElementProperty is false, the binding is changed as follows:

Example 16.30. 

// set Jakarta XML Binding 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.

Jakarta XML Binding 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>:

Example 16.31. 

<jaxb:bindings version="3.0"
               xmlns:jaxb="https://jakarta.ee/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>
    ...

Note

The generateElementProperty attribute was introduced in Jakarta XML Binding 2.1.

16.3.1.3. mapSimpleTypeDef Attribute

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 CLR to XML Schema Type Mapping.

Table 16.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 CLR to XML Schema Type Mapping. Furthermore, Jakarta XML Binding 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 CLR to XML Schema Type Mapping are used in an xsi:type construct, they won't be preserved by default across an unmarshal followed by marshal operation. For example:

Example 16.32. 

// 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:

    Example 16.33. 

    <objvalue xsi:type="xs:unsignedShort"/>

  • Jakarta XML Binding unmarshaller unmarshals the value as an instance of int and assigns it to parameter objvalue.

  • The objvalue is marshalled back by Jakarta XML Binding marshaller with an xsi:type of xs:int.

    Example 16.34. 

    <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:

Example 16.35. 

//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:

    Example 16.36. 

    <objvalue xsi:type="xs:unsignedShort"/>

  • Jakarta XML Binding unmarshaller unmarshals the value as an instance of UnsignedShort and assigns it to parameter objvalue.

  • The objvalue is marshalled back by Jakarta XML Binding marshaller with an xsi:type of xs:int.

    Example 16.37. 

    <objvalue xsi:type="xs:unsignedShort"/>

Guideline: Use the mapSimpleTypedef customization where roundtripping of XML Schema types in CLR to XML Schema Type Mapping are used in xsi:type. However, it is preferable to avoid the use of CLR types listed in CLR to XML Schema Type Mapping since they are specific to .NET platform.

The syntax of the mapSimpleTypeDef customization is shown below.

Example 16.38. 

<jaxb:bindings version="3.0"
               xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jaxb:bindings schemaLocation="schema-importedby-wcfsvcwsdl">
        <jaxb:globalBindings mapSimpleTypeDef="true"/>
    </jaxb:bindings>
    ....

16.4. Developing a Microsoft .NET Client

This section describes how to develop a .NET client that uses data binding.

To Develop a Microsoft .NET Client

Perform the following steps to generate a Microsoft .NET client from a Java web service WSDL file.

  1. Generate WCF web service client artifacts using the svcutil.exe tool:

    svcutil.exe java-web-service-wsdl

    svcutil.exe has the following options for selecting a serializer:

    • svcutil.exe /serializer:auto (default)

    • svcutil.exe /serializer:DataContractSerializer

    • svcutil.exe /serializer:XmlSerializer

    It is recommended that you use the default option, /serializer:auto. This option ensures that svcutil.exe falls back to XmlSerializer if an XML schema construct is used that cannot be processed by DataContractSerializer.

    For example, in the following class the field price is mapped to an XML attribute that cannot be consumed by DataContractSerializer.

    Example 16.39. 

    public class POType {
        @jakarta.xml.bind.annotation.XmlAttribute
        public java.math.BigDecimal price;
    }
    
    <!-- XML schema fragment -->
    <xs:complexType name="poType">
        <xs:sequence/>
        <xs:attribute name="price" type="xs:decimal"/>
    </xs:complexType>

  2. Develop the .NET client using the generated artifacts.

16.5. BP 1.1 Conformance

Jakarta XML Web Services enforces strict Basic Profile 1.1 compliance. In one situation, the .NET framework does not enforce strict BP 1.1 semantics, and their usage can lead to interoperability problems.

In rpclit mode, BP 1.1, R2211 disallows the use of xsi:nil in part accessors: An ENVELOPE described with an rpc-literal binding MUST NOT have the xsi:nil attribute with a value of "1" or "true" on the part accessors.

From a developer perspective this means that in rpclit mode, Jakarta XML Web Services does not allow a null to be passed in a web service method parameter.

Example 16.40. 

//Java Web method
public byte[] retByteArray(byte[] inByteArray) {
    return inByteArray;
}

Example 16.41. 

<!-- In rpclit mode, the above Java web service method will throw an exception
  if the following XML instance with xsi:nil is passed by a .NET client.-->
  <RetByteArray xmlns="http://tempuri.org/">
      <inByteArray a:nil="true" xmlns=""
          xmlns:a="http://www.w3.org/2001/XMLSchema-instance"/>
  </RetByteArray>

Back to the top