Tuesday, December 6, 2011

Maven JAXB2 Plugin and Configuring Package Names

Several Maven plugins exist for generating classes from a schema definition. One I have yet to try is the Maven JAXB2 Plugin. Below I'll show the minimum setup for using the plugin in your project, as well as a couple of methods for dealing with the package name assigned to the generated classes.

Given the simplistic schema below, placed in src/main/resources of the project:

  <?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns="http://example.org/message/1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="message">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="text" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

We can add the plugin definition to our POM:

  <plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>

The classes generated by the plugin can be found in target/generated-sources/xjc. Below is the single class, Message.java, generated by the plugin (with the imports optimized and comments removed for brevity):

  package generated;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"text"})
@XmlRootElement(name = "message")
public class Message {

@XmlElement(required = true)
protected String text;

public String getText() {
return text;
}

public void setText(String value) {
this.text = value;
}
}

The first thing that stands out to me is the package name of generated. This might be ok if I wanted to use the generated classes within a single project, but if I wanted to distribute them, a more useful package name might be helpful.

The user guide for the plugin describes a list of configuration options. The one we're looking for might just be generatePackage, which we can add:

  <plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<executions>
<!-- ... -->
</executions>
<configuration>
<generatePackage>org.example.message</generatePackage>
</configuration>
</plugin>

The generated class can now be found in target/generated-sources/xjc/org/example/messsage/Message.java, with the new package name:

  package org.example.message;

public class Message {
// ...
}

There are a couple more options for setting the package name, one is to add an annotation to the schema:

  <?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns="http://example.org/message"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<xsd:annotation>
<xsd:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="org.example.test"/>
</jaxb:schemaBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="message">
<!-- ... -->
</xsd:element>
</xsd:schema>

If you find annotating a schema to for something like JAXB impurifies the schema, you could influence to derive a namespace by providing a targetNamespace attribute to the root element of the schema:

  <?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns="http://example.org/message"
targetNamespace="http://example.org/message" ...>
<!-- ... -->
</xsd:schema>

If you have any other suggestions or feel like weighing in on the use of xjc annotations in schema definitions, please feel free to add a comment below.