Here's a little tip I thought I'd pass along about customizing JAXB to generate stuff to different packages based on target namespace. There are two ways to do it...
Here are the schemas we'll be looking at:
common.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.test.com/common" targetNamespace="http://www.test.com/common" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="aString" type="aString_Type"/>
<xs:element name="aInteger" type="aInteger_Type"/>
<xs:element name="aLong" type="aLong_Type"/>
<xs:simpleType name="aString_Type">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="aInteger_Type">
<xs:restriction base="xs:integer"/>
</xs:simpleType>
<xs:simpleType name="aLong_Type">
<xs:restriction base="xs:long"/>
</xs:simpleType>
</xs:schema>
A.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.test.com/A" targetNamespace="http://www.test.com/A" xmlns:common="http://www.test.com/common" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="http://www.test.com/common" schemaLocation="common.xsd"/>
<xs:element name="A" type="A_Type"/>
<xs:complexType name="A_Type">
<xs:sequence>
<xs:element ref="common:aString"/>
<xs:element ref="common:aInteger" minOccurs="0"/>
<xs:element ref="common:aLong" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
B.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.test.com/B" targetNamespace="http://www.test.com/B" xmlns:common="http://www.test.com/common" xmlns:a="http://www.test.com/A" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="http://www.test.com/common" schemaLocation="common.xsd"/>
<xs:import namespace="http://www.test.com/A" schemaLocation="A.xsd"/>
<xs:element name="B" type="B_Type"/>
<xs:complexType name="B_Type">
<xs:sequence>
<xs:element ref="common:aString"/>
<xs:element ref="a:A"/>
<xs:element ref="common:aLong" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
I use Windoze for my desktop client, so I created a command file to run the JAXB schema binding compiler:
gen-jaxb.cmd:
@set JAVA_HOME=C:\j2sdk1.4.2_05
@set JWSDP_HOME=C:\jwsdp-1.4
@set SCHEMA_DIR=.
@set DEST_DIR=.\gen-src
@rem Use the below to let JAXB derive package name based on targetNamespace
%JAVA_HOME%\bin\java -jar -Xmx512m -Xss2m %JWSDP_HOME%\jaxb\lib\jaxb-xjc.jar %SCHEMA_DIR%\B.xsd -d %DEST_DIR%
@rem Use the below to customize package name using an external binding file
%JAVA_HOME%\bin\java -jar -Xmx512m -Xss2m %JWSDP_HOME%\jaxb\lib\jaxb-xjc.jar %SCHEMA_DIR%\B.xsd -d %DEST_DIR% -b binding.xjb
And I use an external binding file, so customizations are outside of my schema file. This has two distinct advantages: First, since oftentimes I don't have the luxury of modifying a schema, my binding customizations are externalized. Second, if I want to use a different binding compiler my schema (along with the aforementioned schema files I may or may not be allowed to modify) remain unchanged.
binding.xjb:
<jxb:bindings version="1.0" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:com.fnf="http://www.fnf.com/xes">
<!-- Customize the package name that is generated for each schema.
-->
<jxb:bindings schemaLocation="A.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:package name="com.test.customized.a"/>
</jxb:schemaBindings>
</jxb:bindings>
<jxb:bindings schemaLocation="B.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:package name="com.test.customized.b"/>
</jxb:schemaBindings>
</jxb:bindings>
<jxb:bindings schemaLocation="common.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:package name="com.test.customized.common"/>
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
Okay, so all the pieces are in place. Now let's look at the two scenarios for the package name of our generated code.
Scenario 1: Let JAXB derive package where generated classes will reside based on targetNamespace attribute
JAXB can derive the package name based on the targetNamespace attribute of each schema file. The rules for doing so are outlined in the spec, so I won't include them here. But here's a link to it: http://java.sun.com/xml/downloads/jaxb.html. When I run the binding compiler using the first line of binding.xjb (make sure to comment out the second line or it will overwrite the generated code from the first line, and that will be, well, plain confusing!), I get code generated to packages:
- com.test.common
- com.test.a
- com.test.b
Take another look at the targetNamespace attributes of each schema above and see if you can follow how the binding compiler derived the name of each corresponding package.
Scenario 2: Use a customization to choose the package to which the generated classes will reside
In this scenario, I comment out the first line in the gen-jaxb.cmd file and uncomment the second to force a customization of the package for each namespace and get the following packages generated:
- com.test.customized.common
- com.test.customized.a
- com.test.customized.b
Enjoy!