Tweaking JAXB to generate better code

Maarten Winkels

JAXB can be a real time saver when working on a project that uses XSD to describe interfaces implemented in Java. Sometimes, however, the generated code is not up to standard. I ran into a problem that seems very common and found a very elegant solution to it on the web.

Yesterday, while working on the XML Schema for Document, I had to decide whether I would wrap collections in a surrounding element, like this:

<Document>
...
  <Replies>
    <Reply>
      ...
    </Reply>
    <Reply>
      ...
    </Reply>
    ...
  </Replies>
  ...
</Document>

or I would just have a sequence of <Reply>-elements directly under Document. I think the general consensus is to use wrapping elements, but I decided to base the design on another measure: What would the (Java) code look like that would be generated from the Schema by JAXB.

After configuring the maven-jaxb-plugin into the project (which was really easy and it integrated out of the box with Eclipse through M2Eclipse), the Java code was a little disappointing: For every collection I would get the following structure:

class Document {
  
  @XmlElement(name = "Replies")
  private Replies replies;
  
  public Replies getReplies() {
    return replies;
  }

  public class Replies() {

    @XmlElement(name = "Reply")
    private List<Reply> reply;
    
    public List<Reply> getReply() {
      return reply;
    }
  }
}

This would lead to the following usage pattern:

  Document doc;
  ...
  doc.getReplies().getReply().add(new Reply(...));

which is in my opinion quite awful. I would expect there to be a simple collection structure:

  Document doc;
  ...
  doc.getReplies().add(new Reply(...));

But whether I would use the wrapping element or not, I would still get the additional class.

There is a JAXB annotation that will help in this situation:

  @XmlElementWrapper(name = "replies")
  @XmlElement(name = "reply")
  protected List<Reply> replies;

And this is exactly what we want, but how to tell the JAXB code generator to use that annotation?

After some googling around, I found this blog posting, that provides a solution by using a custom plugin for XJB (the JAXB code generator). Configuring this in maven was quite easy:

  1. Add the plugin jar (which was unfortunately not available from a Maven repo) to the maven-jaxb-plugin dependencies.
  2. Add an <args>-element to the plugin configuration with the -Xxew option to activate the plugin.

The final Maven configuration looks like this:

<plugin>
  <groupId>com.sun.tools.xjc.maven2</groupId>
  <artifactId>maven-jaxb-plugin</artifactId>
  <executions>
    <execution>
      <id>jaxb-generate</id>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <includeSchemas>
      <includeSchema>xsd/Document.xsd</includeSchema>
    </includeSchemas>
    <strict>true</strict>
    <verbose>true</verbose>
    <args>-Xxew</args>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>xew</groupId>
      <artifactId>xew</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</plugin>

The generated code now uses a simple collection, so it looks much more usable.

One last problem is that the generated Replies class, that is now no longer used, is not removed from the code: A little clean up task that must have slipped the plugin developers mind.

Comments (4)

  1. Tzach - Reply

    September 6, 2009 at 12:30 pm

    Nice, but is there a way to annotate the XSD to create the deride code?

  2. Bjarne Hansen - Reply

    September 14, 2009 at 12:36 pm

    Use the -delete option to have modified candidates removed from the final code.

  3. AM - Reply

    October 5, 2009 at 10:48 pm

    Nice, but is there a way to annotate the XSD to create the deride code?

  4. anon - Reply

    February 28, 2012 at 6:59 pm

    Another request for a way to do this without annotations.

Add a Comment