Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question

The <jaxb:javaType /> tag generates a new org.w3._2001.xmlschema.AdapterN class for each new javaType definition. So a better approach would be:

  • Create a class extending XmlAdapter<String, _To_>. In it you will have to override the both methods defined. So in example, the class could be org.example.DateUtilsAdapter.
  • Use this tag instead:

    <xjc:javaType
        name="org.joda.time.DateTime"
        xmlType="xs:time"
        adapter="org.example.DateUtilsAdapter" />
    

Source

share|improve this answer
    
I have an example with a java.util.Date Adapter (JaxbDateAdapter). Source here – Guillaume Husta Jan 13 '14 at 16:26

I tried your example in Eclipse and got a warning:

cvc-complex-type.3.2.2: Attribute 'jaxb:extensionBindingPrefixes' is not allowed to appear in 
 element 'jaxb:bindings'.

When I changed the URL from 2.0 to 2.1 it removed the warning.

Before: http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd
After: http://java.sun.com/xml/ns/jaxb/bindingschema_2_1.xsd

<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_1.xsd"
  jaxb:extensionBindingPrefixes="xjc annox"
  version="2.1">
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.