Customizing CodeGen code generation

You can supply a customization file to CodeGen to control many aspects of the code and binding generation. Two basic customization examples are included in the samples/codegen directory. This page discusses the first customization example (custom1.xml), which demonstrates how you can easily eliminate unnecessary classes from the generated code.

To pass the customization file to CodeGen you need to use a '-c' command line parameter, followed by the actual path to the customization file. The supplied Ant build.xml file has a 'custgen1' target for this purpose:

  <!-- generate using first customizations -->
  <target name="custgen1" depends="check-runtime,clean">
    
    <echo message="Running code generation from schema"/>
    <java classname="org.jibx.schema.codegen.CodeGen" fork="yes"
        classpathref="classpath" failonerror="true">
      <arg value="-t"/>
      <arg value="gen/src"/>
      <arg value="-c"/>
      <arg value="custom1.xml"/>
      <arg value="otasubset/OTA_AirLowFareSearch*.xsd"/>
    </java>
    
  </target>

Aside from the '-c' command line parameter and the actual customization file path, this is identical to the 'codegen' target used for the first example.

First customizations

Here's the actual content of the custom1.xml customizations file used in this example:

<schema-set prefer-inline="true" generate-all="false" package="org.ota.air">
  <schema name="OTA_AirLowFareSearchRQ.xsd" includes="OTA_AirLowFareSearchRQ"/>
  <schema name="OTA_AirLowFareSearchRS.xsd" includes="OTA_AirLowFareSearchRS"/>
</schema-set>

The attributes on the <schema-set> root element tell CodeGen to inline definitions where possible in the generated code (prefer-inline="true"), to only generate the required schema definitions, rather than all the schema definitions (generate-all="false"), and to use the Java package org.ota.air(package="org.ota.air").

The nested <schema> elements each identify a particular schema, and tell CodeGen which global definitions from that schema should be included in the code generation. This is crucial when you use the generate-all="false" customization, since only those schema definitions you specify to be included, and the schema components used by the specified definitions, will be generated. If you leave out the two <schema> lines from the above customization file, CodeGen will happily run and generate a model with 0 classes - certainly efficient, but probably not what you want to use.

Generated code

Run the 'custgen1' target and see the gen/src directory (or use the 'custom1' target to generate and compile the code, run the binding compiler, and finally run a supplied test program which roundtrips the sample documents from the samples directory). The number of generated top-level classes this time is only 33, with 104 inner classes, for a total of 137 - just a third of the 414 classes in the default model. CodeGen is able to simplify the model in this way because many of the global definitions from included schemas are not actually used by the <OTA_AirLowFareSearchRQ> and <OTA_AirLowFareSearchRS> elements, and with the customizations it only generates what's needed for the schema representation of these two elements.

Here's a sample of the generated code (reformated for a reasonable page width, and this time leaving out the methods), showing portions of the main classes used for the response message:

/** 
 * 
 The Low Fare Search Response message contains a number of 'Priced Itinerary'
 options. Each includes:
 - A set of available flights matching the client's request.
 - Pricing information including taxes and full fare breakdown for each passenger
 type
 - Ticketing information
 - Fare Basis Codes and the information necessary to make a rules entry.
 This message contains similar information to a standard airline CRS or GDS Low
 Fare Search Response message.
 
 * 
 * Schema fragment(s) for this class:
 * <pre>
 * &lt;xs:element xmlns:ns="http://www.opentravel.org/OTA/2003/05"
       xmlns:xs="http://www.w3.org/2001/XMLSchema" name="OTA_AirLowFareSearchRS">
 *   &lt;xs:complexType>
 *     &lt;xs:sequence>
 *       &lt;xs:choice>
 *         &lt;xs:sequence>
 *           &lt;xs:element type="ns:SuccessType" name="Success"/>
 *           &lt;xs:element type="ns:WarningsType" name="Warnings"
                 minOccurs="0">
 *             &lt;!-- Reference to inner class Warnings -->
 *           &lt;/xs:element>
 *           &lt;xs:element type="ns:PricedItinerariesType"
                 name="PricedItineraries"/>
 *         &lt;/xs:sequence>
 *         &lt;xs:element type="ns:ErrorsType" name="Errors"/>
 *       &lt;/xs:choice>
 *     &lt;/xs:sequence>
 *     &lt;xs:attributeGroup ref="ns:OTA_PayloadStdAttributes"/>
 *   &lt;/xs:complexType>
 * &lt;/xs:element>
 * 
 * &lt;xs:complexType xmlns:ns="http://www.opentravel.org/OTA/2003/05"
       xmlns:xs="http://www.w3.org/2001/XMLSchema" name="SuccessType"/>
 * 
 * &lt;xs:complexType xmlns:ns="http://www.opentravel.org/OTA/2003/05"
       xmlns:xs="http://www.w3.org/2001/XMLSchema" name="PricedItinerariesType">
 *   &lt;xs:sequence>
 *     &lt;xs:element name="PricedItinerary" maxOccurs="unbounded">
 *       &lt;!-- Reference to inner class PricedItinerary -->
 *     &lt;/xs:element>
 *   &lt;/xs:sequence>
 * &lt;/xs:complexType>
 * 
 * &lt;xs:complexType xmlns:ns="http://www.opentravel.org/OTA/2003/05"
       xmlns:xs="http://www.w3.org/2001/XMLSchema" name="ErrorsType">
 *   &lt;xs:sequence>
 *     &lt;xs:element type="ns:ErrorType" name="Error" maxOccurs="99">
 *       &lt;!-- Reference to inner class _Error -->
 *     &lt;/xs:element>
 *   &lt;/xs:sequence>
 * &lt;/xs:complexType>
 * </pre>
 */
