Skip to main content

skip to main content

developerWorks  >  Java technology | XML | Open source  >

JiBX 1.2, Part 2: XML schema to Java code

Generate cleaner, customized Java code from XML schema

developerWorks
Go to the previous pagePage 7 of 14 Go to the next page

Document options
PDF format - Fits A4 and Letter

PDF - Fits A4 and Letter
222 KB (36 pages)

Get Adobe® Reader®

Sample code


My developerWorks needs you!

Connect to your technical community


Rate this tutorial

Help us improve this content


Customizing the data model

An example earlier in this tutorial showed some simple CodeGen customizations. Now that you've seen how CodeGen handles the HR-XML TimeCard schema with default settings, it's time to look into some more powerful customizations.

Customizing the data model

The data-model code generated by CodeGen using default settings has some weaknesses. For one thing, the schema type names all end with Type, and this carries over to the corresponding generated class names, making the names longer than necessary. The package name generated from the schema namespace, org.hrxml.ns, is reasonable, but it would be better to have a package name that indicates the data model is specifically for TimeCard documents.

Listing 11 shows another awkward aspect of the generated data-model classes, in which a java.math.BigInteger is used to represent an xs:integer type. This is the most accurate representation for xs:integer using standard Java classes, but BigInteger is awkward to use compared to simple int primitive or java.lang.Integer object types. Unfortunately, schemas are often written using the xs:integer type even when xs:int would be more appropriate, so developers can get stuck with BigInteger values in the generated code. That's definitely the case here, where the actual values allowed for GenderCode are all single digits (as shown by the original schema fragment at the bottom of the listing).


Listing 11. xs:integer generation example
/**
 * Schema fragment(s) for this class:
 * <pre>
 * <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:integer" 
 *    name="GenderCode"/>
 * </pre>
 */
public class GenderCode
{
    private BigInteger genderCode;

    /**
     * Get the 'GenderCode' element value.
     *
     * @return value
     */
    public BigInteger getGenderCode() {
        return genderCode;
    }

    /**
     * Set the 'GenderCode' element value.
     *
     * @param genderCode
     */
    public void setGenderCode(BigInteger genderCode) {
        this.genderCode = genderCode;
    }
}

  <xsd:simpleType name="GenderCodeType">
    <xsd:annotation>
      <xsd:documentation>Must conform to ISO 5218 - Representation of Human Sexes 
         (0 - Not Known; 1 - Male; 2 - Female; 9 - Not specified)</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:integer">
      <xsd:pattern value="[0129]"/>
    </xsd:restriction>
  </xsd:simpleType>

Listing 12 shows a customization to improve these aspects of the generated data model. The package="org.hrxml.timecard" attribute gives the Java package to be used for the generated classes. The type-substitutions="xs:integer xs:int" attribute defines schema type substitutions to be applied by CodeGen, in this case using the xs:int type wherever xs:integer is referenced in the schema. You can define multiple pairs of substitutions by just adding more type names to the list, using spaces as separators between the pairs as well as between the type names in each pair.

The nested name-converter element configures the handling of XML names being converted to Java names. In this case, the strip-suffixes="Type" attribute tells CodeGen to remove Type wherever it occurs at the end of a name. You can provide multiple alternatives to be stripped with this attribute, as a space-separated list. You can also use a strip-prefixes attribute to remove unnecessary leading text from names, along with several other forms of customizations. It's even possible to replace the default name conversion class with your own implementation, if you want to do something really special in the name conversions. For the full details on these name-converter options, see the JiBX CodeGen documentation.

