Creating Custom Annotations in Android

Annotations are Metadata.

And Metadata is a set of data that gives information about other data.

So in this case, annotations are essentially just information about your code.

@Override
public String toString() {
  return “I am Amit Shekhar”;
}

Here, you have @Override annotation over the method toString(). Even if you don’t put the @Override annotation, this code will still work fine.

So, what is the use of @Override annotation here?

@Override tells the compiler that this method is an overridden method (metadata about the method) and whether any such method exists in its parent class. Then it throws a compiler error (the method does not override a method from its super class).

Look at the below code. It will not compile, as there is typo error: “toStrring” instead of “toString”.

@Override
public String toStrring() {
  return “I am Amit Shekhar”;
}

But it will compile, if there is you don’t add an @Override annotation.

Creating custom annotations

For Example, Let’s create @Status annotation

Create a Status interface like below:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Status {
  public enum Priority {LOW, MEDIUM, HIGH}
  Priority priority() default Priority.LOW;
  String author() default “Amit”;
  int completion() default 0;
}

@Target specifies where an annotation can be placed. If you don’t specify this, the annotation can be placed anywhere. Here are some valid targets:

  • ElementType.TYPE (class, interface, enum)
  • ElementType.FIELD (instance variable)
  • ElementType.METHOD
  • ElementType.PARAMETER
  • ElementType.CONSTRUCTOR
  • ElementType.LOCAL_VARIABLE

@Retention defines how long the annotation should be kept around. Here are some valid retention policies:

  • RetentionPolicy.SOURCE — Discard during the compile step. These annotations don’t make any sense after the compilation has completed, so they don’t need to be turned into bytecode. Examples: @Override, @SuppressWarnings
  • RetentionPolicy.CLASS — Discard during the class load. Useful when doing bytecode-level post-processing. Somewhat surprisingly, this is the default.
  • RetentionPolicy.RUNTIME — Don’t discard. This annotation should be available for reflection at runtime.

Using annotations in your Class Foo.java:

@Status(priority = STATUS.Priority.MEDIUM, author = “Amit Shekhar”, completion = 0)
public void methodOne() {
 //no code
}
@Status(priority = STATUS.Priority.HIGH, author = “Amit Shekhar”, completion = 100)
public void methodTwo() {
 //complete code
}

Now you can print the status of all the methods like below:

Class foo = Foo.class;
 for(Method method : foo.getMethods()) {
    Status statusAnnotation = (Status)method.getAnnotation(Status.class);
    if(statusAnnotation != null) {
     System.out.println(" Method Name : " + method.getName());
     System.out.println(" Author : " + statusAnnotation.author());
     System.out.println(" Priority : " + statusAnnotation.priority());
     System.out.println(" Completion Status : " + statusAnnotation.completion());
    }
 } 

If you have only one attribute inside an annotation, it should be named “value” and can be used without attribute name while using it:

@interface Status{
 int value();
}
@Status(50)
 public void someMethod() {
  //few codes
 }

And that’s how you create custom annotations.

That’s all, Happy Coding :)

Also, Let’s become friends on Twitter, Linkedin, Github, and Facebook.