Creating Java annotations

I am pretty sure most of us have used custom annotation in our projects at some point. Today we will go step by step and see how to create our own! Annotations in Java are everywhere, from @test, @BeforeClass, @AfterClass in Junit, @Override,@Deprecated in Java SE or @Inject, @Decorator in Java EE or @Entity in JPA.

The first step is to declare an interface with @ .The use of @ denotes that our interface will be of annotation type. Now, if we leave it as is and don’t add any methods we have a marker annotation.

public @interface Furious {

}

But marker annotation get their own annotation which denote what type of the program they target (@Target) and under which conditions(@Retention). Our previous example can become a bit more complex:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Furious {

}

In our case we marked our annotation as RetentionPolicy.RUNTIME because we want it to be accessed during runtime through reflection. Also ElementType.TYPE denotes that it will only be applied on classes. As described in the Java API here are the possible values for @Retention :

- SOURCE
public static final RetentionPolicy SOURCE
Annotations are to be discarded by the compiler.

- CLASS
public static final RetentionPolicy CLASS
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.

- RUNTIME
public static final RetentionPolicy RUNTIMEAnnotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.

Respectively here you can find the allowed types for @Target.

Ok so we have created our annotation, if we like we can also add arguments to it:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Furious {
  public String name();
}

Now that we are ready lets mark our class with the annotation

@Furious(name = "nomikosi")
public class TestClass {

}

Of course we don’t just mark annotations without a reason, we do want them to serve a purpose. In our case we just want to print something in the console. Of course business logic usually is a lot more complex.

public static void main(String[]args){

     Class clazz = TestClass.class;
     Annotation[] annotations = clazz.getAnnotations();

     for(Annotation annotation:annotations){
         if(annotation instanceof Furious){
             System.out.println("Dont play with a furious class!!");
         }

     }

 }

Finally one useful trick, if you like your annotation to be inherited by sub classes mark them with @Inherited.

As additional reference material you can check out this and this guide from Oracle. Code for this sample project can be found at my repo.