Architecture & Design How to Use Annotations Effectively in Java

How to Use Annotations Effectively in Java

Annotation typically means extra information added to a section of text. In Java, it means the same thing except that the additional information is added to a source file. This annotated information has a very subtle effect without and does not take part in any way of changing the semantics of a program. The information annotated can be used effectively by various tools, both during development and deployment of the program. In a sense, it can be thought of as a metadata but the term ‘annotation’ perhaps better describes the idea. This article skims over the basics to understand its effective use in Java programming.

Annotation Is a Special Interface

According to Java syntax, an annotation can be described as a special type of interface that associates metadata with different elements of the Java language. Although it does not have a direct impact on the element that it is annotating, it absolutely is used by the Java compiler. A common annotation we use while method overriding is @Override. This annotation indicates that a method declaration is intended to override a method declaration in a supertype. As soon as we designate a method with this annotation, it gives a message to the Java compiler that it is a overridden version of its super class method and the signature is same as its supertype. The compiler will generate an error message unless it adheres to the rules.

Note that, although it does not have any apparent effect on the program, it tacitly helps in producing considerable impact on the code. The declaration of an annotation is not seemingly very different from declaring a class or an interface.

public @interface MySimpleAnnotation {

Note that @interface is the key to introduce a new annotation type. We may declare attributes in an annotation, optionally, with default values as follows:

public @interface MySimpleAnnotation {
   String myStr();
   int myVal() default 0;

An annotation declared with default values can be used just by the annotation name, but if it contains a non-default attribute, as shown in the code above, we may use it as follows:

@MySimpleAnnotation ( myStr = "sample string" )

However, it is a convention that if an annotation is with a single attribute named as value, which is not the default, it is optional to name the attribute while using, for example.

public @interface MySimpleAnnotation {
   String value();

we can use it as @MySimpleAnnotation ( "sample string" );.

Retention Policy

There is a retention policy associated with annotations. This policy has a crucial effect and does decide its availability for processing by the compiler. There is a set of enumerations to decide the retention policy.

  • The CLASS enumeration denotes that annotations are to be retained in the class file by the compiler and does not require additional annotation at runtime.
  • The RUNTIME enumeration denotes that the annotation is to be retained in the class file as well as retained by the VM during runtime. This supports the principle of reflection.
  • The SOURCE annotation is discarded by the compiler.

We can set the retention policy to the declaration of an annotation with the @Retention annotation as follows.

public @interface MySimpleAnnotation {
   String value();

The RetentionPolicy.RUNTIME signifies its presence during compilation as well as during runtime. Similarly, other retention policies have their own defined impact.

Element Type

Similar to the retention policy, an annotation must have its own element type defined as a set of enumerations. It simply adds a layer of information about its type.

Element type Description
ANNOTATION_TYPE This designates the interface to an annotation type.
CONSTRUCTOR This designates a constructor declaration.
FIELD This designates a field declaration.
LOCAL_VARIABLE This designates a local variable declaration.
METHOD Method declaration.
MODULE Module declaration.
PACKAGE Package declaration.
PARAMETER Formal parameter declaration.
TYPE Class, interface, enum, annotation declaration.
TYPE_PARAMETER Type parameter declaration.
TYPE_USE Use of a type.

Unlike the retention policy, we can use more than one type with element type to an annotation declaration with the @Target.

@Target( { ElementType.FIELD, ElementType.METHOD } )
public @interface MySimpleAnnotation {


There is an interesting connection between annotation and inheritance in Java. A subclass, by default, does not inherit the annotation declared in the super class. As a result, if we really want make an annotation eligible for inheritance by its subclasses, we must do so explicitly by using the @Inherited annotation.

@Target( {
ElementType.FIELD, ElementType.METHOD } )
public @interface MySimpleAnnotation {

This means that, if we designate a class with @MySimpleAnnotation, the child class will inherit the annotations declared in the parent class as well.

public class MySuperclass {


public class MySubclass extends MySuperclass {


Annotation Is Everywhere

The use of annotation has blended so well with the Java language that we rarely notice its use even if we do not invoke them explicitly. In fact, annotation is everywhere; the Java library is full of them. Some common among them are as follows:

Annotation Description
@Deprecated This annotation marks an element for removal in further releases. Therefore, programmers are discouraged from using them. Deprecation means that that the element has been superseded by a new or alternate version, or it has become obsolete.
@SuppressWarning This annotation indicates that a warning from the compiler should be suppressed on the element.
@SafeVarargs When this annotation is applied to a method or constructor, it asserts that the code does not perform any potential unsafe operation on its varargs parameter.
@Documented This annotation indicates that, when it is applied on the element then by default, a tool like javadoc will display annotations of that type in its output while annotations of annotation types without @Documented will not be displayed.
@FunctionalInterface This annotation designates an interface type to be a functional interface as per the Java Language Specification.
@Repeatable This indicates that the annotation can be applied repeatedly on the same declaration or type use.

Effective Use

Perhaps the greatest advantage of annotation is its support in a design paradigm based upon explicit configuration. The convention over configuration is one such paradigm, where it made the development process simple. There are frameworks, such as MVC (model-view-controller) and ORM (Object Relational Mapping), which extensively use annotation to simplify its different aspect of configuration. It is easy to mark a controller object with the @Controller annotation. Similarly, a simple @Entity designates a class to a relational database table. This simplification has an immense impact on the development process. Literally, pages of configuration are reduced to a few words. The benefit not only comes from the predefined annotation in the framework but also from its extensibility. Any improper use of annotation is quickly caught by the compiler rather than relying on the developer’s uncanny skills of hunting bugs. Bug hunting is not very enjoyable, especially when there are a lot of configuration files. So, annotation champions the idea of convention over configuration in its true sense.

We must also consider its limitation to use it effectively. They are as follows.

  • Annotations do not support inheritance as a result like classes do.
  • An annotation instance cannot be created programmatically by using the new operator.
  • Annotations can declare only primitive types attributes, such as String or Class< ?> types and arrays of those only.


This article explores a bit of the annotation feature of Java and tried to surface its potential in a concise manner. To put it in a few words, annotations do not directly affect the annotated element. But, depending on the type and definition of the annotations, it may be used by Java compiler, annotation processor, or runtime code using reflection or other introspection technique. In a way, it is a technique focused to leverage the efficiency of the developer. And, it does so quite powerfully and effectively, something one can understand only when literally used in programming.

Latest Posts

Related Stories