Trouble with Java Default Values

java-logo-thumb.png

I got a note from the London users of my web app - specfically the email alerts system I've built into the web app so that people don't have to watch any one display all day long - they can get a chat or email alert telling them a certain condition has occurred. In any case, this morning I got word that the specific alert wasn't working quite right. So I started digging into the code. And hit one of my biggest annoyances with Java... the timing of the setting of the default values for class instance variables.

Let's look at a class and it's subclass. The problem will be in the subclass, but it's not obvious at looking at the code:

  public class BaseAlert extends Object {
    /**
     * These are the constructors - make the default protected so it's
     * not called accidentally, and make the general form of the
     * constructor take the important params and set things up right.
     */
    protected BaseAlert() {
      // always do the super's constructor
      super();
      // now do the base initialzation
    }
 
    public BaseAlert(String aName, Properties aProp) {
      // do the base constructor
      this();
      // now do the initialization of my args
      setName(aName);
      // update the configuration from the Properties
      updateConfiguration(aProp);
    }
 
    /**
     * This method picks out all the values from the Properties to
     * configure this instance.
     */
    public synchronized void updateConfiguration(Properties aProp) {
      /**
       * Read the values I need from the map and use them. Simple.
       */
    }
  }

and now the subclass that uses the updateConfiguration() method call for the same purpose, but has independent instance variables:

  public class MyAlert extends BaseAlert {
    /**
     * This is meant to be an attribute of the specific class. The
     * default value should work, but it doesn't.
     */
    private String      _code = null;
 
    /**
     * These are the constructors - make the default protected so it's
     * not called accidentally, and make the general form of the
     * constructor take the important params and set things up right.
     */
    protected MyAlert() {
      // always do the super's constructor
      super();
    }
 
    public MyAlert(String aName, Properties aProp) {
      // always do the super's constructor
      super(aName, aProp);
    }
 
    /**
     * This method picks out all the values from the Properties to
     * configure this instance.
     */
    public synchronized void updateConfiguration(Properties aProp) {
      // do all the super's value picking first
      super.updateConfiguration(aProp);
 
      /**
       * Read the values I need from the map and use them. Simple.
       */
      setCode(aProp.getProperty("Code"));
    }
  }

Here's what should happen:

  • Creating an instance of MyAlert causes the subclass to be created.
  • The call to updateConfiguration() is done and the values are read in.

Here's the catch: the default values are applied after the constructor is called. No joke.

The upshot: the value of _code is always going to be null all the debugging isn't going to help, as I found out. It's in the way the JDK handles the creation of the classes. Very annoying.

Fix? Have no default instance variable values. That's about it.

Grrr...