Monday, March 10, 2008

Java annotation parameters can't default to null

I don't update here often enough, but here's a tidbit I wish I'd found on Google earlier.

Suppose you want to write a Java annotation that has a parameter value, but you want its default value to be null. Well, too bad. It is illegal to write this annotation:

public @interface Optional {
   public String value() default null;
}

It's a compile time error. javac says "attribute value must be constant;" Eclipse says "The value for annotation attribute Optional.value must be a constant expression." In fact, it's not that surprising, because even if you didn't set a default value, writing this would also be illegal (same error):

@Optional(null)

What the error is saying is that you can't set a Java annotation parameter to null.

Why is this? The specifications are opaque. JSR-175, which defined annotations for Java 5, just says "If member type is a primitive type or String, the ConditionalExpression must be a constant expression (JLS 15.28)." JLS 15.28, in turn, says that constant expressions can be, for example, any of these:

true
(short)(1*2*3*4*5*6)
Integer.MAX_VALUE / 2
2.0 * Math.PI
"The integer " + Long.MAX_VALUE + " is mighty big."

Notice anything missing? That's right, null. You can never pass null as a Java annotation parameter value, because, uh, null isn't a ConstantExpression.

Why? We may never know. The only thing you can do is workaround it, like this:

public @interface Optional {
   public String value() default NULL;
   public static final NULL = "THIS IS A SPECIAL NULL VALUE - DO NOT USE";
}

... and then make your code carefully treat Optional.NULL as if it were really null.

LAME!