The WSIT Tutorial

Data Types

This section covers the following topics:

Primitives and Wrappers

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

Example: 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");

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

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:

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

Example: @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:@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";

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.

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

Binary Types

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

JAXB 2.0 provides the annotation @XmlMimeType, which supports specifying the content type, but .NET ignores this information.

Example: 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: 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());
}

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

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: 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();

Typed Variables

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

Example: 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; }
    }
}

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.

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 JAXB marshaller will always marshal a null value using xsi:nil.

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

//--- JAXB 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; }    
    }
}

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, JAXB will marshal a null value within the List<Integer> as a value that is absent from the XML instance.

Example: 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; }    
    }
}

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

Array Types

Example: 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; }
    }
}