29
\$\begingroup\$

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.

\$\endgroup\$
0

2 Answers 2

8
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ I have an example with a java.util.Date Adapter (JaxbDateAdapter). Source here \$\endgroup\$ Jan 13, 2014 at 16:26
6
\$\begingroup\$

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">
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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