Here's an interesting scenario that I encountered the other day. I did eventually reach a solution on my own. However, I'd welcome any comments and better approaches.
The requirements
I want to generate JAXB objects based on a collection of XSDs using XJC as part of a Maven build. I'll be using JAXB-RI 2.1 as the implementation.
In addition, I want to make sure that all objects implement a signature interface (e.g. MySignature
) which has no methods. Also, I want to avoid using XmlGregorianCalendar
and have Joda DataTime
instead (with a suitable adapter that I'll provide called DateUtils
with parse()
and format()
methods).
Finally, I want to be able to select certain objects to act as root elements so I'll need to selectively add @XmlRootElement
to some objects, and I have suitable XPath expressions to locate them.
I can't make any changes to the XSDs.
The approach
Step 1 - Configuring the pom.xml
Configure Maven to use the XJC plugin as follows:
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.7.4</version>
<executions>
<execution>
<id>generate-domain1</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<strict>false</strict>
<schemaIncludes>
<value>domain1.xsd</value>
</schemaIncludes>
<bindingIncludes>
<include>domain1-bindings.xjb</include>
</bindingIncludes>
<extension>true</extension>
<generatePackage>org.example.domain1</generatePackage>
<generateDirectory>${project.build.directory}/generated-sources/domain1</generateDirectory>
<args>
<arg>-Xannotate</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.0</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>0.6.0</version>
</plugin>
</plugins>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The use of a dedicated execution configuration is there to allow additional mutually exclusive XSDs to be built using a different target output path.
Step 2 - Configure the bindings
Include the following as src/main/resources/domain1-bindings.xjb
.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:annox="http://annox.dev.java.net"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
jaxb:extensionBindingPrefixes="xjc annox"
version="2.1">
<jaxb:globalBindings>
<jaxb:serializable uid="1"/>
<!-- All generated classes must have MySignature interface (supplied in dependencies) -->
<xjc:superInterface name="org.example.MySignature"/>
<!-- All temporal fields are implemented as Joda DateTime and use DateUtils as an adapter -->
<jaxb:javaType
name="org.joda.time.DateTime"
xmlType="xs:time"
parseMethod="org.example.DateUtils.parseDateTime"
printMethod="org.exmaple.DateUtils.formatDateTime"
/>
</jaxb:globalBindings>
<!-- Application of annotations to selected classes within schemas -->
<!-- org.example.SomeRootType @XmlRootElement -->
<jaxb:bindings schemaLocation="domain1.xsd" node="/xs:schema">
<jaxb:bindings node="xs:complexType[@name='SomeRootType']">
<annox:annotate>
<annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="SomeRootType"/>
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Troubleshooting
If you encounter the infamous
Unsupported binding namespace "". Perhaps you meant "http://annox.dev.java.net"
then you need to examine your bindings.xjb
to make sure that you're using the correct namespace URIs (as defined above) and have included them into extensionBindingPrefixes
.