Java Annotations: Standard, Meta-Annotations & Custom Metadata

Introduced in Java 5, Annotations provide structured metadata about your code without affecting program semantics. Instead of fragile XML configuration files, modern Java uses annotations to configure web routes, test suites, database columns, and validation constraints.

1. Standard Built-in Java Annotations

AnnotationTargetPurpose
@OverrideMethodInstructs compiler to verify that the method correctly overrides a superclass method. Prevents typo bugs.
@DeprecatedType / Method / FieldWarns developers that an element is obsolete and may be removed in future versions.
@SuppressWarningsAnySuppresses specific compiler warnings (e.g., @SuppressWarnings("unchecked")).
@FunctionalInterfaceInterfaceEnforces that an interface contains exactly one single abstract method (SAM) for lambdas.
@SafeVarargsMethod / ConstructorAsserts that the method body does not perform unsafe operations on its varargs parameter.

2. Meta-Annotations (Annotations for Annotations)

Meta-annotations in java.lang.annotation define how custom annotations behave:

Meta-AnnotationValuesExplanation
@RetentionRetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME
Specifies how long the annotation is retained. RUNTIME is required to inspect via Reflection.
@TargetElementType.TYPE
ElementType.METHOD
ElementType.FIELD
Specifies where the annotation may be placed (classes, methods, fields, etc.).
@DocumentedNoneIncludes annotation information in generated Javadoc documentation.
@InheritedNoneAllows subclasses to automatically inherit the annotation from their parent class.

3. Creating a Custom Annotation

Let's build a practical custom annotation: @JsonField to customize JSON property names and serialization behavior:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 1. Define meta-annotations
@Retention(RetentionPolicy.RUNTIME) // Must be readable at runtime
@Target(ElementType.FIELD)          // Can only be placed on fields
public @interface JsonField {
    String name() default "";        // Custom property name
    boolean required() default true; // Validation constraint
}

4. Applying & Processing Custom Annotations via Reflection

import java.lang.reflect.Field;

// Target class using our custom annotation
class UserProfile {
    @JsonField(name = "user_full_name", required = true)
    private String fullName = "Aarav Sharma";

    @JsonField(name = "user_email")
    private String email = "aarav@veewom.com";

    private String internalPassword = "Confidential_Hash"; // Not annotated
}

// Annotation Processor Engine
public class AnnotationParser {
    public static void main(String[] args) throws Exception {
        UserProfile profile = new UserProfile();
        Class clazz = profile.getClass();

        System.out.println("Parsing JSON Mappings for: " + clazz.getSimpleName());

        for (Field field : clazz.getDeclaredFields()) {
            // Check if field is annotated with @JsonField
            if (field.isAnnotationPresent(JsonField.class)) {
                field.setAccessible(true);
                JsonField annotation = field.getAnnotation(JsonField.class);

                String jsonKey = annotation.name().isEmpty() ? field.getName() : annotation.name();
                Object value = field.get(profile);
                boolean isRequired = annotation.required();

                System.out.printf("Field: '%s' -> JSON Key: '%s' | Value: '%s' | Required: %b%n",
                                  field.getName(), jsonKey, value, isRequired);
            }
        }
    }
}
Console Output Trace
Parsing JSON Mappings for: UserProfile
Field: 'fullName' -> JSON Key: 'user_full_name' | Value: 'Aarav Sharma' | Required: true
Field: 'email' -> JSON Key: 'user_email' | Value: 'aarav@veewom.com' | Required: true
BCA / University Exam Corner
  • Viva Question: What happens if you forget to declare @Retention(RetentionPolicy.RUNTIME) on a custom annotation?
    Answer: The default retention policy is RetentionPolicy.CLASS. While recorded in the compiled .class file, the JVM execution engine strips it out during class loading. Calling field.getAnnotation() at runtime will return null.
  • Concept: In Java, @interface implicitly extends java.lang.annotation.Annotation, and annotation elements cannot declare parameters or throw exceptions.

Frequently Asked Questions (FAQ)

Q1. What are Annotations in Java?
Annotations are a form of syntactic metadata added to Java source code (classes, methods, fields, parameters). They do not directly alter program execution logic but provide critical information consumed by compilers (error checking), build tools (code generation), or runtime frameworks via Reflection.
Q2. What does RetentionPolicy.RUNTIME signify?
RetentionPolicy determines how long an annotation is retained: SOURCE (discarded by compiler), CLASS (recorded in .class file but ignored by JVM), and RUNTIME (recorded in .class file and retained by the JVM at runtime, enabling reflection inspection via getAnnotation()).
Q3. What is the purpose of the @Target meta-annotation?
The @Target meta-annotation specifies the Java language elements to which the custom annotation can be applied, such as ElementType.TYPE (classes/interfaces), ElementType.METHOD (methods), ElementType.FIELD (fields), or ElementType.PARAMETER.

Explore Related Java Tutorials

Accelerate your Java mastery by studying these tightly connected core tutorials:

Java Reflection API →

Reading custom annotations at runtime.

Java Methods & Overriding →

Using @Override for compiler safety.

Object-Oriented Programming →

Interface foundations of @interface.

Java Design Patterns →

Framework patterns driven by annotations.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Stumbleupon Share on Tumblr Share on Reddit Share on Diggit

You may also like this!