Annotations were added to the jdk as of release 5.0. Annotations allow us to add additional information to the code without affecting the operation of the code itself. You can read more about annotations here.

There are two things we need to consider when working with annotations. One is the “annotation” itself and the other is the “annotation type”.

The annotation type is used to define an “annotation” whereas the actual annotation is the meta tag that will be used in your code.

Annotations can be grouped as one of three types, namely: Marker, Single-value, Multi-value.

Marker: These annotation types have no elements, except the annotation name.

 public @interface UselessAnnotation { }

@UselessAnnotation
 private void printData() {
 }

Single-value (Single-Element): Single-value annotation types contain a single element/value only.

 public @interface Cheesy {
 String cheeseType();
 }

@Cheesy("blue")
 public void grater() {
 }

Multi-value (Full-value): These types of annotations have multiple values/elements. You need to explicitly state the value for each element. We will be creating and using a multi-value annotation in this tutorial.

In this tutorial we will declare an annotation type and create an annotation instance which we will use to add some meta-data to a class.

We start by creating the annotation type DeveloperInfo.

package za.co.reegz.tutorials.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface DeveloperInfo {

String date();

String name();

String title();

String version();

}

Very simple. We declare DeveloperInfo as an interface using the @ symbol followed by the interface keyword. We then add some methods to it. These methods are abstract and therefore do not have an implementation. Also note that these methods do not accept parameters or have throw clauses. There are no variable declarations.

Cool. So now let’s create a class that will use the new annotation.

package za.co.reegz.tutorials.annotations;

@DeveloperInfo(name = "A Random Coder", title = "King Lazy", date = "2010/10/01",
 version = "1.0")
@SuppressWarnings("all") //this is here for a reason ;-) 
public class ARandomClass {

public void aRandomMethod() {
 // Some very random code...
 }

@DeveloperInfo(name = "Joe Dirt", title = "Codename: The Cleaner",
 date = "2010/09/01", version = "1.0")
 public void doSomeRealWork() {
 // Some real code here...
 }
}

What we’ve done here is add the DeveloperInfo annotation on a class level as well as a method level. So what now?

Now we test!

package za.co.reegz.tutorials.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import za.co.reegz.tutorials.annotations.ARandomClass;
import za.co.reegz.tutorials.annotations.DeveloperInfo;

public class AnnotationTest {

@SuppressWarnings("unchecked")
 public static void main(String[] args) {
 // An instance of the class which uses the annotation.
 ARandomClass aRandomClass = new ARandomClass();

Class clazz = aRandomClass.getClass();

for (Annotation annotation : clazz.getAnnotations()) {
 System.out.printf("Class-level annotation of type: %1$s n", annotation.annotationType());
 }

try {
 Method[] methods = clazz.getMethods();
 for (Method method : methods) {
 DeveloperInfo info = method.getAnnotation(DeveloperInfo.class);
 if (info != null) {
 System.out.printf("Method %1$s contains the DeveloperInfo annotation.n",
 method.getName());
 printAnnotationInfo(info);
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

/**
 * Outputs the data stored in the annotation.
 *
 * @param info
 */
 private static void printAnnotationInfo(DeveloperInfo info) {
 System.out.printf("tName: %1$s, Title:%2$s, Date:%3$s, Version:%4$sn",
 info.name(), info.title(), info.date(), info.version());
 }

}

Cool.. What we have done with this test class is print out all annotations declared on both class and method level.

But something’s not quite right is it?? You should be wondering why the SuppressWarnings annotation wasn’t returned in the getAnnotations() method. Take a look at the source code for the annotation and you will notice that the RetentionPolicy is set to source level.  As the name implies, the RetentionPolicy indicates how long the annotated type will be available for.

Have a look at the source of RetentionPolicy to understand more about the types of policies available and their scope.

And that’s it.. Go forth and spread the annotation love!