How to use an array constant in an annotation

Viewed 44208

I would like to use constants for annotation values.

interface Client {

    @Retention(RUNTIME)
    @Target(METHOD)
    @interface SomeAnnotation { String[] values(); }

    interface Info {
        String A = "a";
        String B = "b";
        String[] AB = new String[] { A, B };
    }

    @SomeAnnotation(values = { Info.A, Info.B })
    void works();

    @SomeAnnotation(values = Info.AB)
    void doesNotWork();
}

The constants Info.A and Info.B can be used in the annotation but not the array Info.AB as it has to be an array initializer in this place. Annotation values are restricted to values that could be inlined into the byte code of a class. This is not possible for the array constant as it has to be constructed when Info is loaded. Is there a workaround for this problem?

6 Answers

It is because arrays' elements can be changed at runtime (Info.AB[0] = "c";) while the annotation values are constant after compile time.

With that in mind someone will inevitably be confused when they try to change an element of Info.AB and expect the annotation's value to change (it won't). And if the annotation value were allowed to change at runtime it would differ than the one used at compile time. Imagine the confusion then!

(Where confusion here means that there is a bug that someone may find and spend hours debugging.)

As already was mentioned in previous posts, annotation vales are compile-time constants and there is no way to use an array value as a parameter.

I solved this problem a bit differently.

If you're owning the processing logic, take advantage of it.

For example, give an additional parameter to your annotation:

@Retention(RUNTIME)
@Target(METHOD)
@interface SomeAnnotation { 
    String[] values();
    boolean defaultInit() default false;
}

Use this parameter:

@SomeAnnotation(defaultInit = true)
void willWork();

And this will be a marker to the AnnotationProcessor, which can do anything - initialize it with an array, use String[], or use Enums like Enum.values() and map them to String[].

Hope this will guide someone who has the similar situation in the right direction.

Related