Skip to main content
Last updated September 24, 2011 13:55, by lexi
Feedicon  

JAXB 2 Default Value Plugin

This is an XJC plugin to set default values in the XJC generated classes based on the default attribute to <xs:element>. The default attribute is documented here. Note that JAXB handles defaults for <xs:attribute> natively, so this plugin is not necessary for an attribute default.


The plugin is particularly useful while generating Value Objects for a user interface from an XML schema. User interface tags such as the Struts HTML tags use reflection on bean properties to render themselves, so it is often useful to have a set of sensible defaults set in the Java Beans mapping to the user interface themselves.

The XML schema below describes a person and their address. It also uses a boolean flag to indicate whether the user's mailing address is different from their residential address. Since a person's mailing address is typically the same as their residential address, it would be nice to default the boolean to true. The XML schema "default" attribute is used to achieve this.


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="firstName" type="xs:string"/>
      <xs:element name="middleName" type="xs:string"/>
      <xs:element name="lastName" type="xs:string"/>
      
      <xs:element name="residentialAddress" type="Address" minOccurs="1" maxOccurs="1"/>
      <xs:element name="mailingAddressIdentical" type="xs:boolean" default="true"/>
      <xs:element name="mailingAddress" type="Address" minOccurs="0" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:complexType name="Address">
  <xs:sequence>
    <xs:element name="careOf" type="xs:string"/>
    <xs:element name="street" type="xs:string"/>
    <xs:element name="apt" type="xs:string"/>
    <xs:element name="city" type="xs:string"/>
    <xs:element name="state" type="xs:string"/>
    <xs:element name="ZIP" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
</xs:schema>

The XJC generated code for the schema (comments removed for brevity):

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "firstName",
    "middleName",
    "lastName",
    "residentialAddress",
    "mailingAddressIdentical",
    "mailingAddress"
})
@XmlRootElement(name = "Person")
public class Person {

    @XmlElement(required = true)
    protected String firstName;
    @XmlElement(required = true)
    protected String middleName;
    @XmlElement(required = true)
    protected String lastName;
    @XmlElement(required = true)
    protected Address residentialAddress;
    @XmlElement(defaultValue = "true")
    protected boolean mailingAddressIdentical;
    protected Address mailingAddress;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String value) {
        this.firstName = value;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String value) {
        this.middleName = value;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String value) {
        this.lastName = value;
    }

    public Address getResidentialAddress() {
        return residentialAddress;
    }

    public void setResidentialAddress(Address value) {
        this.residentialAddress = value;
    }

    public boolean isMailingAddressIdentical() {
        return mailingAddressIdentical;
    }

    public void setMailingAddressIdentical(boolean value) {
        this.mailingAddressIdentical = value;
    }

    public Address getMailingAddress() {
        return mailingAddress;
    }

    public void setMailingAddress(Address value) {
        this.mailingAddress = value;
    }

}

Note that the mailingAddressIdentical property's annotation contains a defaultValue="true" attribute, but does not map to the variable declaration - which, being a boolean, defaults to false. Wouldn't it be nice to have the declaration reflect this as well? Enter the default value plugin. Here's the declaration section of Person.java with the default value plugin enabled:

    @XmlElement(required = true)
    protected String firstName;
    @XmlElement(required = true)
    protected String middleName;
    @XmlElement(required = true)
    protected String lastName;
    @XmlElement(required = true)
    protected Address residentialAddress;
    @XmlElement(defaultValue = "true")
    <b>protected boolean mailingAddressIdentical = true</b>;
    protected Address mailingAddress;

Usage

For information about how to use XJC plugins in general, see here. The README bundled with the distribution has instructions on how to use the plugin with an Ant build file. The only modifications that need to be made are:

      
  • defaultvalueplugin.jar needs to be in the CLASSPATH, or declared in the section of the xjc task
  • The xjc task should be given a "-Xdefault-value" argument
  • Add an entry to the META-INF/services/com.sun.tools.xjc.plugin file within jaxb-xjc.jar with the full class name of the default value plugin class:
    org.jvnet.jaxb2_commons.defaultvalueplugin.DefaultValuePlugin

This is a sample build.xml that shows how the plugin is used. It's used to build the sample classes in the samples/ directory:

<?xml version="1.0" ?>

<project name="samples" default="compile" basedir=".">
  <description>Builds the default value plugin sample</description>

  <property file="../build.properties"/>

  <!-- Remove an earlier build by deleting the "build" directory -->
  <target name="clean">
    <delete dir="gen-src"/>
  </target>

  <!-- Compile classes generated by XJC compiler -->
  <target name="compile" depends="gen-src">
    <javac compiler="javac1.5" srcdir="gen-src/generated" includes="*.java">
      <classpath>
	<fileset dir="${jaxb.lib.dir}" includes="*.jar"/>
      </classpath>
    </javac>
  </target>

  <!-- Use XJC task to compile schema to Java code -->
  <target name="gen-src">
    <mkdir dir="gen-src"/>
    <xjc removeOldOutput="yes" schema="Person.xsd" target="gen-src">
      <arg value="-extension"/>
      <arg value="-Xdefault-value"/>
    </xjc>
  </target>
  
  <!-- Defines XJC task -->
  <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
    <classpath>
      <fileset dir="${jaxb.lib.dir}" includes="*.jar"/>
      <pathelement location="../build/defaultvalueplugin.jar"/>
    </classpath>
  </taskdef>

</project>

The jar can be downloaded here

Questions and comments: hari dot selvarajan at gmail.com

Update 10/22/2007: The plugin now deals with many more types, including Enumerated types and Dates, and is a lot faster. Many thanks to Juergen Lukasczyk.

 
 
Close
loading
Please Confirm
Close