Finally, the nested class-decorator element adds a decorator to the code generation sequence. In this case, the decorator is a predefined one provided as part of the CodeGen distribution, which adds useful support methods for collection values. Any configured code generation decorators are called in sequence by CodeGen as it constructs the source code for data model classes, and have the opportunity to modify or add to the field, method, and class constructs generated by CodeGen. Each of these constructs is passed to the decorator as an Abstract Syntax Tree (AST) component, using the Eclipse AST implementation. The supplied decorators (including the org.jibx.schema.codegen.extend.CollectionMethodsDecorator decorator used here to add methods, and a org.jibx.schema.codegen.extend.SerializableDecorator used to add the java.io.Serializable interface and optionally a version id to data model classes) provide examples of working with the Eclipse AST to extend CodeGen, so the source code of these classes is a great starting point for writing your own decorators.


Listing 12. TimeCard customizations example
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
    type-substitutions="xs:integer xs:int">
  <name-converter strip-suffixes="Type"/>
  <class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
</schema-set>

You can try out the Listing 12 customization using the custgen1 Ant target, or use the custom1 target to run the complete sequence of generate, compile, bind, and test. Listing 13 shows the result of applying the customizations. The TimeCardType class name has changed to just TimeCard, and in addition to the List get and set methods there are now added size, add, indexed get, and clear methods. In the GenderCode class, the BigInteger reference has been replaced with a simple int primitive type.


Listing 13. Customized data model
/** 
 * Schema fragment(s) for this class:
 * <pre>
 * ...
 * </pre>
 */
public class TimeCard
{
    ...
    private List<ReportedTime> reportedTimeList = new ArrayList<ReportedTime>();
    ...
    /** 
     * Get the list of 'ReportedTime' element items.
     * 
     * @return list
     */
    public List<ReportedTime> getReportedTimes() {
        return reportedTimeList;
    }

    /** 
     * Set the list of 'ReportedTime' element items.
     * 
     * @param list
     */
    public void setReportedTimes(List<ReportedTime> list) {
        reportedTimeList = list;
    }

    /** 
     * Get the number of 'ReportedTime' element items.
     * @return count
     */
    public int sizeReportedTime() {
        return reportedTimeList.size();
    }

    /** 
     * Add a 'ReportedTime' element item.
     * @param item
     */
    public void addReportedTime(ReportedTime item) {
        reportedTimeList.add(item);
    }

    /** 
     * Get 'ReportedTime' element item by position.
     * @return item
     * @param index
     */
    public ReportedTime getReportedTime(int index) {
        return reportedTimeList.get(index);
    }

    /** 
     * Remove all 'ReportedTime' element items.
     */
    public void clearReportedTime() {
        reportedTimeList.clear();
    }
    ...
}
/** 
 * Schema fragment(s) for this class:
 * <pre>
 * &lt;xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int"
 *   name="GenderCode"/>
 * </pre>
 */
public class GenderCode
{
    private int genderCode;

    /** 
     * Get the 'GenderCode' element value.
     * 
     * @return value
     */
    public int getGenderCode() {
        return genderCode;
    }

    /** 
     * Set the 'GenderCode' element value.
     * 
     * @param genderCode
     */
    public void setGenderCode(int genderCode) {
        this.genderCode = genderCode;
    }
}



Back to top


Eliminating unused definitions

In the first customization example, using the original simple schema, you saw how to control the type definitions included in the generated data model by using generate-all="false" to disable generating every global definition and an includes list to force generating specific definitions. Listing 14 shows a modified customization for the TimeCard schema that adds these attributes, with only the TimeCard element to be included in the generated data model (along with everything used by the TimeCard representation, of course).


Listing 14. Customization with only TimeCard components
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema" package="org.hrxml.timecard"
    type-substitutions="xs:integer xs:int" generate-all="false">
  <name-converter strip-suffixes="Type"/>
  <class-decorator class="org.jibx.schema.codegen.extend.CollectionMethodsDecorator"/>
  <schema name="TimeCard.xsd" includes="TimeCard"/>
</schema-set>

You can use the custgen2 Ant target to try this customization with CodeGen, or use the custom2 target to run the complete sequence of generate, compile, bind, and test. This change reduces the number of top-level classes in the data model from 15 to 10 — not a bad start on simplifying the data model.



Back to top



Go to the previous pagePage 7 of 14 Go to the next page