public class OTAAirLowFareSearchRS
{
    private int choiceSelect = -1;
    private static final int SUCCESS_CHOICE = 0;
    private static final int ERROR_CHOICE = 1;
    private Warnings warnings;
    private List<PricedItinerary> pricedItineraryList =
        new ArrayList<PricedItinerary>();
    private List<_Error> errorList = new ArrayList<_Error>();
    private OTAPayloadStdAttributes OTAPayloadStdAttributes;
    ...
    
    /** 
     *  Itinerary with pricing information.
     * 
     * Schema fragment(s) for this class:
     * <pre>
     * &lt;xs:element xmlns:ns="http://www.opentravel.org/OTA/2003/05"
           xmlns:xs="http://www.w3.org/2001/XMLSchema" name="PricedItinerary"
           maxOccurs="unbounded">
     *   &lt;xs:complexType>
     *     &lt;xs:complexContent>
     *       &lt;xs:extension base="ns:PricedItineraryType">
     *         &lt;xs:attribute type="xs:integer" use="optional"
                   name="OriginDestinationRefNumber"/>
     *       &lt;/xs:extension>
     *     &lt;/xs:complexContent>
     *   &lt;/xs:complexType>
     * &lt;/xs:element>
     * 
     * &lt;xs:complexType xmlns:ns="http://www.opentravel.org/OTA/2003/05"
           xmlns:xs="http://www.w3.org/2001/XMLSchema" name="PricedItineraryType">
     *   &lt;xs:sequence>
     *     &lt;xs:element type="ns:AirItineraryType" name="AirItinerary"
               minOccurs="0">
     *       &lt;!-- Reference to inner class AirItinerary -->
     *     &lt;/xs:element>
     *     &lt;xs:element type="ns:AirItineraryPricingInfoType"
               name="AirItineraryPricingInfo" minOccurs="0">
     *       &lt;!-- Reference to inner class AirItineraryPricingInfo -->
     *     &lt;/xs:element>
     *     &lt;xs:element type="ns:FreeTextType" name="Notes" minOccurs="0"
               maxOccurs="5"/>
     *     &lt;xs:element name="TicketingInfo" minOccurs="0">
     *       &lt;!-- Reference to inner class TicketingInfo -->
     *     &lt;/xs:element>
     *   &lt;/xs:sequence>
     *   &lt;xs:attribute type="xs:string" use="required"
             name="SequenceNumber"/>
     * &lt;/xs:complexType>
     * </pre>
     */
    public static class PricedItinerary
    {
        private AirItinerary airItinerary;
        private AirItineraryPricingInfo airItineraryPricingInfo;
        private List<FreeTextType> noteList = new ArrayList<FreeTextType>();
        private TicketingInfo ticketingInfo;
        private String sequenceNumber;
        private BigInteger originDestinationRefNumber;
        ...

If you compare this code with the Example 1 generated code you'll see that much of the schema structure has been inlined in the new version. In cases where part of the schema definition has been converted to a separate class the schema fragment in the class JavaDoc references that class, to make it easier to relate the class structure to the schema.

Schema components used in more than one place within the portions of the schema being generated are always generated as top-level classes. Components only used in a single place are, by default, generated as inner classes of the class matching the reference. The Example 1 generated code showed a trivial example of this, where the PricedItinerariesType class had a PricedItinerary inner class. The customizations used for the current example create a lot more inner classes, in some cases nested several levels deep. This use of inner classes is generally convenient when working with a data model since it keeps references local to the containing definition whereever possible,but can be changed by using the use-inner customization attribute.

Next: Example 3: More extensive customizations