Introduction
Java annotations are often used to provide extra information for compilers, IDEs, and build tools. The extra information is often used to enhance the development cycle, such as reducing boilerplate, eliminating repetitive code, or warning against unsafe usage or mistakes.
This tutorial aims to teach you the basic amount of knowledge about annotations, so that you can identify them and know what to search for in your coding journey.
Goals
At the end of the tutorial, you would have learned:
- What Java annotations are.
- When to use Java annotations.
Tools Used
- A Java IDE. IntelliJ CE version #IC-221.6008.13 was used for this tutorial.
- Java 18 was used.
Prerequisite Knowledge
- Basic Java.
Annotation Interface vs Annotation
Before anything else, let us get a common source of confusion regarding terminology out of the way. What is commonly called Annotation by Java developers can refer to two different things:
-
Annotation Interface: blueprints for creating instances of Annotations. For example:
public @interface Override { }
-
Annotation: instances of Annotation Interfaces that can used to mark elements in your code. For example, two instances of the Annotation Interface
@Override
are used below.@Override public String toString() { return super.toString(); } @Override public boolean equals(Object obj) { return super.equals(obj); }
Annotation Interface
Most of the rules for interfaces also apply to annotation interfaces. However, a few key differences are:
-
The keyword
interface
must be preceded by an@
character.interface Foo {} @interface Bar {}
-
An Annotation Interface can never be generic.
interface Foo<T> {} //legal @interface Bar<T> {} //illegal
-
The direct super interface of all annotation interfaces is always
java.lang.annotation.Annotation
. -
Annotation interfaces cannot use the
extends
clause.
Annotation Interface Members
The body of Annotation Interfaces can only contain the members listed below:
-
Interface declarations.
-
Class declarations.
-
Constants.
-
Method declarations. Each method declared is called an element.
interface Foo extends java.lang.annotation.Annotation {} @interface Bar { interface Animal {} //interface @interface Foo {} //annotation interface is also an interface class Dog {} //clas declaration int NUM = 1; //constant //method without default value. Instances must provide a value. int customMethod(); //method with default value. //Instances are not required to provide a value int customMethod2() default 2; }
Annotation Interface Elements (Methods)
Elements of an Annotation Interface have even further restrictions. Methods must return one of the types below:
- A primitive type
- String.
- Class or an invocation of Class.
- An enum class type.
- An annotation interface type.
- An array type whose component type is one of the preceding types.
The method signature cannot override any method from Object or java.lang.annotation.Annotation.
Marker Annotation Interface
An Annotation Interface without any element is called a marker annotation interface.
public @interface Override {
}
Single Element Interface
An Annotation Interface with only one element is called a single-element annotation interface. If you use the method name value
in a single-element annotation interface, then the caller is not required to specify the element name when instantiating your annotation interface.
@interface Name {
String value();
}
@interface Age {
int age();
}
@Name("Annie") //the element name "value" is not required
@Age(age = 1) //the element name "age" is required
class Person {}
Default Java Annotations
Java SE comes with many pre-defined annotations. You are not required to know them all, but the most important ones are:
-
@Deprecated
: Mark part of your code as deprecated, so other developers will avoid using this part of your code. -
@Override
: You should always use this annotation when overriding a method. This enables the compiler and your IDE to warn you in cases where you think that you are overriding a super method, but maybe a typo created a completely new method instead of overriding. -
@Target
: This annotation can be used on other annotations to restrict the type of constructs that the other annotation be applied to. For example, the@Target(ElementType.Method)
used on the@Override
annotation interface indicates that@Override
can only be used on methods.@Target(ElementType.METHOD) public @interface Override { }
When are Annotations Used
The main purpose of annotations are to provide extra information in your code. Different actors such as compilers, build tools, IDE, or other plugins use this extra information to provide something useful (hopefully) when compiling your code. A couple of examples include:
- Java SE:
@Override
is used to reduce mistakes by developers. - Project Lombok: A lot of its features are delivered via annotations. getters and setters are automatically generated by Lombok if you annotate any field with
@Getter
or@Setter
. This lessens the amount of code that you have to write. Less code to look at makes your code easier to read. - Spring framework:
@Controller
,@Service
,@Repository
are used to mark classes as fulfilling architectural duties, so Spring can set up the environment correctly. - Vaadin framework:
@Route
is used to configure navigation routes. - Android:
@Insert
,@Update
,@Query
, and@Delete
are used on DAO methods, so that the compiler will generate appropriate CRUD code for you.
Annotations are not language constructs limited to Java. Other languages also employ the same feature. For example, decorators in Typescript also serve the same purpose as Java annotations.