Annotations are used to mark program elements, possibly with extra information. Annotations are designed so that markers can be read and used by annotation processors at various points along the lifecycle of program development.
Annotations provide a means of adding structured information to program elements that can be processed easily.
1 | @ name ( ) |
2 | @ name (
element-value ) |
3 | @ name (
element-value-list ) |
where...
name | is a qualified or simple name that refers to the annotation. |
element-value | is a constant expression or another (nested) annotation that
matches the type of the annotation's value element.
|
element-value-list | is a map of annotation elements to constant expressions or other
annotations. The map is specified as a comma-separated list of
key-value pairs of the form:
element-name where element-name specifies
which element the value is assigned to and value
specifies the value to assign.
= value
|
1 An annotation without attributes provided (a marker annotation).
2 An annotation that specifies a
single attribute, value
, of its annotation type.
3 A normal annotation, with attributes explicitly named.
Annotations associate supplementary information with a Java element in a program. They can apply to:
The location in source code that an annotation may be present at to apply to a certain element is dictated by the syntax for that element. For example, see Method Declarations. Semantic rules invovling the annotation's declared targets define whether annotations deemed to apply to certain elements are illegal and will raise compiler errors.
Annotations that apply to declarations are almost always specified in
the declaration's modifier list, intermixed with keyword
modifiers, such as public
, protected
, static
,
final
, etc. Annotations that apply to type uses may appear
in these same locations (subject to some constraints) or may appear
more closely to the type. For details, see below.
Although not required, an annotation declaration can restrict (or
expand) its use to certain program elements using the @java.lang.annotation.Target
meta-annotation. The @Target
annotation has a non-default
java.lang.annotation.ElementType[]
member, which specifies
the types of program elements that the annotation may be applied to.
The ElementType
array may not contain duplicates when used
as an argument to the @Target
annotation.
There are 10 possible targets that an annotation declaration may
specify in a @Target
meta-annotation:
Enum Constant | Target | Description | Index |
---|---|---|---|
TYPE |
Type | any class , enum , and interface
declarations (including any @interface annotation
declarations).
|
1 |
ANNOTATION_TYPE |
Annotation Type | any @interface annotation declarations.
|
2 |
METHOD |
Method | any method declaration, including abstract
declarations and annotation element declarations.
|
3 |
CONSTRUCTOR |
Constructor | any constructor declaration. | 4 |
FIELD |
Field | any field declaration, including constants declared in @interface s
and enum constants. (Note that annotations targeting
fields can be used on their own member constants.)
|
5 |
PARAMETER |
Parameter | any method parameter (not including receiver parameters). | 6 |
LOCAL_VARIABLE |
Local Variable | any local variable declaration, including those in the header of a
for loop or try -with-resources statement.
|
7 |
PACKAGE |
Package | implementation-chosen package declarations. | 8 |
TYPE_PARAMETER |
Type Parameter | any type parameter declaration. | 9 |
TYPE_USE |
Type Use | the use of a type. | 10 |
Annotations whose declarations do not specify a target can be applied to:
That is, they can be applied to all annotatble program elements except Type Parameters and Type Uses.
Otherwise, if @Target
is applied to an annotation's
declaration, that annotation may be applied to the union of the types
permitted by each ElementType
specified in the @Target
annotation. For example, if @Target({ TYPE, FIELD })
is
applied to a declaration, the annotation may be applied to both
type declarations (e.g. classes, interfaces, etc.) and fields.
TYPE
Target
The TYPE
target allows an annotation to be applied to any
type declaration.
class
declaration, (including nested, inner, and local classes).
interface
declaration, (including @interface
declarations and any nested interface
or @interface
declarations),
TYPE
target can
be applied to its own declaration.)
ANNOTATION_TYPE
Target
The ANNOTATION_TYPE
target is a subset of the TYPE
target. The ANNOTATION_TYPE
allows an annotation to apply
to annotation declarations.
An annotation that targets both TYPE
and ANNOTATION_TYPE
can be applied to the same set of program elements as an annotation
that targets only TYPE
.
METHOD
Target
Allows an annotation to apply to methods. Such annotations may be put within the modifier-list of a method declaration.
Annotation declarations with this target can apply to annotation elements, including their own annotation elements.
CONSTRUCTOR
Target
Allows an annotation to target any constructor declaration. The annotation is put in the modifier-list of the declaration.
FIELD
Target
Allows an annotation to target any field declaration. Such annotations
can only be placed in the modifier-list
of a field declaration. Reflectively, the annotation can be accessed
from any java.lang.reflection.Field
that is a part of the
annotated declaration, though the annotation cannot be applied to only
some fields in a multi-field declaration.
PARAMETER
Target
Allows an annotation to target any parameter in a:
catch
clause.
The annotation is put in the modifier-list of the parameter.
Note that this target does not allow an annotation to be applied to receiever parameters, as annotations that are a part of a receiver parameter may only be applied to the type use within the receiver parameter declaration.
LOCAL_VARIABLE
Target
Allows an annotation to target any local variable declaration,
including those inside the headers of for
loops and try
statements. The annotation is put in the modifier-list,
just like the keyword final
if it is present.
PACKAGE
Target
Allows an annotation to target package declarations. In any given package, only one such package declaration is allowed to be annotated. The annotation is put in front of the declaration, in the declaration's "modifier list." As of Java 8, there are no modifiers applicable to a package declaration other than annotations.
Implementations typically choose to specify a canonical package
declaration, and require that this be the only package declaration that
be annotated. Many implementations follow suggestions made by the
specification that this canonical declaration be in a file called package-info.java
which is situated directly in the package.
This means that, in some implementations of the Java compiler, an annotated package declaration must go in a specific file, rather than go in any file subject to the constraint that there is only one such annotated declaration per package.
TYPE_PARAMETER
Target
Annotations with this target can be applied to type parameters in a declaration of a generic:
The type parameters declared in the type-parameter-list
of these program elements can each be annotated with annotations
targetnig TYPE_PARAMETERS
. Such annotations are located
textually immediately in front of the name of the type variable in the
declaration.
TYPE_USE
Target
The TYPE_USE
target allows an annotation to be applied to
types in type contexts. Type contexts are contexts where a type
is used to denote the literal type of a value, object, or other thing.
For example, the type in a simple variable declaration is used to
denote the type of value the variable can store, and the type in an extends
clause is used to denote what the type is being extended. In some
cases, types can be used as other objects, such as a simple container
for a nested class; the TYPE_USE
target does not permit an
annotation to be applied in these other cases.
The TYPE_USE
target permits an annotation to be located as
follows:
void
return type in a method declaration
(including the element type of an annotation element declaration),
catch
clause,
extends
clause,
of a class
or interface
declaration,
implements
clause,
static
context), A type can surround or enclose a member:
static
, the type surrounds
that member.
static
),
that type encloses that member.
Types used in a reference to qualify other types may only be
annotated if they enclose the qualified type. For example, if Ann
is an annotation that targets TYPE_USE
,
class Outer {
class Inner { }
private @Ann Outer.Inner someField; // Make a class variable of type Outer.Inner, where Outer is annotated.
}
The above @Ann
annotation applies to Outer
and compiles, since the identifier Outer
refers to
the class Outer
as an enclosing instance of
the class Inner
; the meaning of the Outer
identifier is semantically a type enclosing Inner
.
However, if Inner
is static
then the
class Inner
is no longer an instance member of Outer
and outer no longer encloses it:
class Outer {
static class Inner { }
// private @Ann Outer.Inner someField; // No longer compiles. Outer is considered nothing more than a container.
}
Outer
is no longer semantically considered a type in
the field declaration, so it may not be annotated as a type use.
It is simply considered a "container" that statically contains Inner
.
In both cases, Inner
may be annotated in the field
declaration, since it is a type in both respects:
class Outer {
static class Nested { }
class Inner { }
private Outer.@Ann Nested field1;
private Outer.@Ann Inner field2;
}
throws
clause,
extends
clause of a type parameter
declaration),
new
operator that is instantiated by the new
expression,
new
operator to denote the
supertype of an anonymous class being instantiated,
instanceof
operator,
new
, such as int[]::new
or Object::new
),
::
in a method reference where new
does not follow the ::
).
java.lang.@Ann Object myObjectVariable = "abc";
Object
is a simple name, and it immediately follows @Ann
,
so @Ann
applies to the type Object
used in
that variable declaration.
This also has implications for array types:
@Ann Object[][] objectMatrix;
The @Ann
annotation applies only to the type Object
as it is used in the variable declaration. To apply the annotation
to Object[]
or Object[][]
as used in the
declaration, the annotation would need to be immediately before the
appropriate pair of brackets. This occurs because an array type is
textually composed of multiple types, so in the above variable
declaration, the three types Object
, Object[]
,
and Object[][]
are being used.
[]
) used to denote
an array dimension in a type. In this case, the annotation applies to
the type of dimension indicated by the targeted pair.
In an array type with multiple dimensions, a bracket pair
to the left represents an array type whose component is an
array of dimension equal to the number of bracket pairs to the right.
For example:int @A[][][]@B[][] highDimensionalArray;
The bracket pair that @A
applies to represents the a
5-dimensional array type: int[][][][][]
. The bracket
pair that @B
applies to represents the 2-dimensional
type: int[][]
.
...
token of a variable arity
parameter, in which case the annotation applies to the type
represented by the ...
. The
...
is treated as the innermost dimension of the array
represented by the parameter's type. That is, in a parameter of type
int[][] @A...
, the parameter is equivalent to int[][]
@A[]
and (in both cases) @A
applies to the type
int[]
.
void
and is specified by a simple
name,
for
and try
-with-resources statements.
TYPE_USE
does not permit an annotation to be used
on:
void
(as a method's return type),import
declaration,
this
or super
keyword (including in method references, e.g. Type.super::method
,
or in the identifier optionally used to qualify a receiver parameter
in an inner class's constructor), or An
example of such an identifier being illegally annotated is: class Outer {
class Inner {
Inner(Outer @A Outer.this) { } // Illegal annotation
// Outer within Outer.this cannot be annotated.
}
}
Note that the receiver parameter's type may still be annotated.
despite each of these being uses of types.
An annotation that targets TYPE_USE
while also targeting
any of the following declarations:
METHOD
CONSTRUCTOR
FIELD
LOCAL_VARIABLE
PARAMETER
may apply to both the declaration and its type if used within the declaration's modifier list. This may happen even if the declaration declares type parameters (in the case of constructor and method declarations, considering a constructor's type to be the type of object it constructs).
TYPE_USE
Examples
TYPE_USE
. This can be done if the
method declares any type parameters and the annotation is placed
within the method's modifier-list as
well as immediately before the method's return type, so long as the
return type is not void
.
Attempting to access the annotation on the return type, via
reflection, raises a java.lang.annotation.AnnotationFormatError
,
reflecting the invalid application of the annotation in bytecode.
Code to reproduce the error is as follows:
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface A { }
@A <T> @A int test() {// Problematic line
return 0;
}
@Repeatable
, resulting in a java.lang.annotation.AnnotationFormatError
when the annotation is accessed, as from the following code: @Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface As {
A[] value();
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(As.class)
@interface A { }
@A <T> @A int test() {// Problematic line
return 0;
}
Such results in an error because of the way annotations are compiled.
TYPE_USE
to be applied to void
in a method declaration if the declaration declares a type parameter
list. Code containing such an annotation successfully compiles by the
IDE's compiler, and the annotation is not available during runtime,
even if its retention is RUNTIME
. Code to reproduce the
behavior is as follows: @Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface A { }
<T> @A void test() { }
The correct behavior is for a compilation error to be raised.
TYPE_USE
from being applied to a
constructor declaring type-parameters if located after that
constructor's type-parameter-list: @Target(TYPE_USE)
@interface A { }
class Ex {
<T> @A Ex() { } // Compiler complains that "@" symbol is not allowed here
}
Curiously, duplicating the annotation by placing it in the modifier
list of the constructor, before the type-parameter-list,
raises an additional error that @A
is duplicated:
@Target(TYPE_USE)
@interface A { }
class Ex {
@A <T> @A Ex() { } // Compiler complains that "@" symbol is not allowed here
}
TYPE_USE
can be construed as being either:
A simple example is in the method declaration:
@A int one() { return 1; }
In these cases, the annotation still applies to the declaration's type, (and is considered to apply only once). It is possible for an annotation to be unambiguously placed into either of these two parts of a declaration in any declaration that permits type parameters. For example, if the method declaration above declared a type parameter list:
@A <T> int one() { return 1; }
the annotation @A
then unambiguously falls within the
method declaration's modifier-list.
This phenomenon is possible for method declarations and constructor
declarations, alike. This phenomenon gives rise to the two
aforementioned distinct rules listed above that say where TYPE_USE
annotations are permitted, but do not have any effect on how the
annotation applies, as annotations at the end of the modifier-list of a declaration that
target TYPE_USE
will still apply to the declaration's
type.
Types that are not:
can be fully qualified by a package name when used as a declaration's
type, deterring the ability of an annotation in the declaration's modifier-list from applying to both the
declaration and the declaration's type. Such annotations targeting
any of the five potentially
ambiguous declarations as well as TYPE_USE
can be
made to only apply to the declaration, since the simple name closest
to the declaration's modifier list will be a package name, not a type
name:
@Target({ TYPE_USE, FIELD })
@interface A {}
class Test {
@A Object someField; // @A applies to Object and the whole declaration
@A java.lang.Object someOtherField; // @A applies only to the whole declaration
}
In the code example, since @A
targets both field
declarations and type use, it applies to someField
's
declaration and its type: Object
, since Object
is a simple name. In the declaration of someOtherField
,
@A
can only apply to the declaration, since the the
simple name closest to @A
is java
which
names a package.
This is also possible to use for static
ally nested
types, even in the default package.