Using Java Enums

This week I discovered two useful things you can do with Enums in Java.

The first and probably the more useful of the two is for formatting error messages in a consise and type safe way.

public enum ErrorMessageKey {
 
FILE_NOT_FOUND( "Cannot find file {0}"),
 
CANNOT_READ_FILE( "Cannot read file {0}"),
 
FILESTORE_CANNOT_OPEN_FILE( "Unable to open {0} nor {1}");
 
private final String message; // Message string
 
/**
 
* Constructor for the enum.
 
* @param message message string
 
*/
 
ErrorMessageKey(String message) {
 
this.message = message;
 
}
 
/**
 
* Get the message string
 
* @return the message string
 
*/
 
public String getMesssage() {
 
return message;
 
}
 
}

Defining an error message key in this way means that we can have a type safe way of passing error message strings to logging mechanisms and exception trees.

First we define a logging function that takes an error message key and a Java 5 varargs array. This logging function formats the error string using the getMessage() method we have defined for the Enum.

public void info(ErrorMessageKey msg, Object... arg) {
 
// Format the message into a string and pass it to the
 
// normal logger
 
MessageFormat mf = new MessageFormat(msg.getMesssage());
 
info( msg.name() +":"+mf.format(arg));
 
}

Then using the logging mechanism is type safe, straightforward, and most importantly, very readable

logger.info(ErrorMessageKey.CANNOT_READ_FILE, "file.txt");
62 INFO [main] MyClass - CANNOT_READ_FILE:Cannot read file file.txt

You can’t get much more concise than that.

The second use I found for Enums is for creating Hierarchical trees of Enums using the Nested Enum pattern. I will come clean here in that this bug on Sun’s website provided me with the clue as to how I could implement my idea. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6424491

The example I’m going to show here is a bit contrived, but it gives you an idea of what you can do.

public enum HierarchicalEnum implements Serializable {
 
// special null enum
 
NULL (null, "null", "not assigned"),
 
PLOTS (null, "plots", "plots"),
 
TWODPLOTS (PLOTS, "2dplots", "2D Plots"),
 
HISTOGRAM (TWODPLOTS, "histogram", "Histogram plots"),
 
SCATTER (TWODPLOTS, "scatter", "Scatter plots"),
 
THREEDPLOTS (PLOTS, "3dplots", "3d plots"),
 
SPHERE_PLOT (THREEDPLOTS, "sphere", "Sphere plots");
 
static final long serialVersionUID = 1L;
 
private final HierarchicalEnum parent; // parent in the heirarchy
 
private final List children; // children in the heirarchy
 
private final String code; // plot code
 
private final String description; // plot description
 
/**
 
* Constructor for the enum.
 
* Fills in the code recursively from the parent enum.
 
* @param parent parent category
 
* @param code category code
 
* @param description category description
 
*/
 
HierarchicalEnum(HierarchicalEnum parent, String code, String description) {
 
this.children = new ArrayList();
 
this.parent = parent;
 
if (parent != null) {
 
this.code = parent.getCode() + "." + code;
 
parent.addChild(this);
 
} else {
 
this.code = code;
 
}
 
this.description = description;
 
}
 
/**
 
* Gets the parent category
 
* @return the parent category
 
*/
 
public HierarchicalEnum getParent() { return parent; }
 
/**
 
* Gets the code including all the parent codes
 
* @return the category code
 
*/
 
public String getCode() { return code; }
 
/**
 
* Gets the category description
 
* @return the category description
 
*/
 
public String getDescription() { return description; }
 
/**
 
* Private method to add a new child
 
* @param child
 
*/
 
private void addChild (HierarchicalEnum child) {
 
this.children.add(child);
 
}
 
}

Creating an Enum variable of type HISTOGRAM and using it as below

HierarchicalEnum h = HierarchicalEnum.HISTOGRAM;
 
logger.info("Histogram plot: Name = " + h.name() + " code = " + h.getCode() + " description = " + h.getDescription());

gives the following output

Histogram plot: Name = HISTOGRAM code = plots.2dplots.histogram description = Histogram plots

The pattern relies on the parent Enum being constructed first, in order to initialise the parent attribute to a valid value. The constructor then augments the parent’s list of children by calling the addChild() method. The code for the plot in this case is built up by recursing up the tree until we find a root node.

The only drawback I have found so far with this approach is that Enums cannot be extended so you have to be pretty sure that you can declare everything you need in one place.

4 Comments on “Using Java Enums”

  1. #1 Michael
    on Apr 17th, 2008 at 1:23 pm

    Thankyou very much for this. I have been struggling with an approach to hierarchical enums and this is just the ticket !

    Best regards
    Michael

  2. #2 Xavi
    on Aug 12th, 2009 at 5:02 pm

    Very nice, I’ve spent many time to find a solution for this!

    If it can help, I found a different way for implenting taxonomy hierarchy. The problem here is that you can find repeated elements, so they cannot be at the same enum type. Also I didn’t want to define a special enum value for the hierarchy root.

    public interface Taxonomy {

    /**
    * The taxonomy value.
    */
    String value();

    /**
    * The taxonomy childrens.
    */
    Taxonomy[] children();

    }

    Then you can define a taxonomy like this:

    public enum ArticleType implements Taxonomy {

    BRAND(“Brand”, ProductType.), ENTERPRISE(“Enterprise”), MARKET(“Market”), PRODUCT_RANGE(
    “Product range”), NEW_PRODUCT(“New product”);

    private static final Taxonomy taxonomy = new TaxonomyImpl(“Article”, values());

    private final String value;
    private final Taxonomy[] children;

    private ArticleType(String value, Taxonomy… children) {
    this.value = value;
    this.children = children;
    }

    public String value() {
    return value;
    }

    public static Taxonomy taxonomy() {
    return taxonomy;
    }

    public Taxonomy[] children() {
    return children;
    }

    @Override
    public String toString() {
    return value();
    }

    }

    The TaxonomyImpl class is simply:

    class TaxonomyImpl implements Taxonomy {

    /**
    * Useful empty array for taxonomies without children.
    */
    protected static final Taxonomy[] EMPTY_CHILDREN = new Taxonomy[0];

    private final String value;
    private final Taxonomy[] children;

    protected TaxonomyImpl(String value, Taxonomy… children) {
    this.value = value;
    this.children = children;
    }

    public String value() {
    return value;
    }

    public Taxonomy[] children() {
    return children;
    }

    @Override
    public String toString() {
    return value();
    }

    }

    You need much more code, but you get a more typed hierarchy.

    Salut,
    Xavi

  3. #3 Tamas
    on Apr 14th, 2010 at 8:26 pm

    Hi,

    In my recent project I did something similar to your Message enum, but with a little twist:

    The message can be in any enum, the exact value of the enum is stored in a property file next to the enum (if you use the same classloader that loaded the enum you can get the property file next to it from everywhere). Property files have the advantage, that they can be i18ed on the clientside. The name of the enum is used as a message code.

    In order to help the programmer sending the message, all keys and arguments were documented in the enum as javadoc (thus the IDE will look up for you.)

    Cheers,

    Tamas

  4. #4 Narada
    on May 28th, 2010 at 10:18 am

    Thanks for this. It was invaluable.

Leave a Comment