Java Annotations Explained: Custom Annotations, Reflection & Real Examples

Learn Java Annotations from basics to advanced. Covers built-in annotations, custom annotations, meta-annotations, and real-world usage with reflection.

Java Annotations: Complete Guide

Annotations in Java are metadata that provide additional information about code. They do not directly affect program logic but can be used by the compiler or runtime to influence behavior.

What is an Annotation?

An annotation is defined using @ symbol. It is used to mark classes, methods, fields, or parameters.

@Override
public String toString() {
    return "Hello";
}
  • Provides metadata
  • Used by compiler or runtime
  • Helps frameworks process code
  • Improves readability and maintainability

Built-in Annotations

  • @Override → Ensures method overriding
  • @Deprecated → Marks outdated code
  • @SuppressWarnings → Suppresses compiler warnings
  • @FunctionalInterface → Ensures single abstract method

Meta-Annotations

Meta-annotations define how custom annotations behave.

  • @Target → Where annotation can be applied
  • @Retention → How long annotation is available
  • @Documented → Include in Javadoc
  • @Inherited → Allow inheritance

Retention Policies

  • SOURCE → Available only in source code
  • CLASS → Stored in .class file (default)
  • RUNTIME → Available at runtime (used with reflection)

Creating Custom Annotation

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {
    String value();
    int count() default 1;
}

Using Custom Annotation

class Test {
    @MyAnnotation(value = "Hello", count = 2)
    public void sayHello() {
        System.out.println("Hello Method");
    }
}

Accessing Annotation Using Reflection

import java.lang.reflect.Method;

class Main {
    public static void main(String[] args) throws Exception {
        Method m = Test.class.getMethod("sayHello");

        if (m.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation ann = m.getAnnotation(MyAnnotation.class);
            System.out.println(ann.value());
            System.out.println(ann.count());
        }
    }
}

Complex Example: Real Use Case

import java.lang.annotation.*;
import java.lang.reflect.*;

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

class Service {
    @LogExecution
    public void process() {
        System.out.println("Processing...");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Service service = new Service();

        for (Method m : service.getClass().getDeclaredMethods()) {
            if (m.isAnnotationPresent(LogExecution.class)) {
                System.out.println("Method " + m.getName() + " is annotated");
                m.invoke(service);
            }
        }
    }
}

Output

Method process is annotated
Processing...

Why Annotations are Used

  • Configuration without XML (Spring)
  • Code generation tools
  • Validation frameworks
  • Dependency Injection
  • Aspect-Oriented Programming

Disadvantages

  • Overuse makes code complex
  • Hidden logic
  • Requires reflection (performance cost)
  • Harder debugging

Best Practices

  • Use meaningful annotation names
  • Avoid too many custom annotations
  • Use RUNTIME only when needed
  • Document annotation usage
  • Keep annotations simple

Interview Tips

  • Annotations are metadata, not logic
  • RetentionPolicy.RUNTIME is needed for reflection
  • @Target defines usage scope
  • Used heavily in Spring Boot
  • Custom annotations are common interview topic

Final Summary

  • Annotations provide metadata
  • Can be built-in or custom
  • Controlled using meta-annotations
  • Used with reflection for dynamic behavior
  • Widely used in modern frameworks