Defining application properties with an Enum

8

I’ve been playing this week with defining an application’s properties in an Enum and so far it feels pretty nice. I’m sure people smarter than I have already done this but it’s the first time it occurred to me. The topic of app configuration is itself a topic I have many thoughts on…but that’s another post.

The basic idea is that I have some properties that configure my application and I have property keys that indicate how to retrieve those values. Rather than create a file of constants (maybe the best case) or worse just litter my code with constants in many places (the common case in my experience), I define in an Enum all of the properties, their default values, and other information.

Here’s a starting point:
[source:java]
public enum AppProperty {

FOO(“app.foo”), // no default
BAR(“app.soup”, “false”); // no soup for you

// enum state doesn’t have to be final…but doing otherwise
// is almost always a bad idea – don’t do it!
private final String propertyKey;
private final String defaultValue;

private AppProperty(String propertyKey) {
this(propertyKey, null);
}

private AppProperty(String propertyKey, String defaultValue) {
this.propertyKey = propertyKey;
this.defaultValue = defaultValue;
}

public String getPropertyKey() {
return this.propertyKey;
}

public String getDefaultValue() {
return this.defaultValue;
}

public String computeValue(Properties props) {
return props.getProperty(getPropertyKey(), getDefaultValue());
}
}
[/source]

So, here we define an enumerated type with 2 values – FOO and SOUP, each of which represent a property that can be passed to my app for configuration. FOO has no default value and SOUP has a default of “false”. The property key to use is always defined in exactly one place – in this enumerated type. You can get it by simply saying AppProperty.FOO.getPropertyKey().

You can use the computeValue() method to compute a value from a Properties source and the default value for the property. For example: AppProperty.FOO.computeValue(System.getProperties()).

A nice fallout from using enum is that you can get an enumerated list of all app properties. If you happened to also store a property description in here, you could actually build a generic usage method that walked all app properties (order defined by order of the constant definition) and printed the key, default, and description.

Or you could add type information here for common property types (boolean, int, date, etc) and methods to help you retrieve a type-specific value (auto-convert to Integer, Date, Boolean, etc).

It would be great if this could be made generic, but it’s not possible to create abstract enums, which would let you define everything BUT the constants and then subclass to set the constants. Fred Simon has proposed something like this for Java 7 and even built a patch to try it.

Comments

8 Responses to “Defining application properties with an Enum”
  1. Casper says:

    That’s an interesting use of enum’s which I haven’t seen, gotta remember this trick. Enum’s are easily my favorite part of Java, very crisp and flexible for modeling static meta data.

    Regarding the abstract issue, Heinz M. Kabutz of JavaSpecialists fame has exposed some interesting hacks:
    http://www.javaspecialists.eu/archive/Issue141.html

  2. Okay. Now I just figured out a stupid shortcoming of enums; they can’t have a generics type. I’d love to do something like this:

    public enum AppOptions {
    FOOBAR(“app.foobar”, 5);

    private final T default;
    private final String key;
    public T compute(Properties properties);

    private AppOptions(String key, T default) {
    this.default = default;
    this.key = key;
    }
    }

    But alas you get weird error messages in eclipse (and somewhat saner ones in javac) if you try to generify an enum type. Why can’t I generify these? This way ‘compute’ would either have to return a string, or you’d need to create getAsInt, getAsString, etc methods and enforce the caller to pick the type. Shame.

    Any way to work around this?

  3. Alex says:

    I believe that Fred’s patch that I linked also allows generics with enums.

  4. Fred’s patch is in one of the branches at Kijaro – http://kijaro.dev.java.net

  5. Steven Devijver says:

    The problem with Enums is that they really get in the way when you have to support different versions of data dictionaries. There’s no way to support that with Enums, or rather, a list of enumerated values cannot change between versions a the same data dictionary.

  6. Casper says:

    Steven, forgive me if I am asking stupid, but do you refer to Enums i.e. generated from a database table?

    If so, that must be a very common problem (keeping static and dynamic version in sync) but I guess it’s really just not what Enums are for. However, it WOULD be a very sweet thing to be able to infer the enums from i.e. a db table. But for this I guess you need a radical dynamic change to the Enum concept, a data provider API, type inference and IDE support – a kin to what you can do in LINQ.

  7. Steven Devijver says:

    The problem is not so much that they’re static. The problem is that once you support an Enum value you can’t remove it anymore, at least not if you don’t want to break older versions of an application.

  8. bkag says:

    That’s what readObject override is for.

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!