Types of Annotations

About

Annotations in Java are not just syntactic sugar but they are a powerful mechanism to add metadata that the compiler, tools, or frameworks can interpret. Understanding their types helps us write more expressive, readable, and maintainable code.

We can classify Java annotations broadly into several types based on purpose, structure, and usage scope.

1. Standard Annotations (Built-in Language Annotations)

These are provided by Java itself and typically influence compiler behavior.

Examples

Annotation
Purpose

@Override

Ensures a method is overriding a superclass method.

@Deprecated

Indicates that a method or class should no longer be used.

@SuppressWarnings

Tells the compiler to ignore specific warnings (like unchecked casts).

@FunctionalInterface

Marks an interface as having a single abstract method.

@SafeVarargs

Suppresses heap pollution warnings for varargs with generics.

These annotations improve readability, compile-time safety, and documentation clarity.

2. Meta-Annotations

Meta-annotations are annotations on other annotations. They define the behavior, scope, and life cycle of custom annotations.

Key Meta-Annotations

Annotation
Description

@Target

Specifies where the annotation can be applied (method, field, class, etc.).

@Retention

Defines how long the annotation should be retained (SOURCE, CLASS, RUNTIME).

@Documented

Indicates that the annotation should appear in Javadocs.

@Inherited

Allows annotations to be inherited by subclasses.

@Repeatable

Allows an annotation to be applied multiple times to the same element.

These are crucial when creating our own annotations.

3. Custom Annotations

These are annotations defined by the developer for specific use cases, often processed using reflection or annotation processors.

Example

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

We can then process @LogExecutionTime in our application logic (e.g., with Spring AOP or a custom processor) to add behavior like measuring method execution time.

Custom annotations are often used in frameworks, validations, event handling, or configuration.

4. Framework-Specific Annotations

Modern Java frameworks (like Spring, JPA, Jackson) heavily rely on annotations to provide declarative programming.

Examples by Framework

  • Spring: @Component, @Autowired, @RequestMapping, @Transactional

  • JPA (Hibernate): @Entity, @Table, @Id, @Column

  • Jackson (for JSON mapping): @JsonProperty, @JsonIgnore, @JsonInclude

  • JUnit: @Test, @BeforeEach, @AfterAll

These annotations configure application behavior, manage dependencies, or handle persistence—all without writing boilerplate code.

5. Marker Annotations

Marker annotations are annotations without any methods. Their presence alone conveys meaning.

Examples:

  • @Deprecated

  • @Override

  • Custom: @Secure, @Trackable, etc.

They act like boolean flags: the mere presence of the annotation is enough to trigger logic.

6. Single-Value Annotations

These annotations have only one method, usually named value(), allowing the user to omit the key when assigning a value.

public @interface Role {
    String value();
}

@Role("ADMIN") // no need to write value = "ADMIN"

They provide a concise syntax while still carrying metadata.

7. Multi-Value Annotations

Multi-value annotations allow for multiple named attributes, making them versatile for complex metadata.

public @interface Config {
    String name();
    int version();
}

@Config(name = "AppX", version = 2)

These are ideal for declarative configuration, such as defining API routes, validation rules, or policies.

8. Repeatable Annotations

Prior to Java 8, the same annotation couldn’t be applied more than once to the same element. With @Repeatable, this is now possible.

@Schedule(day = "Monday")
@Schedule(day = "Friday")
public void generateReport() {}

We must mark the annotation with @Repeatable(SomeContainer.class) to enable this.

Last updated