261
votes

Today I wanted to create my first annotation interface following this documentation and I got this compiler error

Invalid type for annotation member":
public @interface MyAnnotation {
    Object myParameter;
    ^^^^^^
}

Obviously Object cannot be used as type of an annotation member. Unfortunately I could not find any information on which types can be used in general.

This I found out using trial-and-error:

  • String → Valid
  • int → Valid
  • Integer → Invalid (Surprisingly)
  • String[] → Valid (Surprisingly)
  • Object → Invalid

Perhaps someone can shed some light on which types are actually allowed and why.

4
possibly it varies by annotation - please show the code you're trying to write. - djna
Added to the question. But I don't think it varies. - Daniel Rikowski

4 Answers

350
votes

It's specified by section 9.6.1 of the JLS. The annotation member types must be one of:

  • primitive
  • String
  • an Enum
  • another Annotation
  • Class
  • an array of any of the above

It does seem restrictive, but no doubt there are reasons for it.

Also note that multidimensional arrays (e.g. String[][]) are implicitly forbidden by the above rule.

Arrays of Class are not allowed as described in this answer.

58
votes

I agree with Skaffman for the Types available.

Additional restriction : it has to be a compile-time constant.

For example, the following are forbidden:

@MyAnnot("a" + myConstantStringMethod())
@MyAnnot(1 + myConstantIntMethod())
35
votes

Also don't forget that annotations themselves can be part of an annotation definition. This allows some simple annotation nesting - handy in cases where you would like to have one annotation present many times.

For example:

@ComplexAnnotation({
    @SimpleAnnotation(a="...", b=3),
    @SimpleAnnotation(a="...", b=3),
    @SimpleAnnotation(a="...", b=3)
})
public Object foo() {...}

where SimpleAnnotation is

@Target(ElementType.METHOD)
public @interface SimpleAnnotation {
    public String a();
    public int b();
)

and ComplexAnnotation is

@Target(ElementType.METHOD)
public @interface ComplexAnnotation {
    public SimpleAnnotation[] value() default {};
)

Examples taken from: http://web.archive.org/web/20131216093805/https://blogs.oracle.com/toddfast/entry/creating_nested_complex_java_annotations

(original URL: https://blogs.oracle.com/toddfast/entry/creating_nested_complex_java_annotations)

14
votes

The concept of annotations fits really well with the design of my project, until I realized you can't have complex datatypes in the annotation. I got around it by using the class of what I wanted to instantiate rather than an instantiated object of that class. It's not perfect, but java rarely is.

@interface Decorated { Class<? extends PropertyDecorator> decorator() }

interface PropertyDecorator { String decorate(String value) }

class TitleCaseDecorator implements PropertyDecorator {
    String decorate(String value)
}

class Person {
    @Decorated(decorator = TitleCaseDecorator.class)
    String name
}