AnnotationsSince Java 5

New in Java 5, annotations (also called metadata) allow you to add information to your code that the compiler or some other tool can use.  An annotation can be used anywhere a Java modifier (e.g., public) can be used.  (Style: annotations first.)

Think of an annotation as a Post-It® note you put on some piece of code.

For example the annotation @Deprecated can be used as a method modifier to inform the compiler the method, although legal, is discouraged in favor of a new (unspecified) method.

In pre-Java 5, a comment above a method could contain the word “@Deprecated”, and the compiler would issue warnings if other classes used that method.  This is a rare example of a compiler altering the generated code due to a comment.  (Most compilers completely ignore comments.)

The annotation @Override can be used as a method modifier when overriding inherited methods.  This annotation tells the compiler you intend the method to override something and not overload or define a new method.  The compiler generates an error if you make a mistake like this:

class Foo {
  @Override
 
public boolean equals( Foo f ) { ... }
}

should produce an error, but wouldn’t without the annotation.  (Qu: Do you see the error?  Ans: Argument must be of type Object.)

JUnit 4 shows a good use of annotations.  It is in many ways easier to use than JUnit 3.  All you do to define a test method is precede it with @Test annotation.  That’s it!  When you later run the JUnit program, giving it the class containing your tests, it finds the test methods and runs them using this annotation.  TestNG uses this too.

Code Generation and Interjection

Other types of annotations can be defined (by anyone) and used to automatically generate “boilerplate” code.  For example, @Property might be used to mark some properties of a class as JavaBean properties, and could automatically generate the get and set methods required.  Or an @RMI annotation could be defined that would cause stub and skeleton classes to be generated automatically.  In JavaEE, EJBs use these to automatically manage objects and to initialize instance properties.  This is called interjection.  You can write your own annotation processors, found in classpath automatically by the compiler.  However, creating such processors yourself is very difficult; it is a black art.

Standard Java 5 SE Annotations

Java defines these annotations as standard (see java.lang (scroll to bottom) and java.lang.annotation package): @Deprecated, @Documented, @Inherited, @Override, @Retention, @SuppressWarnings, and @Target.  Several more were added in Java 7 and Java 8.

A programmer should know and use @Deprecated, @Override, and @SuppressWarnings; the rest are only useful when defining your own annotations.

With @SuppressWarnings, the list of warnings is not standardized.  However, every compiler warning belongs to one of two standard categories, deprecation and unchecked.  The unchecked warning can occur when interfacing with legacy code written before the advent of generics.  To suppress multiple categories of warnings, use the following syntax:

@SuppressWarnings({"unchecked", "deprecation"})

The Java 7 @SafeVarargs annotation, when applied to a method or constructor, asserts that the code does not perform potentially unsafe operations on its varargs parameter.  When this annotation type is used, unchecked warnings relating to varargs usage are suppressed.

The Java 8 @FunctionalInterface annotation indicates that the type declaration is intended to be a functional interface (a lambda expressions, sort of an anonymous method).

Annotations other than these standard ones won’t do anything on their own; you’ll need to pre-process your source code with apt, javadoc, or some other tool that recognizes those annotations.  Before annotations, you marked methods deprecated using a special Java doc method (the compiler peeks at these): /** @deprecated ...reason...*/.  You should still do this, to document why the method is deprecated and what should be used instead.

Note!  It is not an error to use a deprecated method or variable from within that same class!

Annotations can optionally be passed values called elements.  These values are then available to the extra tools that pay attention to them.  For example, to say what warning messages to suppress. use:  @SuppressWarnings(value="unchecked").  Here value is an element of the annotation, which may define as many of these as desired.  Each element can be of a simple type or an array.

As a convenience, when there is only one element defined and it has the name value, you can omit the name.  So the above can be simplified to: @SuppressWarnings("unchecked").  Also, if there are no elements at all, you can omit the parenthesis too.

With @SuppressWarnings, the list of warning that can be suppressed varies depending on the compiler used.  There is a list for Eclipse in the on-line docs (search for suppresswarnings).  Netbeans uses (apparently) the JDK ones.  You can see a list by “javac ‑X”, and look at the list that shows for the “-Xlint” option.)

Using Annotations

Using annotations is simple; it is defining them that gets tricky.  Just place one or more annotations directly before the code you are annotating.  If there are no elements (arguments to annotations are called elements) passed to the annotation, you don’t need any parenthesis.  So both of these work the same way:

@MarkerAnnotation class Foo { ... }
@MarkerAnnotation() class Foo { ... }

