How do Annotations Work In Java?

Basically, annotations are just markers which are read by the compiler or the application. Depending on their retention policy they are available at compile time only or are readable at runtime using reflection.

Many frameworks use runtime retention, i.e. they reflectively check whether some annotations are present on a class, method, field etc. and do something if the annotation is present (or not). Additionally, members of annotations can be used to pass further information.

What are Annotations ?

One word to explain Annotation is Metadata. Metadata is data about data. So Annotations are metadata for code. For example look at following piece of code.

2.public String toString() {
3.return "This is String Representation of current object.";

I have overridden the toString() method and used @Override annotation in above code. Even if I don’t put @Override, code works properly without any issue. So what’s the advantage and what does this annotation stand for? @Override tells the compiler that this method is an overridden method (metadata about method) and if any such method does not exist in parent class, then throw a compiler error (method does not override a method from its super class). Now if I would have made a typography mistake and used method name as toStrring() {double r} and if I wouldn’t have used @Override, my code would have compiled and executed successfully but outcome would be different from what I would have accepted. So now we understand what annotations are but still it’s good to read formal definitions

Annotation is special kind of Java construct used to decorate a class, method, field, parameter, variable, constructor, or package. It’s the vehicle chosen by JSR-175 to provide metadata.

Why Were Annotations Introduced?

Prior to annotation (and even after) XML were extensively used for metadata and somehow a particular set of Application Developers and Architects thought XML maintenance was getting troublesome. They wanted something which could be coupled closely with code instead of XML which is very loosely coupled (in some cases almost separate) from code. If you google “XML vs. annotations”, you will find a lot of interesting debates. Interesting point is XML configurations were introduced to separate configuration from code. Last two statements might create a doubt in your mind that these two are creating a cycle, but both have their pros and cons. Let’s try to understand with an example.

Suppose, you want to set some application wide constants/parameters. In this scenario, XML would be a better choice because this is not related with 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 combination of both XML and Annotations to leverage positive aspects of both.

How Annotations Work and How to Write Custom Annotations

Before I start this explanation, I will suggest you download this sample code for annotations ( and keep that open in any IDE of your choice, as it will help you to understand following explanation better.

Writing annotations is very simple. You can compare annotation definition to an interface definition. Let’s have a look at two examples – One is standard @Override annotation and second is a custom annotation @Todo

3.public @interface Override {

Something seems fishy about @Override, it’s not doing anything, how it checks if a method is defined in parent class. Well, don’t be surprised, I am not kidding you. Override annotation’s definition has that much code only. This is the most important part to understand and I am reiterating myself – Annotations are only metadata and they do not contain any business logic. Tough to digest but true. If annotations do not contain the logic than someone else must be doing something and that someone is consumer of this annotation metadata. Annotations only provide some information about the attribute (class/method/package/field) on which it is defined. Consumer is a piece of code which reads this information and then performs necessary logic.

When we are talking about standard annotations like @Override – JVM is the consumer and it works at bytecode level. Now that’s something application developers can’t control and can’t use for custom annotations. So we need to write consumers for our annotations by ourselves.

Let’s understand the key terms used for writing annotations one by one. In the above examples, you will see annotations are used on annotations.

J2SE 5.0 provides four annotations in the java.lang.annotation package that are used only when writing annotations:

@Documented – Whether to put the annotation in Javadocs

@Retention – When the annotation is needed

@Target? – Places the annotation can go

@Inherited – Whether subclasses get the annotation.

@Documented – A simple market annotations which tells whether to add Annotation in java doc or not.

@Retention – Defines for how long the annotation should be kept.

RetentionPolicy.SOURCE – Discard during the compile. These annotations don’t make any sense after the compile has completed, so they aren’t written to the bytecode. Examples @Override, @SuppressWarnings
RetentionPolicy.CLASS – Discard during class load. Useful when doing bytecode-level post-processing. Somewhat surprisingly, this is the default.
RetentionPolicy.RUNTIME – Do not discard. The annotation should be available for reflection at runtime. This is what we generally use for our custom annotations.

@Target – Where annotation can be placed. If you don’t specify this, annotation can be placed anywhere. Following are the valid values. One important point here is, it’s inclusive only which means if you want annotation on 7 attributes and just want to exclude only one attribute, you need to include all 7 while defining target.

ElementType.TYPE (class, interface, enum)

ElementType.FIELD (instance variable)





ElementType.ANNOTATION_TYPE (on another annotation)

ElementType.PACKAGE (remember

@Inherited – Controls whether annotation should affect subclass.

Now what goes inside an annotation definition? Annotations only support primitives, string and enumerations. All attributes of annotations are defined as methods and default values can also be provided

@interface Todo {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
String author() default "Yash";
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;

Following is an example of how the above annotation can be used

@Todo(priority = Todo.Priority.MEDIUM, author = "Yashwant", status = Todo.Status.STARTED)
public void incompleteMethod1() {
//Some business logic is written
//But it’s not complete yet

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

@interface Author{
String value();
public void someMethod() {

So far so good. We have defined our custom annotation and applied it to some business logic methods. Now it’s time to write a consumer. For that we will need to use Reflection. If you are familiar with Reflection code, you know reflection provides Class, Method and Field objects. All of these have a getAnnotation() method which returns the annotation object. We need to cast this object as our custom annotation (after checking with instanceOf()) and then we can call methods defined in our custom annotation. Let’s look at the sample code, which uses above annotation:

Class businessLogicClass = BusinessLogic.class;
for(Method method : businessLogicClass.getMethods()) {
Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " +;
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" Status : " + todoAnnotation.status());


A spring AOP way of doing custom annotation


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s