Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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

1 Answer 1

As I don't know how exactly works this site, I'll only reply. If I have to edit the "original post", tell it to me :)

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
    
This looks like a useful improvement. I'll test it out and if it works as expected I'll update the original post, or feed back any problems. Thanks for contributing! –  Gary Rowe Aug 22 '12 at 16:54
    
I have an example with a java.util.Date Adapter (JaxbDateAdapter). Source here –  Guillaume Husta Jan 13 at 16:26

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.