Detailed Java annotations tutorial and custom annotations

  • 2020-04-01 04:37:58
  • OfStack

Java annotations provide some information about the code, but do not directly affect the content of the code it annotates. In this tutorial, we will learn Java annotations, how to customize annotations, how to use annotations, and how to parse annotations through reflection.

Annotations were introduced in Java1.5, and are now heavily used in many Java frameworks, such as Hibernate, Jersey, and Spring. Annotations are embedded in a program as metadata. Annotations can be parsed by some parsing or compilation tools. We can also declare that annotations are useful during compilation or execution.

Before using annotations, program source data was only available through Java annotations and javadoc, but annotations provide much more than that. Annotations not only contain metadata, they also act on the program as it runs, and the annotation interpreter USES them to determine the order of execution of the program. For example, in Jersey webservice we add a **PATH** annotation in the form of a string of uris to a method, and the jerser interpreter determines that the method calls the given URI while the program is running.

Create Java custom annotations

Creating a custom annotation is similar to creating an interface, but the annotation's interface keyword needs to start with the @ symbol. We can declare methods for annotations. Let's look at an example of an annotation, and then we'll discuss some of its features.


package com.journaldev.annotations;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
  public @interface MethodInfo{
  String author() default 'Pankaj';
  String date();
  int revision() default 1;
  String comments();
}

Annotation methods cannot take parameters;
The Annotation method return value type is limited to: base type, String, Enums, Annotation, or an array of these types;
  Annotation methods can have default values;
  Annotations themselves can contain meta-annotations that are used to annotate other annotations.
There's a There are four types of meta-annotations :

1. @ Documented Indicates that the element with this annotation can be documented by tools such as javadoc. This type should be used to annotate those types that affect the customer's use of annotated element declarations. If a declaration is annotated using Documented, this type of annotation is used as a public API for the annotated program member.

2. @ Target Specifies the scope of program elements that this type of annotation can annotate. Value of the yuan notes for the TYPE, METHOD, CONSTRUCTOR, FIELD, etc. If the Target meta-annotation does not appear, the defined annotation can be applied to any element of the program.

3. @ Inherited Specifies that the annotation type is automatically inherited. If the user queries for the meta-annotation type in the current class and the declaration of the current class does not contain the meta-annotation type, then Inherited meta-annotations are also automatically inquired for in the parent class of the current class, and this action is repeated until the annotation type is found, or until the top-level parent class is queried.

4. @ Retention Specifies how long the Annotation is retained. The value of RetentionPolicy is SOURCE,CLASS and RUNTIME.

Java built-in annotations

Java provides three built-in annotations.

1. @ Override When we want to copy a method in a parent class, we need to use this annotation to tell the compiler that we want to copy the method. This will prompt the compiler for an error message when a method in the parent class is removed or changed.

2. @ Deprecated We should use this annotation when we want the compiler to know that a method is not recommended. Java recommends this annotation in javadoc, and we should provide reasons why it is not recommended and alternatives.

3. @ SuppressWarnings This simply tells the compiler to ignore specific warnings, such as using native data types in generics. Its retention policy is SOURCE and is discarded by the compiler.

Let's take a look at an example of a Java built-in annotation with reference to the custom annotation mentioned above.


package com.journaldev.annotations;
 
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
 
public class AnnotationExample {
 
public static void main(String[] args) {
}
 
@Override
@MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 1)
public String toString() {
  return 'Overriden toString method';
}
 
@Deprecated
@MethodInfo(comments = 'deprecated method', date = 'Nov 17 2012')
public static void oldMethod() {
  System.out.println('old method, don't use it.');
}
 
@SuppressWarnings({ 'unchecked', 'deprecation' })
@MethodInfo(author = 'Pankaj', comments = 'Main method', date = 'Nov 17 2012', revision = 10)
public static void genericsTest() throws FileNotFoundException {
  List l = new ArrayList();
  l.add('abc');
  oldMethod();
}
 
}

I believe this example is self-explanatory and shows the application in different scenarios.

Java annotation resolution
We will use reflection techniques to parse annotations for Java classes. So the RetentionPolicy of the annotation should be set to RUNTIME otherwise the annotation information of the Java class will not be available during execution so we cannot get any data related to the annotation from it.


package com.journaldev.annotations;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
 
public class AnnotationParsing {
 
public static void main(String[] args) {
  try {
  for (Method method : AnnotationParsing.class
    .getClassLoader()
    .loadClass(('com.journaldev.annotations.AnnotationExample'))
    .getMethods()) {
    // checks if MethodInfo annotation is present for the method
    if (method.isAnnotationPresent(com.journaldev.annotations.MethodInfo.class)) {
      try {
    // iterates all the annotations available in the method
        for (Annotation anno : method.getDeclaredAnnotations()) {
          System.out.println('Annotation in Method ''+ method + '' : ' + anno);
          }
        MethodInfo methodAnno = method.getAnnotation(MethodInfo.class);
        if (methodAnno.revision() == 1) {
          System.out.println('Method with revision no 1 = '+ method);
          }
 
      } catch (Throwable ex) {
          ex.printStackTrace();
          }
    }
  }
  } catch (SecurityException | ClassNotFoundException e) {
      e.printStackTrace();
     }
  }
 
}

Running the above program will output:


Annotation in Method 'public java.lang.String com.journaldev.annotations.AnnotationExample.toString()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=Main method, date=Nov 17 2012)
Method with revision no 1 = public java.lang.String com.journaldev.annotations.AnnotationExample.toString()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @java.lang.Deprecated()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.oldMethod()' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=1, comments=deprecated method, date=Nov 17 2012)
Method with revision no 1 = public static void com.journaldev.annotations.AnnotationExample.oldMethod()
Annotation in Method 'public static void com.journaldev.annotations.AnnotationExample.genericsTest() throws java.io.FileNotFoundException' : @com.journaldev.annotations.MethodInfo(author=Pankaj, revision=10, comments=Main method, date=Nov 17 2012)

That's all for this tutorial, and hopefully you learned something from it.


Related articles: