JAXB class generation with imported XSD and binding JAXB class generation with imported XSD and binding xml xml

JAXB class generation with imported XSD and binding


Normally, the way you would want to do this would be to use Schema Component Designators (SCD) instead of XPath.

Using SCD for customizations

[XPath] is also error prone, because it relies on the way schema documents are laid out, because the schemaLocation attribute needs to point to the right schema document file. When a schema is split into multiple files for modularity (happens especially often with large schemas), then you'd have to find which schema file it is. Even though you can use relative paths, this hard-coding of path information makes it hard to pass around the binding file to other people.

SCD Support

Compared to the standard XPath based approach, SCD allows more robust and concise way of identifying a target of a customization. For more about SCD, refer to the scd example. Note that SCD is a W3C working draft, and may change in the future.

Unfortunately, due to a bug in XJC, SCD does not work in combination with vendor extensions. You would see an error like:

[ERROR] cvc-elt.1: Cannot find the declaration of element 'inheritance:implements'.

The author of jaxb2-basics has recently written up a detailed explanation of that particular problem. Basically, if you want to use vendor extensions, you are stuck with XPath (and its limitations) for now.

An XPath-based solution

Here is a complete, working example using XPath with the vendor extensions based on the information you provided in your question. I believe the proper way to generate the classes from the imported schemas are via a separate bindings element. As proof that this is working as expected, the class generated from this binding (Cust) is visible and reused by those classes generated by common.xsd. Each generated class implements the base class jaxb.BaseMessage.

I believe this is as good a solution as you will find until the XJC bug is fixed.

src/main/resources/bindings.xjb:

<?xml version="1.0" encoding="UTF-8"?><jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"    jaxb:version="2.1"    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"    xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"    jaxb:extensionBindingPrefixes="xjc inheritance">  <jaxb:globalBindings>    <jaxb:javaType name="java.lang.Long" xmlType="xsd:integer" />  </jaxb:globalBindings>  <jaxb:bindings schemaLocation="schema/x.xsd">    <jaxb:bindings node="//xsd:complexType[@name='Customer']">      <jaxb:class name="Cust" />      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>    </jaxb:bindings>  </jaxb:bindings>  <jaxb:bindings schemaLocation="schema/y.xsd">    <jaxb:bindings node="//xsd:complexType[@name='Payments']">      <jaxb:class />      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>    </jaxb:bindings>  </jaxb:bindings>  <jaxb:bindings schemaLocation="schema/common.xsd">    <jaxb:bindings node="//xsd:complexType[@name='CustomerPayments']">      <jaxb:class />      <inheritance:implements>jaxb.BaseMessage</inheritance:implements>    </jaxb:bindings>  </jaxb:bindings></jaxb:bindings>

src/main/resources/schema/common.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    xmlns:x="http://test.org/common/x"    xmlns:y="http://test.org/common/y"    targetNamespace="http://test.org/common">  <xsd:import namespace="http://test.org/common/x" schemaLocation="x.xsd" />  <xsd:import namespace="http://test.org/common/y" schemaLocation="y.xsd" />  <xsd:complexType name="CustomerPayments">    <xsd:sequence>      <xsd:element name="customer" type="x:Customer" />      <xsd:element name="payments" type="y:Payments" />    </xsd:sequence>  </xsd:complexType></xsd:schema>

src/main/resources/schema/x.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    elementFormDefault="qualified"    attributeFormDefault="unqualified"    targetNamespace="http://test.org/common/x">  <xsd:complexType name="Customer">    <xsd:sequence>      <xsd:element name="name" type="xsd:string" />    </xsd:sequence>  </xsd:complexType></xsd:schema>

src/main/resources/schema/y.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    elementFormDefault="qualified"    attributeFormDefault="unqualified"    targetNamespace="http://test.org/common/y">  <xsd:complexType name="Payments">    <xsd:sequence>      <xsd:element name="amount" type="xsd:float" />    </xsd:sequence>  </xsd:complexType></xsd:schema>

