Friday, September 23, 2011

JAXB and Java 5 Enums

In my previous post about Java 5 Enums, I wrote about how Java 5 provides capabilities to add behavior (via member fields and methods) within the enum class. This can be leveraged to provide the switching-like on the enumeration constants. So instead of the following code fragment:
We can define an abstract method in the Enum specification, and override that method in each of the Enum definitions as shown here. However there can be cases where it is not possible to change the Enum class in order to define an abstract method, if the Enum class has been generated, such as via JAXB compiler. In that case, the only way we can provide any custom behavior is by programming a switch construct as above in a class that leverages the enum.
Digressing a little bit from the main point, I would also like to point out how JAXB treats different XSD enum definitions. See the examples below from a file, example.xsd which contains the 2 schema definitions, viz. CountryCurrencyEnum and CountryEnum.

    
        
           
               
                   
                   
                   
                   
               
           
        
        
    


    
        
        
        
        
    

The above example demonstrates 2 Enum examples. The currency Enum is an example of inline definition of the Enum, while the Country enum is an example of a external Enum definition. When you run the latter explicit enum definition through the XJC compiler, it produces a separate Enum class as below:
package com.examples;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;

@XmlType(name = "CountryEnum")
@XmlEnum
public enum CountryEnum {

    @XmlEnumValue("UnitedStates")
    UNITED_STATES("UnitedStates"),
    @XmlEnumValue("France")
    FRANCE("France"),
    @XmlEnumValue("UnitedKingdom")
    UNITED_KINGDOM("UnitedKingdom"),
    @XmlEnumValue("Japan")
    JAPAN("Japan");
    private final String value;

    CountryEnum(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static CountryEnum fromValue(String v) {
        for (CountryEnum c: CountryEnum.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }
}
However the XJC compiler will produce the following file when it sees the inline Enum definition.
package com.examples;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "CountryCurrencyEnum", propOrder = {
    "currency",
    "country"
})
public class CountryCurrencyEnum
    implements Serializable
{

    private final static long serialVersionUID = 2010L;
    @XmlElement(required = true)
    protected String currency;
    @XmlElement(required = true)
    protected CountryEnum country;

    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String value) {
        this.currency = value;
    }

    public CountryEnum getCountry() {
        return country;
    }

    public void setCountry(CountryEnum value) {
        this.country = value;
    }
}
So if we are interested in generating Java 5 style enums via JAXB, we are better off creating a separate definition in the xsd file.