javaenumsannotations

How to supply Enum value to an annotation from a Constant in Java


I'm unable to use an Enum taken from a Constant as a parameter in an annotation. I get this compilation error: "The value for annotation attribute [attribute] must be an enum constant expression".

This is a simplified version of the code for the Enum:

public enum MyEnum {
    APPLE, ORANGE
}

For the Annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface MyAnnotation {
    String theString();

    int theInt();

    MyEnum theEnum();
}

And the class:

public class Sample {
    public static final String STRING_CONSTANT = "hello";
    public static final int INT_CONSTANT = 1;
    public static final MyEnum MYENUM_CONSTANT = MyEnum.APPLE;

    @MyAnnotation(theEnum = MyEnum.APPLE, theInt = 1, theString = "hello")
    public void methodA() {

    }

    @MyAnnotation(theEnum = MYENUM_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
    public void methodB() {

    }

}

The error shows up only in "theEnum = MYENUM_CONSTANT" over methodB. String and int constants are ok with the compiler, the Enum constant is not, even though it's the exact same value as the one over methodA. Looks to me like this is a missing feature in the compiler, because all three are obviously constants. There are no method calls, no strange use of classes, etc.

What I want to achieve is:

Any way to achieve these goals would be fine.

Edit:

Thanks all. As you say, it cannot be done. The JLS should be updated. I decided to forget about enums in annotations this time, and use regular int constants. As long as the int is assigned from a named constant, the values are bounded and it's "sort of" type safe.

It looks like this:

public interface MyEnumSimulation {
    public static final int APPLE = 0;
    public static final int ORANGE = 1;
}
...
public static final int MYENUMSIMUL_CONSTANT = MyEnumSimulation.APPLE;
...
@MyAnnotation(theEnumSimulation = MYENUMSIMUL_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
public void methodB() {
...

And I can use MYENUMSIMUL_CONSTANT anywhere else in the code.


Solution

  • It seems to be defined in the JLS #9.7.1:

    [...] The type of V is assignment compatible (§5.2) with T, and furthermore:

    • [...]
    • If T is an enum type, and V is an enum constant.

    And an enum constant is defined as the actual enum constant (JLS #8.9.1), not a variable that points to that constant.

    Bottom line: if you want to use an enum as a parameter for your annotation, you will need to give it an explicit MyEnum.XXXX value. If you want to use a variable, you will need to pick another type (not an enum).

    One possible workaround is to use a String or int that you can then map to your enum - you will loose the type safety but the errors can be spotted easily at runtime (= during tests).