build.xml:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE project><project name="JAXB XPath Test" default="xjc" basedir=".">  <property name="build.folder" location="build" />  <taskdef name="xjc" classname="org.jvnet.jaxb2_commons.xjc.XJC2Task">    <classpath>        <fileset dir="${basedir}/lib">          <include name="jaxb-impl-2.2.6.jar" />          <include name="jaxb-xjc-2.2.6.jar" />          <include name="jaxb2-basics-ant-0.9.4.jar" />          <include name="javaparser-1.0.11.jar" />          <include name="commons-lang3-3.2.jar" />        </fileset>    </classpath>  </taskdef>  <target name="xjc" description="Generate the source code.">    <xjc destdir="${basedir}/src/main/java" extension="true">      <arg line="        -Xequals        -XhashCode        -XtoString        -Xcopyable        -Xmergeable        -Xinheritance" />      <binding dir="${basedir}/src/main/resources">        <include name="**/*.xjb" />      </binding>      <schema dir="${basedir}/src/main/resources/schema">        <include name="**/*.xsd" />      </schema>      <classpath>        <fileset dir="${basedir}/lib">            <include name="jaxb2-basics-0.9.4.jar"/>            <include name="jaxb2-basics-runtime-0.9.4.jar"/>            <include name="jaxb2-basics-tools-0.9.4.jar"/>            <include name="commons-beanutils-1.8.0.jar"/>            <include name="commons-lang3-3.2.jar"/>            <include name="commons-logging-1.1.1.jar"/>        </fileset>      </classpath>    </xjc>  </target></project>


I'm posting a second answer because I believe what you are trying to achieve is possible without vendor extensions, but I also think that my original answer may be useful to others who need vendor extensions.

This example also removes the namespaces, but they could be added back easily. The same build script is used for this answer as in my previous one.

src/main/resources/bindings.xjb:

<?xml version="1.0" encoding="UTF-8"?><jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"    jaxb:version="2.1"    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"    jaxb:extensionBindingPrefixes="xjc"    xmlns:common="schema/common.xsd">  <jaxb:globalBindings>    <jaxb:javaType name="java.lang.Long" xmlType="xsd:integer" />    <xjc:superInterface name="jaxb.BaseMessage" />  </jaxb:globalBindings></jaxb:bindings>

src/main/resources/schema/common.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <xsd:include schemaLocation="x.xsd" />  <xsd:include schemaLocation="y.xsd" />  <xsd:complexType name="CustomerPayments">    <xsd:sequence>      <xsd:element name="customer" type="Customer" />      <xsd:element name="payments" type="Payments" />    </xsd:sequence>  </xsd:complexType></xsd:schema>

src/main/resources/schema/x.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    <xsd:complexType name="Customer">      <xsd:sequence>        <xsd:element name="name" type="xsd:string" />      </xsd:sequence>    </xsd:complexType></xsd:schema>

src/main/resources/y.xsd:

<?xml version="1.0" encoding="UTF-8"?><xsd:schema version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">    <xsd:complexType name="Payments">      <xsd:sequence>        <xsd:element name="amount" type="xsd:float" />      </xsd:sequence>    </xsd:complexType></xsd:schema>


Why don't you just point your schemaLocation to x.xsd and y.xsd, where the types are defined?

<jaxb:bindings schemaLocation="x.xsd" node="/xsd:schema">    <jaxb:bindings node="xsd:complexType[@name='Customer']">        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>        <jaxb:class />    </jaxb:bindings></jaxb:bindings><jaxb:bindings schemaLocation="y.xsd" node="/xsd:schema">    <jaxb:bindings node="xsd:complexType[@name='Payments']">        <inheritance:implements>jaxb.BaseMessage</inheritance:implements>        <jaxb:class />    </jaxb:bindings></jaxb:bindings>