Data Contracts, XSDs and Redundant List Wrappers – XEW Plugin to rescue


This article talks about problem associated with defining List Complex Types, how can we overcome this problem using XEW Plugin and the benefits.

In Service Oriented Architecture (SOA) or MicroServices Architecture, data is exchanged between different components over the network.

Keeping in mind the INTEROPERABILITY, Data Contracts are created and shared.

Contracts either in the form of WSDL or XSDs etc are mutually agreed between the components to exchange the Structured data among them.

As part of these contracts, you may have a need to send a collection of similar data and for this purpose you may have defined different complexTypes in your xsd.

Consider you want to exchange a list of AirSegments under an Itinerary like:

<OriginDestinationBooked>
    
<AirSegmentBookedList>
        
<AirSegmentBooked>
            
<CarrierCode>AC</CarrierCode>
            
<FlightNumber>12</FlightNumber>
        
</AirSegmentBooked>
        
<AirSegmentBooked>
            
<CarrierCode>AC</CarrierCode>
            
<FlightNumber>13</FlightNumber>
        
</AirSegmentBooked>
        
<AirSegmentBooked>
            
<CarrierCode>AC</CarrierCode>
            
<FlightNumber>189</FlightNumber>
        
</AirSegmentBooked>
    
</AirSegmentBookedList>
</OriginDestinationBooked>

 

To accomplish this, you will define Something like below:

<xs:complexType name="OriginDestinationBookedType">
    <xs:sequence>
 <xs:element name="AirSegmentBookedList" type="SegmentBookedListType"/>
    </xs:sequence>
  </xs:complexType>


<xs:complexType name="SegmentBookedListType">
    <xs:sequence>
 <xs:element maxOccurs="unbounded" name="AirSegmentBooked" type="SegmentBookedType"/>
    </xs:sequence>
  </xs:complexType>


  <xs:complexType name="SegmentBookedType">
    <xs:sequence>
      <xs:element name="CarrierCode" type="CarrierCodeType"/>
      <xs:element name="FlightNumber" type="FlightNumberType"/>
    </xs:sequence>
  </xs:complexType>

This looks good. Looks Good until we generate the Proxy classes out of these Contracts. Give it a try to generate the classes out of these XSDs using Plugins: JAXB-MAVEN, CXF etc.

You will notice that 3 proxy classes get generated.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OriginDestinationBookedType", propOrder = {
"segmentBookedList"
})
public class OriginDestinationBookedType {
@XmlElement(name = "SegmentBookedList", required = true)
protected SegmentBookedListType segmentBookedList;
public SegmentBookedListType getSegmentBookedList() {
return segmentBookedList;
}
public void setSegmentBookedList(SegmentBookedListType value) {
this.segmentBookedList = value;
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SegmentBookedListType", propOrder = {
"segmentBookeds"
})
public class SegmentBookedListType {
@XmlElement(name = "SegmentBooked", required = true)
protected List segmentBookeds;
public List getSegmentBookeds() {
if (segmentBookeds == null) {
segmentBookeds = new ArrayList();
}
return this.segmentBookeds;
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SegmentBookedType", propOrder = {
"carrierCode",
"flightNumber"
})
public class SegmentBookedType {
@XmlElement(name = "CarrierCode", required = true)
protected String carrierCode;
@XmlElement(name = "FlightNumber", required = true)
protected String flightNumber;
}

With the above classes, if you want to get an access to a Segment within an OD, you will have to write:

OriginDestinationBookedType od; // Initialized properly and you have a non-null reference
od.getSegmentBookedList().getSegmentBookeds().get(segIndex);

Bold part above is redundant and not needed for sure. Instead, we want to have:

od.getSegmentBookeds().get(segIndex);

How can we directly get a list of segments under an OD?

Solution
Integrate XEW Plugin into your repository and get it executed during Code generation phase.
Simply,

 

<plugin>
        <groupId>org.jvnet.jaxb2.maven2</groupId>
        <artifactId>maven-jaxb2-plugin</artifactId>
        <version>0.13.1</version>
        <dependencies>
            <dependency>
                <groupId>org.jvnet.jaxb2_commons</groupId>
                <artifactId>jaxb2-basics</artifactId>
                <version>0.6.3</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <id>air-ticket-schema</id>
                <goals>
                      <goal>generate</goal>
                </goals>
                <configuration>
                    <extension>true</extension>
                    <args>
                        <arg>-Xannotate</arg>
                        <arg>-Xxew</arg>
                        <arg>-Xxew:control ${basedir}/src/main/resources/xsds/xewInclusionExclusion.txt</arg>
                    </args>
                    <plugins>
                        <plugin>
                            <groupId>org.jvnet.jaxb2_commons</groupId>
                            <artifactId>jaxb2-basics-annotate</artifactId>
                            <version>1.0.2</version>
                        </plugin>
                        <plugin>
                            <groupId>com.github.jaxb-xew-plugin</groupId>
                            <artifactId>jaxb-xew-plugin</artifactId>
                            <version>1.9</version>
                        </plugin>
                        <plugin>
                            <groupId>com.sun.xml.bind</groupId>
                            <artifactId>jaxb-xjc</artifactId>
                            <version>2.2.11</version>
                        </plugin>
                    </plugins>
                    <vmArgs>
                        <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
                    </vmArgs>
                    <schemaDirectory>${basedir}/src/main/resources/xsds</schemaDirectory>
                    <schemaIncludes>
                        <include>yourXSDsHere.xsd</include>
                    </schemaIncludes>
                    <generateDirectory>${basedir}/target/generated-sources</generateDirectory>
                    <bindingDirectory>${basedir}/src/main/resources/xsds</bindingDirectory>
                    <bindingIncludes>
                        <bindingInclude>bindings.xjb</bindingInclude>
                    </bindingIncludes>
                      <removeOldOutput>false</removeOldOutput>
                      <clearOutputDir>false</clearOutputDir>
                      <extension>true</extension>
                </configuration>
              </execution>
        </executions>
    </plugin>

 

With the above configuration, only 2 classes will be generated.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OriginDestinationBookedType", propOrder = {
"segmentBookedList"
})
public class OriginDestinationBookedType {
@XmlElement(name = "SegmentBookedList", required = true)
protected List segmentBookedList;
public List getSegmentBookedList() {
return segmentBookedList;
}
public void setSegmentBookedList(List value) {
this.segmentBookedList = value;
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SegmentBookedType", propOrder = {
"carrierCode",
"flightNumber"
})
public class SegmentBookedType {
@XmlElement(name = "CarrierCode", required = true)
protected String carrierCode;
@XmlElement(name = "FlightNumber", required = true)
protected String flightNumber;
}

And you are all set. No cursing on XSDs 🙂

ADVANTAGES

    No more List wrapper classes.No more additional clumsy code
    No redundant Null checks
    More readability
    Less Machine Instructions to execute
    Less Memory Footprint of Virtual Functions Table
    More maintainability


Advertisements

About Sunil Singhal

A human being whose dreams are tied to a Horse that will never tire
This entry was posted in Java. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s