300

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.

Daniel Rikowski
  • 71,375
  • 57
  • 251
  • 329

4 Answers4

395

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.

Community
  • 1
  • 1
skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 44
    How does one find those pages/documents? I swear I google everytime before asking on StackOverlow and on many Java question someone posts a link to the JSL which answers my question. Why do I not find those pages via Google?! – Daniel Rikowski Sep 22 '09 at 07:17
  • 13
    The JLS isn't very google-friendly. You just need to know that it's there. – skaffman Sep 22 '09 at 07:21
  • 1
    the same information is also available in the annotation guide on sun's site (did find that googling): http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html – wds Sep 22 '09 at 12:52
  • 1
    Yes, I found that page, too, but I've must have missed that sentence, hidden in all that prose text. I've looked for something more table or list-like. – Daniel Rikowski Sep 22 '09 at 19:43
  • 15
    What's missing from the above list is "Annotation". You can have an annotation which contains another annotation or an array of another annotation. – Matt Mar 16 '12 at 17:54
  • Indeed, "annotation" was missing from the list. – Ceki Apr 15 '13 at 22:15
  • Perhaps not literally "Annotation", see http://stackoverflow.com/questions/679177/annotation-member-which-holds-other-annotations – Karl the Pagan Jul 09 '14 at 05:35
  • 2
    Note that "Class" here is mean to be the literal _java.lang.Class_ class, not all classes. – Kajzer Nov 22 '21 at 11:43
  • 1
    @skaffman "Arrays of Class are not allowed as described in this answer." I've read the link but I can't see why `Class[]` is not allowed, can you clarify? – Revin Nov 30 '21 at 14:11
  • @skaffman Edit the answer to say `java.lang.Class` to make it more unambiguous. – John Strood Jan 09 '22 at 15:59
  • Can I have an annotation member of type java.util.function.Function? – Kuldeep Yadav Nov 21 '22 at 08:56
41

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)

oujesky
  • 2,837
  • 1
  • 19
  • 18
fikovnik
  • 3,473
  • 3
  • 28
  • 29
15

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
}
jdmichal
  • 10,984
  • 4
  • 43
  • 42
Josh
  • 159
  • 1
  • 2
  • 1
    What target type did you use on @interface Decorated ? Tried to use this pattern in my project, everything compiles but at runtime i get a big fat null pointer on "String name" (in my case: List myList (trying to decorate a generic processor with a list of things it needs to do to process something) – niken Feb 03 '21 at 17:05
2

According to Oracle the valid types for annotation elements are:

1. Primitives (byte, char, int, long float, double)
2. Enums
3. Class (Think generics here Class <?>, Class<? extends/super T>>)
4. String
5. Array of the above (array[] of primitives, enums, String, or Class)
5. Another annotation.

A plus to note, all elements are inherently considered public and abstract.

Therefore

 static final variable(s) allowed as well.
Amos Kosgei
  • 877
  • 8
  • 14