HomeJavaHow to Create Annotations in Java?

How to Create Annotations in Java?

How to Create Annotations in Java?

Annotations have been a powerful part of Java, but most times we tend to use them rather than create them. For example, it is not always difficult to find annotations in Java source code like @Override which is processed by the Java compiler, @Autowired used by the Spring framework. But how often do you see custom annotations? Yes, very rarely. Custom annotations at times can be very useful and become so handy in developing readable code. Creating custom annotations can also be useful in understanding how the common frameworks, such as Hibernate, Spring, etc they accomplish their goals. Let’s now dig into “How to Create Annotations in Java?

Before creating the annotations lets first understand:

  • What annotations are?
  • Why were annotations introduced?
  • How are they Created?
  • How to process them?

What are Annotations?

One word to explain Annotation is Metadata. (Metadata is data about data). Basically, Annotations are decorators that when applied to Java code, such as classes, methods, or fields associate the metadata with the construct. The annotations defined are benign and do not execute any code of themselves, instead, they can be used by runtime frameworks or the compiler to perform certain actions.

An annotation is a marker which associates information with a program construct, but has no effect at run time.

Java Language Specification (JLS), Section 9.7

Why were Annotations Introduced?

Prior to the introduction of annotations (and even after), XML was extensively used for metadata and separate the configurations from the code. With the growing up of enterprise applications, XML maintenance was getting troublesome. The Application developers and Architects started to look for solutions which could be coupled closely with the code instead of XML which is loosely couples (in some of the cases almost separate) from the code.

Suppose, you want to set some application-wide constants/parameters. In this scenario, XML would be a better choice because this is not related to any specific piece of code. If you want to expose some method as a service, annotation would be a better choice as it needs to be tightly coupled with that method and developer of the method must be aware of this.

Another important factor is that annotation defines a standard way of defining metadata in code. Prior to annotations people also used their own ways to define metadata. Some examples are – using marker interfaces, comments, transient keywords etc. Each developer decided his own way to decide metadata, but annotation standardized things.

These days most frameworks use the combination of both XML and Annotations to leverage positive aspects of both.

How are they Created?

In order to start creating an annotation, we first need to have two important pieces of information:

Retention Policy and Target

A retention policy specifies how long, in terms of the program lifecycle, the annotation should be retained for. For example, annotations may be retained during compile-time or runtime, depending on the retention policy associated with the annotation. As of Java 9, there are three standard retention policies, as summarized below:

Source Annotations are discarded by the compiler
Class Annotations are recorded in the class file generated by the compiler but are not required to be retained by the Java Virtual Machine (JVM) that processes the class file at runtime
Runtime Annotations are recorded in the class file by the compiler and retained at runtime by the JVM

Annotation has exactly one associated retention policy.

The runtime option for annotation retention is one of the most common, as it allows for Java programs to reflectively access the annotation and execute code based on the presence of an annotation, as well as access the data associated with an annotation.

The target of an annotation specifies which Java constructs an annotation can be applied to. For example, some annotations may be valid for methods only, while others may be valid for both classes and fields. As of Java 9, there are eleven standard annotation targets, as summarized below:

Annotation Type Annotates another annotation
Constructor Annotates a constructor
Field Annotates a field, such as an instance variable of a class or an enum constant
Local variable Annotates a local variable
Method Annotates a method of a class
Module Annotates a module (new in Java 9)
Package Annotates a package
Parameter Annotates a parameter to a method or constructor
Type Annotates a type, such as a class, interfaces, annotation types, or enum declarations
Type Parameter Annotates a type parameter, such as those used as formal generic parameters
Type Use Annotates the use of a type, such as when an object of a type is created using the new keyword, when an object is cast to a specified type, when a class implements an interface, or when the type of a throwable object is declared using the throws keyword.

More information on these targets, Section 9.7.4 of the JLS

one or more targets may be associated with an annotation

Annotations may also have associated parameters. These parameters may be a primitive (such as int or double), String, class, enum, annotation, or an array of any of the five preceding types (see Section 9.6.1 of the JLS).

In order to demonstrate how annotations work in practice, we will be creating a sample Annotation name.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodInfo {
    public String author() default "DJ";
}

The core of the above declaration is the, public @interface MethodInfo which declares an annotation type with a public modifier, which allows our annotation to be used in any package. The body of the annotation declares a single String parameter, named author, that has a type of String and a default value of “DJ”.

Important point of notice in the above example is the variable named author. This variable has a special meaning as it defines a Single-Element Annotation (Section 9.7.3. of the JLS). This allows users using this annotation to supply a single parameter to the annotation without specifying the name of the parameter. Let’s understand this by taking an example, a user can annotate a field using @MethodInfo("developersjournal") and is not required to declare the annotation as @MethodInfo(author = "developersjournal"). Although, the latter can be used but it’s not required.

The inclusion of a default value of string allows for the value to be omitted, resulting in value holding the default string if no value is explicitly specified. For example, if a user declares the above annotation using the form @MethodInfo, then the author parameter is set to “DJ” string.

Notice the two annotations used in the above example @Retention and @Target, these are used to specify the Retention Policy and Target. The retention policy is specified using the java.lang.annotation.RetentionPolicy enum and includes constants for each of the three standard retention policies. The target is specified using the java.lang.annotation.ElementType enum and includes constants for each of the eleven standard target types.

In a short summary, we just created a public, single-element annotation named MethodInfo. This annotation is retained by the JVM during runtime and may only be applied to methods. This annotation created has a single parameter, author, of type String with a default value of “DJ” string. With our annotation created, we can now annotate fields.

Let’s take an example now to understand how to use this newly created annotation.

public class AnnotationExample {

    @Override
    @MethodInfo(author = "DevelopersJournal")
    public String toString() {
        return "Overriden toString method";
    }

    @MethodInfo()
    public static void oldMethod() {
        System.out.println("old method, don't use it.");
    }
}

How are Annotations Processed?

Processing annotations are accomplished through the Java Reflection Application Programming Interface (API). We will use the Reflection API to parse java annotations from a class. Please make a point of the Annotation Retention policy, this should be set to RUNTIME otherwise the information will not be available at runtime and we won’t be able to fetch any data from it.

public class AnnotationParsing {

	public static void main(String[] args) {
		try {
			Class annotationExample = AnnotationExample.class;
			for (Method method : annotationExample.getMethods()) {
				// checks if MethodInfo annotation is present for the method
				if (method.isAnnotationPresent(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);
						System.out.println("Author of the Method is " + methodAnno.author());
					} catch (Throwable ex) {
						ex.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Output of the above program will look something like below:

Annotation in Method: public java.lang.String com.eightbytestech.AnnotationExample.toString(): @com.eightbytestech.MethodInfo(author="DevelopersJournal")
Author of the Method is DevelopersJournal
Annotation in Method: public static void com.eightbytestech.AnnotationExample.oldMethod(): @com.eightbytestech.MethodInfo(author="DJ")
Author of the Method is DJ

 

RELATED ARTICLES

Most Popular