Generating Java Code from XSD

Previous Menu Next

Generating Java Code from XML Schemas

Let's look again at our Purchase.xsd file from previously, which is reproduced here:

   <xsd:element name="purchase" type="PurchaseRecord"/>

   <xsd:complexType name="PurchaseRecord">
      <xsd:sequence>
         <xsd:element name="customer" type="CustomerType" maxOccurs="1"/>
         <xsd:element name="store" type="xsd:string" maxOccurs="1"/>
         <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="item" type="xsd:string"/>
            <xsd:element name="price" type="xsd:float"/>
         </xsd:sequence>
      </xsd:sequence>
   </xsd:complexType>

   <xsd:complexType name="CustomerType">
      <xsd:simpleContent>
         <xsd:extension base="xsd:string">
            <xsd:attribute name="number" type="xsd:integer"/>
         </xsd:extensiion>
      </xsd:simpleContent>
   </xsd:complexType>
   

To generate Java code from this schema, we could use the following XBinder command:

        
         > xbinder Purchase.xsd -java -xml -pkgname sample.purchase
        
       

The -pkgname is not required, but it can be useful for controlling the name of the package with which the generated classes are associated. Without it, the package name would default to the name of the current directory. So, for example, if your current directory is "mydocs", the package for the generated code will also be called "mydocs". Also note that the Java generation creates directories for each component of the package name. So for the example command above a directory named "sample" in the current directory would be created, and then a directory named "purchase" in the directory "sample" would be created. The generated code would be placed into this "purchase" directory.

This command will produce five files, as follows:

FilePurpose
_Purchase.javaContains some miscellaneous definitions that may be used by other generated code.
CustomerType.java Contains the definitions for the CustomerType class; i.e., the class that corresponds to the complex type that defines the <customer> element within a PurchaseRecord.
Purchase_CC.java Contains the definitions for the Purchase control class; i.e., the class that corresponds to the <purchase> global element that's declared at the top of the .xsd file (though it doesn't have to be) and that encapsulates everything else.
PurchaseRecord.java Contains the definitions for the PurchaseRecord class; i.e., the class that corresponds to the complex type that defines the global <purchase> element.
PurchaseRecord_3.java Contains the definitions to encapsulate and manage the items that might repeat within a PurchaseRecord. The number 3 is used simply because the sequence defining these potentially repeating items is the third item in the PurchaseRecord.

 

Let's look a little more closely at some of the classes generated for the element declarations in the .xsd file. We'll look first at the code that gets generated for the CustomerType. Here is the schema declaration again:

      <xsd:complexType name="CustomerType">
      <xsd:simpleContent>
         <xsd:extension base="xsd:string">
            <xsd:attribute name="number" type="xsd:integer"/>
         </xsd:extensiion>
      </xsd:simpleContent>
   </xsd:complexType>
   

The defining code that gets generated in CustomerType.java looks like this:

   public class CustomerType extends com.objsys.xbinder.runtime.XBComplexType
   {

      public static final QName XSD_TYPE = new QName("http://www.example.org/Purchase",
         "CustomerType");

      //attribute fields
      protected int number;
      protected boolean _set_number = false;

      //Empty element indicator.  This variable may stay false
      //even if an element is empty because emptiness is
      //sometimes detected by another means.
      protected boolean elementEmpty = false;

      //content fields
      protected String value;

      //attribute methods

      public int getNumber() {
         if (!_set_number)throw new XBException("field number not set");
         return this.number;
      }

      public boolean isSetNumber() {
         return _set_number;
      }

      public void setNumber(int value) {
         this.number = value;
         _set_number = true;
      }

      public void setNumber() {
         _set_number = false;
      }

      //content methods

      public String getValue() {
         if (this.value == null)throw new XBException("field value not set");
         return this.value;
      }

      public boolean isSetValue() {
         return this.value != null;
      }

      public void setValue(String value) {
         if ( value == null )  {
            this.value = null;
         }
         else  {
            this.value = value;
         }
      }

      // Other methods to manage the instance, such as encoding and
      // decoding methods, follow after this point, but are not reproduced.
   }

Take note of the following:

  • The complexType definition in the .xsd file results in a class definition in the .java file.
  • Attributes that may appear in an element instance each have a boolean defined in the class to indicate whether they're present.
  • The base value of the element is represented as a string member of the class.
  • The value of the attribute is represented as an integer member of the class.
  • The generated class extends a class called XBComplexType in a package named com.objsys.xbinder.runtime. This package and class are part of the XBinder Java runtime components, which come with the product.

Now let's look at the code that gets generated for the PurchaseRecord, which appears like this in the schema:

   <xsd:complexType name="PurchaseRecord">
      <xsd:sequence>
         <xsd:element name="customer" type="CustomerType" maxOccurs="1"/>
         <xsd:element name="store" type="xsd:string" maxOccurs="1"/>
         <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="item" type="xsd:string"/>
            <xsd:element name="price" type="xsd:float"/>
         </xsd:sequence>
      </xsd:sequence>
   </xsd:complexType>

The defining code that gets generated in PurchaseRecord.java looks like this:

   public class PurchaseRecord extends com.objsys.xbinder.runtime.XBComplexType
   {

      public static final QName XSD_TYPE = new QName("http://www.example.org/Purchase",
         "PurchaseRecord");

      //particleInfo[i] provides information for the ith particle.
      //For elements, it is a QName, identifying the expected element.
      //For element wildcards, it is a String[], listing the allowed namespaces
      protected static Object[] particleInfo = {
         new QName("http://www.example.org/Purchase","customer"),
         new QName("http://www.example.org/Purchase","store")
      };

      //attribute fields

      //Empty element indicator.  This variable may stay false
      //even if an element is empty because emptiness is
      //sometimes detected by another means.
      protected boolean elementEmpty = false;

      //content fields
      protected sample.purchase.CustomerType customer;
      protected String store;
      protected java.util.List<sample.purchase.PurchaseRecord_3> purchaseRecord_3;


      //attribute methods

      //content methods

      public sample.purchase.CustomerType getCustomer() {
         if (this.customer == null)
            throw new XBException("field customer not set");
         return this.customer;
      }

      public boolean isSetCustomer() {
         return this.customer != null;
      }

      public void setCustomer(sample.purchase.CustomerType value) {
         if ( value == null )  {
            this.customer = null;
         }
         else  {
            this.customer = value;
         }
      }

      public String getStore() {
         if (this.store == null)throw new XBException("field store not set");
         return this.store;
      }

      public boolean isSetStore() {
         return this.store != null;
      }

      public void setStore(String value) {
         if ( value == null )  {
            this.store = null;
         }
         else  {
            this.store = value;
         }
      }

      public java.util.List<sample.purchase.PurchaseRecord_3> getPurchaseRecord_3()
      {
         if (this.purchaseRecord_3 == null) {
            this.purchaseRecord_3 = new ArrayList<sample.purchase.PurchaseRecord_3>();
         }
         return this.purchaseRecord_3;
      }

      public boolean isSetPurchaseRecord_3() {
         return this.purchaseRecord_3 != null;
      }

      public void unsetPurchaseRecord_3() {
         this.purchaseRecord_3 = null;
      }

      // Other methods to manage the instance, such as encoding and
      // decoding methods, follow after this point, but are not reproduced.
   }

Take note of the following:

  • The customer element in the purchase record is simply a member of type CustomerType, the definition for which we just examined.
  • The store element is simply a string member of the class.
  • The collection of items and prices, which might repeat within an instance, is represented by a list of instances of another class called PurchaseRecord_3. Let's look now at the definition of PurchaseRecord_3.

XBinder generates a separate class for the elements within the PurchaseRecord that might repeat. This class, called PurchaseRecord_3 (3 simply because it's the third element in the PurchaseRecord) is defined as follows in PurchaseRecord_3.java:

   public class PurchaseRecord_3
   {

      public static final QName XSD_TYPE = new QName("http://www.example.org/Purchase",
         "PurchaseRecord_3");

      //particleInfo[i] provides information for the ith particle.
      //For elements, it is a QName, identifying the expected element.
      //For element wildcards, it is a String[], listing the allowed namespaces
      protected static Object[] particleInfo = {
         new QName("http://www.example.org/Purchase","item"),
         new QName("http://www.example.org/Purchase","price")
      };

      public static boolean acceptsElem(String elemNs, String elemLocalName) {
         if (XBQualifiedName.namesMatch(
            (QName)particleInfo[0], elemNs, elemLocalName)) return true;
         return false;
      }

      //Empty element indicator.  This variable may stay false
      //even if an element is empty because emptiness is
      //sometimes detected by another means.
      protected boolean elementEmpty = false;

      //content fields
      protected String item;
      protected float price;

      //content methods

      public String getItem() {
         if (this.item == null)throw new XBException("field item not set");
         return this.item;
      }

      public boolean isSetItem() {
         return this.item != null;
      }

      public void setItem(String value) {
         if ( value == null )  {
            this.item = null;
         }
         else  {
            this.item = value;
         }
      }

      public float getPrice() {
         return this.price;
      }

      public void setPrice(float value) {
         this.price = value;
      }

      // Other methods to manage the instance, such as encoding and
      // decoding methods, follow after this point, but are not reproduced.
   }

Here we see that the item element is simply expressed as a string class member, and the price element is a float class member.

Previous Menu Next