Java Annotations

An annotation is a label that you attach to a class, method, or variable. The label starts with the @ sign. Annotations give extra information to the compiler and to tools. They do not change what your code does by themselves.

A Luggage Tag Example

Airlines attach tags to bags. A tag reads "Fragile" or "Heavy". The tag does not change the bag, yet the airport staff handle the bag in a different way. Annotations work as tags on code.

Diagram: Tags on Code

@Override          <-- tag
void show() { }    <-- code

@Deprecated        <-- tag
void oldMethod() { } <-- code

Built-In Annotations

AnnotationPurpose
@OverrideChecks that a method replaces a parent method
@DeprecatedWarns that a feature is old
@SuppressWarningsHides chosen compiler warnings
@FunctionalInterfaceChecks that an interface has one abstract method

@Override in Action

class Animal {
    void sound() { }
}
class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Woof");
    }
}

@Deprecated in Action

class Printer {
    @Deprecated
    void oldPrint() { }

    void print() { }
}

Code that calls oldPrint shows a warning, so developers move to print.

@SuppressWarnings in Action

@SuppressWarnings("unchecked")
void legacyCode() {
    java.util.List list = new java.util.ArrayList();
    list.add("text");
}

@FunctionalInterface in Action

@FunctionalInterface
interface Greeter {
    void greet(String name);
}

An extra abstract method in Greeter triggers a compile error.

Creating Your Own Annotation

Use the @interface keyword. Two helper annotations control the new annotation. @Target says where you can place it. @Retention says how long it lives.

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Task {
    String owner();
    int priority() default 1;
}

Retention Choices

PolicyLifetime
SOURCEOnly in source code, dropped by the compiler
CLASSStored in the class file, not visible at run time
RUNTIMEVisible while the program runs

Using the Custom Annotation

class Work {
    @Task(owner = "Asha", priority = 2)
    void clean() { }
}

Reading an Annotation at Run Time

A program reads RUNTIME annotations through the reflection feature.

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        Method m = Work.class.getDeclaredMethod("clean");
        Task t = m.getAnnotation(Task.class);
        System.out.println(t.owner() + " " + t.priority());   // Asha 2
    }
}

Diagram: Who Reads the Tag

 @Override  --> compiler checks it
 @Task      --> your program reads it while running
 @Entity    --> a framework reads it to build database tables

Where You See Annotations

  • Testing tools mark test methods with annotations
  • Web frameworks mark classes that handle web requests
  • Database tools mark fields that map to table columns

Common Mistakes

  • Forgetting RetentionPolicy.RUNTIME and reading null at run time
  • Skipping @Override and missing spelling errors
  • Leaving out a required annotation value

Real Example: Marking Slow Methods

A team wants to list every method that needs speed checks. Developers create a Slow annotation and tag each method. A small tool scans the class and prints the tagged names. The tags stay next to the code, so nobody maintains a separate list.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Slow { }

class Report {
    @Slow
    void buildYearlyReport() { }

    void showTitle() { }
}

The scan tool checks each method with isAnnotationPresent and reports buildYearlyReport only.

Quick Summary

  • Annotations are labels that start with @
  • Built-in annotations help the compiler
  • Custom annotations use @interface, @Target, and @Retention