(Annotations that take no element arguments are called marker annotations.)

If an annotation takes exactly one value (for an element named value), you can just pass the value (of the correct type).  If there is more than one element value being passed, or you didn’t name the one element “value”, you must use the syntax name=value, ...  For example, an annotation that takes one String element could be used either of these ways:

@OneItemAnnotation("XYZ") class Foo { ... }

@OneItemAnnotation(value="XYZ") class Foo { ... }

If the value is an array, you can use the literal array notation like this:

@Reviewers( {"Moe", "Larry", "Curly"} ) class Foo {...}

(Show example on Website.)

Defining Your Own Annotations

To define your own annotation, you create a special type of interface.  An annotation type with no elements is termed a marker annotation type.  Each element (a property) of an annotation is defined just like a method declaration, but don’t let that fool you.  Element declarations must not have any parameters, generics, or throws clauses; they’re not really methods at all.

Element types are restricted to primitives plus String, Class, enum, annotation, and arrays of those types.

@interface AnnotationName {}  // A marker annotation
                              // with no content

In annotations with a single element, the one element should be named value:

@interface AnnotationName {
   elementType value();
}

(You can call an element anything you like; but the name value is treated specially so you should stick with this convention.)

Annotations can have as many elements as you like:

@interface AnnotationName {
   elementType elementName1();
   elementtype elementName2(); // ...
}

Again you can name these anything.  If your annotation has one commonly used element, you should name it value.

You can specify default values for elements too:

@interface AnnotationName {
   elementType elementName() default literal;
   ...

}

You can specify if Java doc comments should show the annotation or not:

@Documented
public @interface RFE {
   int    id();
   String description();
   String assignedTo() default "[unassigned]";
   String dateRequested() default "[unknown]";
}

Note, only things that show up in the Java doc (HTML) output can show annotations.  That is, the annotations on local variables or private members won’t appear, since those don’t get processed by javadoc.

Here’a a use of the RFE annotation:

@RFE( id = 123, description = "Enable telepathy",
 assignedTo = "Hymie Piffl",  date = "2/30/2010" )
public static void readMinds () { ... }

When defining your own annotations, you can add other annotations to them, to define their properites.  These additional annotations are:

·       Some annotations are for internal use only.  Other annotations are part of the public interface of the class (or whatever) and users of your code need to know about them.  To cause javadoc (or other similar tools) to include an annotation in the generated documentation, annotate your annotation with @Documented.  (Remember, if you annotate something within a method, it won’t show in the Java docs regardless.)

·       You use @Target to restrict where your annotation can be applied.  The default is that anything can be annotated.  But you can restrict your annotation to local variables, fields, methods, classes, packages, method parameters, etc.  (See java.lang.annotation.ElementType)  For example, to restrict some annotation to be used only on methods, use:

@Target( ElementType.METHOD )
@interface MyMethodAnnotation { ... }

·       @Inherited shows that the annotation may be inherited (i.e., mark the parent with the annotation, and the child will show as having it too).

·       @Repeatable (new in Java 8) This means the annotation can be used multiple times on the same thing.  For example:

@Reviewer("Moe")
@Reviewer("Larry")
@Reviewer("Curly")
class Foo { ... }

To allow this, you need to declare the @Reviewer annotation with @RepeatableIn addition, you need to declare the element value as an array.  The whole thing would look like this:

@Repeatable
public @interface Reviewer {
   String[] value ();
}

·       You can control if your annotation will be part of the Class object loaded into RAM (RUNTIME), in the .class file but not the Class object (CLASS), or just in the source code and not in the .class file (SOURCE).  This is known as the retention policyCLASS is the default.  For example:

@Retention( RetentionPolicy.SOURCE )  // ibid

To use reflection to check for annotations, the policy must be RUNTIME.

Here’s one last example, inspired by some discussions on the comp.lang.java.programmer newsgroup (11-12, 2013).

When using @Override, there is no element to say which class’s or interface’s method you are overriding.  If your class implements several interfaces, and/or you have a deep inheritance tree, it can be difficult to remember which one you were attempting to override when you get a compiler error.  Of course, you could just put that information in a method’s comment; Java doc will show it as well.  But we can also create a new annotation to record from where an overridden method originates:

@Documented
@Target(ElementType.METHOD)
//@Retention(RetentionPolicy.RUNTIME) //For Reflection
@interface From {
   Class<?> value();
}

And use it like so:

@From(Foo.class) @Override public void aMethod(){}