Trouble with Java Default Values
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...