07 December 2010

I certainly haven’t the time to blog about every unhelpful error message I find, especially not when it comes to frameworks. Good error handling is an art, and even the best projects aren’t likely to get it all right. And then there’s JSF. Or, at least, JSF as I’m using it now: the 1.2 API, MyFaces, ICEfaces, all running on Jetspeed 2. I’ve become numb to the bad error messages, mostly. You get used to them after a while, and even start to understand them.

This particular case had me up until midnight with nothing but frustration to show for it. After a bit of sleep (one of the key elements of software debugging that is often overlooked) it dawned on me what my problem was. Consider the code:

public class MyBean
{
    enum MyEnum {
        VAR1,
        VAR2;
        public String getTitle() {
            return name().toLowerCase();
        }
    }
    …
}

And the related facelet markup:

#{myEnumValue.class} is titled '#{myEnumValue.title}'

It seemed to be straightforward, but I kept getting this error message:

Property 'title' not readable on type java.lang.String

And what kept bugging me was the fact that #{myEnumValue.class} worked when it was by itself (it would output MyBean.MyEnum). I could clearly see the class name, and it looked just fine. But as soon as I added in the title property, I would get the error message again. Obviously myEnumValue was not a String, so why does the error message say that it is?

As it turns out, my Enum wasn’t public, and so apparently the methods on it could not be invoked. Rather than telling me that, the expression evaluator decided to coerce the Enum into a String and then see if the property I wanted was part of the String class. It wasn’t. Here’s the solution:

public class MyBean
{
    public enum MyEnum {
    …
    }
}

So there you have it: one more strange error message deciphered. I hope others will spend less time tracking down these types of errors than I do.

And the real moral of the story? Well, first, error handling is hard. While string coercion may be a good strategy for this situation, the fallback error message proves unhelpful. Better to capture the message that triggered the fallback and return it instead. Unfortunately, that requires that your error handling strategy can maintain such a message and know when to use it. So a second moral is, be prepared for error handling to get much more complex as your requirements expand.