Hubbry Logo
Java annotationJava annotationMain
Open search
Java annotation
Community hub
Java annotation
logo
7 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Contribute something
Java annotation
Java annotation
from Wikipedia

In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code, like an attribute.[1] Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection.[2] It is possible to create meta-annotations out of the existing ones in Java.[3]

History

[edit]

The Java platform has various ad-hoc annotation mechanisms—for example, the transient modifier, or the @Deprecated javadoc tag. The Java Specification Request JSR-175 introduced the general-purpose annotation (also known as metadata) facility to the Java Community Process in 2002; it gained approval in September 2004.[4]

Annotations became available in the language itself beginning with version 1.5 of the Java Development Kit (JDK). The apt tool provided a provisional interface for compile-time annotation processing in JDK version 1.5; JSR-269 formalized this, and it became integrated into the javac compiler in version 1.6.

In C++26, C++ added annotations for reflection that are similar to Java annotations.

Built-in annotations

[edit]

Java defines a set of annotations that are built into the language. Of the seven standard annotations, three are part of java.lang, and the remaining four are imported from java.lang.annotation.[5][6]

Annotation Package Description
@Deprecated java.lang Marks the method as obsolete. Causes a compile warning if the method is used.
@FunctionalInterface java.lang Marks an interface as intended to be a functional interface.
@Override java.lang Marks that the method overrides an ancestor class-defined method. Causes a compilation error if the method is not found in one of the parent classes or implemented interfaces.
@SafeVarargs java.lang Suppress warnings for all callers of a method or constructor with a generics varargs parameter, since Java 7.
@SuppressWarnings java.lang Instructs the compiler to suppress the compile time warnings specified in the annotation parameters.
@Documented java.lang.annotation Marks another annotation for inclusion in the documentation.
@Inherited java.lang.annotation Marks another annotation to be inherited to subclasses of annotated class (by default annotations are not inherited by subclasses).
@Native java.lang.annotation Marks a field defining a constant value as potentially being referenced from native code.
@Repeatable java.lang.annotation Marks another annotation as repeatable.
@Retention java.lang.annotation Specifies how the marked annotation is stored, whether in code only, compiled into the class, or available at runtime through reflection.
@Target java.lang.annotation Marks another annotation to restrict what kind of Java elements the annotation may be applied to.

In Jakarta EE (formerly Java Platform, Enterprise Edition), the following annotations also exist in jakarta.annotation (formerly javax.annotation):[7][8]

Annotation Package Description
@Generated jakarta.annotation Marks source code that has been generated (i.e. not written by a user, or automatically generated by a computer).
@Resource jakarta.annotation Marks a class, method, or field as a reference to a resource.
@Resources jakarta.annotation Declares reference to resources, as a container for multiple resource declarations.
@PostConstruct jakarta.annotation Marks a method to indicate that it must be executed after dependency injection to perform initialization, i.e. the method must be invoked before the class is used.
@PreDestroy jakarta.annotation Marks a method as a callback notification to indicate the instance is in the process of being removed by the container, i.e. the method is used to release resources held by the instance.
@Priority jakarta.annotation Marks any program element to indicate in what order they should be used.
@Nonnull jakarta.annotation Marks any element that cannot be null.
@Nullable jakarta.annotation Marks any element that has the explicit possibility of being null.
@RunAs jakarta.annotation Defines the security role of the application during execution in a Jakarta EE container.
@RolesAllowed jakarta.annotation.security Marks a method to specify security roles permitted to access the method.
@PermitAll jakarta.annotation.security Marks a method to specify that all security roles may access the method.
@DenyAll jakarta.annotation.security Marks a method to specify that no security roles may access the method.
@DeclareRoles jakarta.annotation.security Specifies security roles used by the application.
@DataSourceDefinition jakarta.annotation.sql Defines a container DataSource that is registered with Java Naming and Directory Interface (JNDI).
@DataSourceDefinitions jakarta.annotation.sql Declares a container DataSource, acting as a container for multiple data source declarations.

There was previously an annotation, @ManagedBean, located in jakarta.annotation, which was historically used to declare a Managed Bean which are container managed objects that support a small set of basic services such as resource injection, lifecycle callbacks and interceptors. However, it has been removed.[9][10]

Example

[edit]

Built-in annotations

[edit]

This example demonstrates the use of the @Override annotation. It instructs the compiler to check parent classes for matching methods. In this case, an error is generated because the gettype() method of class Cat doesn't in fact override getType() of class Animal like is desired, because of the mismatching case. If the @Override annotation were absent, a new method of name gettype() would be created in class Cat.

public class Animal {
    public void speak() {}

    public String getType() {
        return "Generic animal";
    }
}

public class Cat extends Animal {
    @Override
    public void speak() { // This is a good override.
        System.out.println("Meow.");
    }

    @Override
    public String gettype() { // Compile-time error due to typo: should be getType() not gettype().
        return "Cat";
    }
}

Custom annotations

[edit]

Annotation type declarations are similar to normal interface declarations. An at-sign (@) precedes the keyword "interface".

// @Twizzle is an annotation to method toggle().
@Twizzle
public void toggle() {

}

// Declares the annotation Twizzle.
public @interface Twizzle {

}

Annotations may include a set of key-value pairs, which are modeled as methods of the annotation type. Each method declaration defines an element of the annotation type. Method declarations must not have any parameters or a throws clause. Return types are restricted to primitives, String, Class, enums, annotations, and arrays of the preceding types. Methods can have default values.

// Same as: @Edible(value = true)
@Edible(true)
Item item = new Carrot();

public @interface Edible {
    boolean value() default false;
}

@Author(first = "Oompah", last = "Loompah")
Book book = new Book();

public @interface Author {
    String first();
    String last();
}

Annotations themselves may be annotated to indicate where and when they can be used:

@Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection.
@Target({ElementType.METHOD})       // This annotation can only be applied to class methods.
public @interface Tweezable {}

The compiler reserves a set of special annotations (including @Deprecated, @Override and @SuppressWarnings) for syntactic purposes.

Annotations are often used by frameworks as a way of conveniently applying behaviours to user-defined classes and methods that must otherwise be declared in an external source (such as an XML configuration file) or programmatically (with API calls). The following, for example, is an annotated JPA data class:

@Entity                                             // Declares this an entity bean
@Table(name = "people")                             // Maps the bean to SQL table "people"
public class Person implements Serializable {
    @Id                                             // Map this to the primary key column.
    @GeneratedValue(strategy = GenerationType.AUTO) // Database will generate new primary keys, not us.
    private Integer id;

    @Column(length = 32)                            // Truncate column values to 32 characters.
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The annotations are not method calls and will not, by themselves, do anything. Rather, the class object is passed to the JPA implementation at run-time, which then extracts the annotations to generate an object–relational mapping.

A complete example is given below:

package com.acme.proj.annotation;

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

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
    ElementType.TYPE, ElementType.METHOD,
    ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE,
    ElementType.PACKAGE, ElementType.FIELD, ElementType.LOCAL_VARIABLE
})
@Inherited
public @interface Unfinished {
    public enum Priority { LOW, MEDIUM, HIGH }
    String value();
    String[] changedBy() default "";
    String[] lastChangedBy() default "";
    Priority priority() default Priority.MEDIUM;
    String createdBy() default "James Gosling";
    String lastChanged() default "2011-07-08";
}
package com.acme.proj.annotation;

public @interface UnderConstruction {
    String owner() default "Patrick Naughton";
    String value() default "Object is Under Construction.";
    String createdBy() default "Mike Sheridan";
    String lastChanged() default "2011-07-08";
}
package com.acme.proj.validators;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

import com.acme.proj.annotation.UnderConstruction;
import com.acme.proj.annotation.Unfinished;
import com.acme.proj.annotation.Unfinished.Priority;
import com.acme.proj.util.Util;

@UnderConstruction(owner = "Jon Doe")
public class DateValidator implements Validator {
	
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String date = (String) value;
        String errorLabel = "Please enter a valid date.";
        if (!component.getAttributes().isEmpty()) {
            errorLabel = (String) component.getAttributes().get("errordisplayval");
        }

        if (!Util.validateAGivenDate(date)) {
            @Unfinished(
                changedBy = "Steve",
                value = "whether to add message to context or not, confirm",
                priority = Priority.HIGH
            )
            FacesMessage message = new FacesMessage();
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            message.setSummary(errorLabel);
            message.setDetail(errorLabel);
            throw new ValidatorException(message);
        }
    }
}

Processing

[edit]

When Java source code is compiled, annotations can be processed by compiler plug-ins called annotation processors. Processors can produce informational messages or create additional Java source files or resources, which in turn may be compiled and processed. However, annotation processors cannot modify the annotated code itself. (Code modifications may be implemented using methods beyond the Java Language Specification.) The Java compiler conditionally stores annotation metadata in the class files, if the annotation has a RetentionPolicy of CLASS or RUNTIME. Later, the JVM or other programs can look for the metadata to determine how to interact with the program elements or change their behavior.

In addition to processing an annotation using an annotation processor, a Java programmer can write their own code that uses reflection to process the annotation. Java SE 5 supports a new interface that is defined in the java.lang.reflect package. This package contains the interface called AnnotatedElement that is implemented by the Java reflection classes including Class, Constructor, Field, Method, and Package. The implementations of this interface are used to represent an annotated element of the program currently running in the Java Virtual Machine. This interface allows annotations to be read reflectively.

The AnnotatedElement interface provides access to annotations having RUNTIME retention. This access is provided by the getAnnotation, getAnnotations, and isAnnotationPresent methods. Because annotation types are compiled and stored in byte code files just like classes, the annotations returned by these methods can be queried just like any regular Java object. A complete example of processing an annotation is provided below:

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

// This is the annotation to be processed
// Default for Target is all Java Elements
// Change retention policy to RUNTIME (default is CLASS)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeHeader {
    // Default value specified for developer attribute
    String developer() default "Unknown";
    String lastModified();
    String[] teamMembers();
    int meaningOfLife();
}
// This is the annotation being applied to a class
@TypeHeader(
    developer = "Bob Bee",
    lastModified = "2013-02-12",
    teamMembers = { "Ann", "Dan", "Fran" },
    meaningOfLife = 42
)
public class SetCustomAnnotation {
    // Class contents go here
}
// This is the example code that processes the annotation
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;

public class UseCustomAnnotation {
    public static void main(String[] args) {
        Class<SetCustomAnnotation> classObject = SetCustomAnnotation.class;
        readAnnotation(classObject);
    }

    static void readAnnotation(AnnotatedElement element) {
        try {
            System.out.println("Annotation element values: %n");
            if (element.isAnnotationPresent(TypeHeader.class)) {
                // getAnnotation returns Annotation type
                Annotation singleAnnotation = element.getAnnotation(TypeHeader.class);
                TypeHeader header = (TypeHeader) singleAnnotation;

                System.out.printf("Developer: %s%n", header.developer());
                System.out.printf("Last Modified: %s%n", header.lastModified());

                // teamMembers returned as String[]
                System.out.print("Team members: ");
                for (String member : header.teamMembers()) {
                    System.out.printf("%s, ", member);
                }
                System.out.println();

                System.out.println("Meaning of Life: %s%n", header.meaningOfLife());
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

See also

[edit]

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
Java annotations are a feature of the Java programming language that allow developers to add metadata to source code elements such as classes, methods, fields, and parameters, providing additional information without altering the program's execution. Introduced in Java SE 5.0 in 2004, annotations are denoted by the @ symbol followed by an annotation type name and optional element-value pairs in parentheses, enabling compile-time processing, code generation, and runtime inspection. Annotations serve multiple purposes, including informing the compiler about intended overrides with @Override, suppressing specific warnings via @SuppressWarnings, and marking elements as deprecated using @Deprecated, all of which are predefined in the java.lang package. They also support meta-annotations like @Retention, which defines whether an annotation is retained at compile-time, in class files, or at runtime, and @Target, which restricts where the annotation can be applied. Since Java SE 8, enhancements such as type annotations—applicable to type declarations and uses for stronger type checking—and repeating annotations, enabled by the @Repeatable meta-annotation, have expanded their utility in frameworks and pluggable type systems. Custom annotations can be created by defining interfaces extending java.lang.annotation.Annotation, allowing developers to build domain-specific metadata for tools like or validation libraries. Overall, annotations promote cleaner, more maintainable code by reducing boilerplate and enabling paradigms across the ecosystem.

Overview

Definition and Purpose

Java annotations are a form of syntactic metadata that can be attached to various program elements in the Java programming language, such as classes, interfaces, fields, methods, parameters, constructors, and, since Java SE 8, type uses. They provide additional information about these elements without directly altering the program's execution flow, serving as a standardized way to embed descriptive data into source code. The primary purpose of annotations is to enable by allowing developers to specify configuration, constraints, or behavioral hints in a concise manner. They offer guidance to compilers for tasks like error detection or warning suppression, support compile-time and deployment-time processing for generating code, XML files, or other artifacts, and facilitate runtime examination through reflection for dynamic behaviors. In frameworks, annotations play a key role in areas such as (e.g., in Spring) and validation (e.g., in Jakarta Bean Validation), where they declaratively wire components or enforce rules without invasive code changes. Annotations enhance code readability by making metadata explicit and self-documenting, reducing the need for like extensive XML configurations or manual checks. They promote by distinguishing core logic from configuration or tooling directives, leading to more maintainable and modular applications. Prior to their introduction, developers relied on approaches such as marker interfaces (e.g., for type categorization) or informal comments and naming conventions to convey similar metadata, which were less structured and harder to process programmatically.

Key Concepts

Java annotations are built upon several foundational concepts that define their structure and behavior. An annotation type is a special form of interface that extends the java.lang.annotation.Annotation marker interface, declared using the @interface keyword. These types serve as blueprints for creating metadata that can be attached to various program elements, enabling without altering the core logic of the code. Central to annotation types are their elements, which are abstract methods defined within the @interface declaration. These elements represent the configurable attributes of the annotation and can include optional default values specified via the default keyword. The return types for elements are strictly limited to primitives (such as int, boolean, double), String, Class, an enum type, another annotation type, or arrays of these types, ensuring type safety and simplicity in processing. For instance, an element might be declared as String value() default "";, allowing users to provide string-based metadata with a fallback. The applicability of an annotation is governed by targets, which specify the program elements where the annotation can be applied. These targets are defined using the @Target meta-annotation, whose value is an array of ElementType enum constants. Common targets include TYPE for classes, interfaces, or enums; FIELD for fields (including enum constants); METHOD for methods; PARAMETER for formal parameters; CONSTRUCTOR for constructors; LOCAL_VARIABLE for local variables; ANNOTATION_TYPE for other annotation types; and PACKAGE for packages. Additional targets introduced in Java SE 8, such as TYPE_PARAMETER and TYPE_USE, extend applicability to type parameters and type uses like casts or implements clauses. If no @Target is specified, the annotation defaults to all element types. Retention policies determine the lifecycle of annotations, controlling their visibility from source code through runtime. Specified via the @Retention meta-annotation with a RetentionPolicy enum value, the policies are: SOURCE, where annotations are used only during compilation and discarded afterward; CLASS (the default), where they are stored in the class file but not accessible at runtime; and RUNTIME, where they persist in the class file and remain available for reflection at runtime, enabling dynamic processing by tools or frameworks. This mechanism balances compile-time efficiency with runtime flexibility, as runtime retention incurs a minor performance overhead due to class file size and reflection access. Repeatable annotations, introduced in Java SE 8, allow multiple instances of the same annotation type to be applied to a single program element, enhancing expressiveness for scenarios requiring lists of metadata. To enable this, the annotation type is marked with the @Repeatable meta-annotation, referencing a annotation type that holds an array of the repeatable type as its value element. The automatically synthesizes the when multiple instances are used, and retrieval at runtime is supported via reflection methods like getAnnotationsByType(Class<T>). This feature requires the to be properly defined with appropriate targets and retention matching the repeatable .

History and Evolution

Introduction in Java 5

Java annotations were introduced as a core language feature in Java SE 5.0, released in September 2004, through JSR 175: A Metadata Facility for the Java Programming Language. This specification, developed under the Java Community Process, aimed to standardize the addition of metadata to program elements such as classes, interfaces, fields, and methods. The expert group included representatives from Sun Microsystems, Oracle, Borland, and others, with key contributions from language designers like Neal Gafter, who played a central role in integrating these changes into the Java compiler and language specification. The motivation for annotations stemmed from the need to replace fragmented, metadata mechanisms prevalent in earlier Java development, such as marker interfaces for simple type indications and verbose XML files for configuring tools like , compilers, and frameworks including Enterprise JavaBeans (EJB). These approaches often led to , maintenance challenges, and separation of metadata from , hindering developer productivity and tool integration. JSR 175 sought to provide a lightweight, declarative syntax embedded directly in Java source, enabling better support for compile-time and runtime processing without extending the core . Among the key features introduced were the foundational syntax for declaring and applying , the ability to define custom with type-safe elements, and three built-in annotations in the java.lang package: @Override, which verifies that a method overrides a superclass method; @Deprecated, which signals that an element is outdated and should not be used in new code; and @SuppressWarnings, which allows selective suppression of compiler warnings for specific code elements. were also tightly integrated with the Java reflection , providing methods in classes like java.lang.reflect.Method and java.lang.Class to access annotation metadata at runtime, thus enabling dynamic processing by libraries and tools. Initial adoption of annotations occurred rapidly in the Java ecosystem, particularly in object-relational mapping (ORM) frameworks. For instance, Hibernate 3.0, released in February 2005, incorporated annotations to support EJB 3.0-style entity mappings, allowing developers to replace XML descriptors with inline metadata for configurations, which streamlined development and reduced configuration overhead in enterprise applications. This early integration highlighted annotations' potential for framework extensibility and paved the way for broader annotation-driven programming patterns.

Developments in Later Versions

Java 6 integrated annotation processing directly into the compiler, eliminating the need for the separate apt tool introduced in Java 5 and enabling automatic discovery of pluggable processors via the ServiceLoader mechanism. This improvement allowed developers to configure annotation processors more seamlessly during compilation, supporting the standardized from JSR 269 while enhancing tool integration and runtime efficiency. Java 8 introduced repeatable annotations through JEP 120, permitting multiple instances of the same annotation type on a single program element to improve code readability without requiring wrapper container annotations. Additionally, JSR 308 extended annotation targets to include type uses, such as generic arguments, type casts, and method receivers, enabling more precise type checking and pluggable type systems. These features updated reflective s and class file formats to handle repeated and type annotations, broadening their applicability in static analysis tools. The apt tool and its associated com.sun.mirror , deprecated since Java 7, were fully removed in this release. In Java 9, the (JPMS) introduced support for on modules via the new ElementType.MODULE target, allowing annotations directly on module-info.java declarations to describe module properties or enforce policies. The standardized was recommended for all processing tasks to align with modularization goals. Subsequent releases up to Java 25 enhanced annotation support in modern language features without altering core syntax. , finalized in Java 16, permit annotations on record components, which propagate to generated fields, constructors, and methods, facilitating validation and in data classes. Sealed classes and interfaces, standardized in Java 17, integrate annotations seamlessly on sealed types and their permitted subclasses, supporting exhaustive in switch expressions where annotated hierarchies can be deconstructed more safely. enhancements in Java 21, including guarded patterns and null handling, leverage these structures but do not introduce new annotation mechanisms, instead relying on existing processing for compile-time validation. No major changes to annotations were introduced in Java 22 through 25. These developments have significantly impacted library ecosystems, enabling tools like Project Lombok to leverage annotations for automated code generation, such as producing getters, setters, equals, and constructors from simple declarations like @Data, thereby reducing boilerplate while maintaining compatibility with evolving features.

Syntax and Declaration

Annotation Declaration

Custom types in are declared using the @interface keyword, which defines a new type that implicitly extends the java.lang.annotation.[Annotation](/page/Annotation) interface. The declaration resembles an interface but contains only method declarations that represent the annotation's elements, with no constructors, instance fields, or implementation code allowed. For example, a basic type might be declared as follows:

java

@interface MyAnnotation { String value(); }

@interface MyAnnotation { String value(); }

This structure ensures that annotations serve solely as metadata carriers without executable logic. Annotation elements are abstract methods that return values of restricted types, including primitive types (e.g., int, boolean), String, Class, enumerations, other annotations, and arrays of these types; no other return types are permitted to maintain compile-time constancy. An extends clause is prohibited in the declaration, as the type automatically inherits from Annotation, and methods must have no parameters or throws clauses. Default values can be assigned to elements using the = operator, allowing optional parameters when the annotation is applied; these defaults must be compile-time constants of the supported types. For instance:

java

@interface MyAnnotation { [String](/page/String) value() default ""; int priority() default 1; }

@interface MyAnnotation { [String](/page/String) value() default ""; int priority() default 1; }

This enables flexible usage while enforcing . To promote clarity and simplicity, best practices recommend minimizing the number of elements in an annotation type, ideally to zero (for annotations) or one. If only a single element is needed, it should be named value to allow abbreviated application syntax, such as @MyAnnotation("example") instead of @MyAnnotation(value = "example"). Meta-annotations like @Target and @Retention can be applied to the declaration to specify where and how the annotation may be used, but their details are covered elsewhere.

Applying Annotations

Annotations in Java are applied by prefixing the annotation type name with an at-sign (@) immediately before the declaration of the program element it modifies, such as a class, method, field, or parameter. This placement treats the annotation as a modifier, similar to keywords like public or static, and it must appear before other modifiers. For instance, the syntax @MyAnnotation public class Example { } attaches the @MyAnnotation to the class declaration. When specifying element values for an annotation, parentheses enclose the pairs in the form elementName = value, with values being compile-time constants like strings, primitives, enums, classes, or annotation instances. For marker annotations without elements, the parentheses are optional and often omitted, as in @Preliminary. Single-element annotations, where the element is named value, allow omission of the name and equals sign, simplifying to @Annotation("value"). Multiple elements are listed comma-separated within the parentheses, such as @RequestForEnhancement(id=2868724, synopsis="Enable time-travel", engineer="Duke", date=1492). Multiple distinct annotations can be stacked sequentially before a single element declaration, applying each to the same target. For repeatable annotations, introduced in Java 8, the same annotation type can be applied multiple times to the same element if marked with the @Repeatable meta-annotation, which specifies a container annotation to hold the array of instances. Without @Repeatable, repetition requires explicitly using the container, like @Schedules({@Schedule(...), @Schedule(...)}); with it, the handles the container implicitly, allowing direct repetition such as @Schedule(...) @Schedule(...). Type annotations, available since Java 8, extend this syntax to annotate not just declarations but any use of a type, including generics, casts, and method parameters, to support pluggable type checking. The annotation precedes the type identifier, as in @NonNull String str for a variable or @NonNull [List](/page/List)<String> for a parameterized type, ensuring annotations apply to the type itself rather than the declaration. These enhance analysis for issues like nullability without altering program semantics. Application of annotations is restricted by the @Target meta-annotation on their declaration, which specifies allowable program elements (e.g., ElementType.METHOD limits use to methods). Annotations cannot be attached to arbitrary expressions or statements outside these targets, ensuring they modify only valid declarations or type uses. Violations result in compile-time errors.

Built-in Annotations

Core Standard Annotations

The core standard annotations in , defined in the java.lang package, provide essential mechanisms for enhancing code correctness, maintenance, and feedback. These annotations—@Override, @Deprecated, @SuppressWarnings, and @SafeVarargs—are primarily applied at the source level to signal intentions to the , helping developers avoid common errors and manage code evolution without altering runtime behavior. They are integral to everyday programming, supporting features like validation and warning suppression, and have remained stable since their introduction in Java 5 and 7. @Override indicates that a method declaration is intended to override a method from a supertype, such as a superclass or implemented interface. The enforces this by generating an if the annotated method does not actually override a supertype method or if its is not override-equivalent to a public method in java.lang.Object (e.g., equals, hashCode, or toString). This annotation targets only methods (@Target(METHOD)) and has source retention (@Retention(SOURCE)), meaning it is not retained in the compiled class file. It prevents subtle bugs from accidental overloading instead of overriding, such as typos in method names or mismatched parameter types, thereby promoting reliable hierarchies. For example:

java

class Parent { public void doSomething() { } } class Child extends Parent { @Override public void doSomething() { } // Valid override }

class Parent { public void doSomething() { } } class Child extends Parent { @Override public void doSomething() { } // Valid override }

If the method name were misspelled as doSomthing, the would , catching the mistake early. Introduced in Java 5, @Override applies to record component accessor methods as well in modern Java. @Deprecated marks a program element—such as a class, method, field, or —as outdated, signaling to developers that it should not be used due to potential issues, replacement by better alternatives, or planned removal in future versions. When a deprecated element is used or overridden in non-deprecated code, the issues a warning, but the element remains functional and does not trigger warnings for local variables, parameters, or packages. It supports two attributes since Java 9: since (a string indicating the version of deprecation, default empty) and forRemoval (a flagging imminent removal, default false), which refine the deprecation intent. For documentation, the corresponding @deprecated tag must be used to explain the reason and suggest alternatives, ensuring alignment with the annotation. In modules, deprecation warns on requires directives but not on exports or opens. An example usage:

java

@Deprecated(since="1.5", forRemoval=true) public void oldMethod() { }

@Deprecated(since="1.5", forRemoval=true) public void oldMethod() { }

This annotation aids code maintenance by gradually phasing out legacy APIs without breaking existing code. It was introduced in 5 and targets a wide range of declaration contexts (@Target includes TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, PACKAGE, MODULE). @SuppressWarnings allows developers to suppress specific warnings within an annotated element and its sub-elements, reducing from known issues without disabling all warnings globally. It requires a value attribute as a String[] specifying warning categories, such as "unchecked" for generic issues, "deprecation" for deprecated element usage, "removal" for elements marked for removal, or "preview" for preview features; unrecognized or duplicate names are ignored without error. The annotation applies to types, fields, methods, parameters, constructors, and local variables (@Target includes those), with source retention, and is most effective when placed on the innermost relevant element (e.g., a method rather than the enclosing class) to avoid over-suppression. Compilers must support JLS-mandated warnings but may add vendor-specific ones. For instance:

java

@SuppressWarnings("unchecked") public void processList(List list) { // Suppresses unchecked warning for raw type usage }

@SuppressWarnings("unchecked") public void processList(List list) { // Suppresses unchecked warning for raw type usage }

Introduced in Java 5, it supports code correctness by allowing targeted silencing of warnings in legacy or intentionally permissive code. @SafeVarargs, added in Java 7, asserts that a variable-arity method or constructor with varargs parameters performs no potentially unsafe operations on its arguments, such as storing them into an array that might cause heap . It suppresses unchecked warnings at call sites related to non-reifiable vararg types or parameterized array creation, but only applies to static or final methods/constructors (or private methods since Java 9); using it on overridable instance methods triggers a compile-time error to prevent inheritance-related risks. The annotation targets constructors and methods (@Target({CONSTRUCTOR, METHOD})) with runtime retention (@Retention(RUNTIME)), allowing reflection-based checks. Heap occurs when mismatched types lead to runtime ClassCastException, which @SafeVarargs helps avoid by signaling safe usage. Example:

java

@SafeVarargs public static <T> List<T> combine(List<T>... lists) { // Safe varargs handling assumed return Arrays.asList(lists); }

@SafeVarargs public static <T> List<T> combine(List<T>... lists) { // Safe varargs handling assumed return Arrays.asList(lists); }

Compilers may still warn if unsafe operations are detected inside the method. This annotation enhances type safety in generic varargs scenarios, a common need in utility methods.

Specialized Built-in Annotations

In addition to the core annotations, several specialized built-in annotations—spanning the java.lang package and other standard packages—support advanced language features, integrations, and tool usage. These annotations enable validation for constructs, marking generated code, and facilitating testing frameworks, among other specialized roles. They are integral to 's evolution, particularly from Java 8 onward, enhancing and developer productivity without altering core language semantics. The @FunctionalInterface annotation, defined in the java.lang package since 8, serves as an informative marker for interfaces intended to represent expressions or method references. It indicates that the annotated interface should have exactly one abstract method, allowing the to enforce this rule and prevent errors in functional interface usage. For example, applying @FunctionalInterface to an interface with multiple abstract methods results in a , ensuring compatibility with targets. This annotation supports the introduction of in , where such interfaces are ubiquitous in the java.util.function package and Stream API. The @Generated annotation, part of javax.annotation.processing since Java 8, marks produced by automated tools, such as code generators or processors. It includes attributes for the generating tool's name, version, date, and comments, aiding static analysis tools in distinguishing generated code from manually written code—often to suppress warnings or linting on auto-generated elements. For instance, IDEs and build tools like Maven or use this to avoid unnecessary checks on from frameworks like JPA or . This annotation promotes better integration between annotation processors and development workflows. These specialized annotations also contextualize broader features: @FunctionalInterface bolsters support in Java 8, @Generated aids annotation processors in modular builds from Java 9 onward, collectively improving code maintainability and feature-specific validations.

Meta-Annotations

Retention and Target Policies

Java annotations utilize meta-annotations to define their behavior, with @Retention and @Target playing key roles in controlling lifecycle and applicability. The @Retention meta-annotation specifies the retention policy for an annotation type, determining how long it persists through the compilation and execution process. This policy is essential for deciding whether annotations are available for processing at compile time, in , or at runtime via reflection. The RetentionPolicy enum provides three values to guide this behavior. RetentionPolicy.SOURCE indicates that the annotation is discarded by the and retained only in , making it suitable for tools like linters or annotation processors that operate solely at without affecting the final . RetentionPolicy.CLASS, the default if @Retention is omitted, records the annotation in the class file during compilation but discards it at runtime, allowing access by bytecode manipulation tools while minimizing runtime overhead. RetentionPolicy.RUNTIME ensures the annotation is recorded in the class file and retained by the , enabling reflective access during program execution for dynamic behaviors like framework integrations. In declaration, @Retention is applied directly to the annotation interface, as shown in this example:

java

import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {}

import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {}

This configuration allows MyAnnotation to be queried via reflection at runtime. The @Target meta- restricts the kinds of program elements to which an can be applied, preventing misuse and promoting clearer intent. Its value is an array of ElementType enum constants, specifying allowable targets such as classes, methods, or fields; if omitted, the annotation can apply to any element. Key ElementType values include TYPE (for classes, interfaces, enums, or records), FIELD (for fields and enum constants), METHOD (for methods), (for parameters), CONSTRUCTOR (for constructors), LOCAL_VARIABLE (for local variables), ANNOTATION_TYPE (for other annotations), PACKAGE (for packages), TYPE_PARAMETER (for type parameters, since Java 8), TYPE_USE (for type uses, since Java 8), MODULE (for modules, since Java 9), and RECORD_COMPONENT (for record components, since Java 16). For instance, to limit an annotation to fields only:

java

import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Target(ElementType.FIELD) public @interface FieldAnnotation {}

import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Target(ElementType.FIELD) public @interface FieldAnnotation {}

This ensures FieldAnnotation cannot be applied to methods or types, enforcing targeted usage. Combining @Retention and @Target in a declaration provides precise control, as in:

java

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface MyAnno {}

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface MyAnno {}

Here, MyAnno is retained for runtime access but applicable only to fields. Retention policies involve trade-offs in flexibility, performance, and resource use. RUNTIME retention enables powerful runtime introspection but increases class file size and , potentially impacting startup time and reflection-heavy applications; in contrast, SOURCE retention minimizes overhead, ideal for compile-time checks like static analysis tools, while CLASS balances accessibility for bytecode tools without runtime costs. Broad @Target specifications enhance reusability but risk erroneous placements, whereas narrow targets reduce errors at the expense of versatility.

Documentation and Inheritance Meta-Annotations

The @Documented meta-annotation, defined in the java.lang.annotation package, indicates that annotations of a particular type are to be considered part of the public contract of the elements they annotate, ensuring their inclusion in generated documentation such as Javadoc. When applied to an annotation interface declaration, it instructs documentation tools to include instances of that annotation in the output for documented elements like classes, methods, or fields; without @Documented, such annotations are typically excluded from API documentation to avoid cluttering public interfaces. For instance, custom annotations marked with @Documented will appear in Javadoc alongside standard documented elements, promoting transparency in API usage. This meta-annotation targets only annotation types (@Target(ElementType.ANNOTATION_TYPE)) and has runtime retention by default, though its primary impact is on build-time documentation generation. In contrast, the @Inherited meta- enables automatic propagation of class-level annotations to subclasses, facilitating inheritance of metadata in object-oriented hierarchies. When @Inherited is applied to an type declaration targeted at types (classes), any instance of that annotation on a is implicitly inherited by its subclasses unless explicitly overridden by a subclass-specific . This behavior is queried via reflection methods like getAnnotation(), which traverse the upward until the annotation is found or the Object class is reached; if absent throughout, the subclass is treated as unannotated. For example, applying @Inherited to a custom on a base class ensures subclasses automatically acquire it for type-related metadata, such as configuration or behavioral markers. Both meta-annotations have specific limitations to their applicability. @Documented affects only tools and does not influence runtime behavior or annotation retention policies, which are handled separately. Similarly, @Inherited is restricted to with a TYPE target on classes and has no effect on annotations applied to methods, fields, constructors, or other elements, nor does it propagate annotations from implemented interfaces to implementing classes. These constraints ensure predictable behavior in and contexts without unintended side effects across diverse uses.

Processing Mechanisms

Compile-Time Processing

Compile-time processing of Java annotations occurs during the compilation phase, leveraging the Pluggable Annotation Processing API defined in JSR 269 to enable developers to create custom processors that analyze annotated source code and generate additional artifacts or perform validations. This mechanism integrates directly with the compiler, allowing processors to hook into the build process without runtime overhead. The core of this API is the javax.annotation.processing package, which provides interfaces and classes for implementing annotation processors. Processors must implement the Processor interface, which includes methods like process to handle sets of annotated elements and getSupportedAnnotationTypes to declare the annotations they target. Discovery of processors happens automatically via the service provider mechanism: implementations are registered in META-INF/services/javax.annotation.processing.Processor files within their JARs, and the compiler loads them at build time. Processing follows a round-based lifecycle managed by the annotation processing tool environment, typically the compiler itself. In each round, the tool scans source files for annotations supported by registered processors and passes subsets of annotated program elements—such as types, methods, or fields—to the relevant process methods. Processors can then query element details using the Elements utility, generate new source files or resources via the Filer interface, or issue diagnostic messages (warnings or errors) through the Messager. Rounds continue iteratively until no new annotations are found or no further changes are made to the source, ensuring completeness while avoiding infinite loops; the environment signals the end when processing is claimed complete by all processors. This framework supports code generation and boilerplate reduction in popular tools. For instance, Project Lombok uses annotation processors to automatically generate methods like getters, setters, and constructors based on such as @Data, reducing repetitive code in domain classes. Similarly, Google's Auto library employs processors in components like AutoValue and AutoService to generate value classes and registrations from annotations, streamlining immutable data and SPI implementations. In a typical flow, a processor registers support for a custom annotation like @MyAnnotation, receives annotated elements during a round, analyzes their structure (e.g., via Element.getAnnotation), and outputs new .java files to the Filer's source output stream, which are then compiled in subsequent rounds. This build-time approach contrasts with runtime by producing static code enhancements rather than dynamic .

Runtime Processing

Runtime processing of Java annotations occurs through the reflection API, enabling dynamic inspection and utilization of annotations during program execution. The java.lang.reflect package provides the AnnotatedElement interface, implemented by classes such as Class, Method, Field, and Constructor, which represent program elements that can bear annotations. Key methods include getAnnotation(Class<T> annotationClass), which returns the annotation of the specified type if present on the element, or null otherwise, and getAnnotations() to retrieve all annotations on the element. These methods facilitate runtime access to annotation metadata, such as attribute values, allowing frameworks to configure behavior based on annotated elements. Access to annotations at runtime is governed by the @Retention meta-annotation; only those declared with RetentionPolicy.RUNTIME are preserved in the class file and visible via reflection, while SOURCE or CLASS retention policies make annotations unavailable during execution. This design ensures that runtime-visible annotations incur minimal overhead for non-runtime cases, as the compiler discards them from the . For instance, the retains runtime annotations in dedicated class file attributes, enabling reflective queries without additional storage for discarded ones. In practice, runtime annotation processing powers key framework features. The employs reflection to detect @Autowired annotations on fields, constructors, or methods, automatically injecting dependencies during bean initialization via post-processors like AutowiredAnnotationBeanPostProcessor. Similarly, Jakarta Bean Validation uses @Valid to trigger runtime constraint validation on annotated objects, inspecting bean properties reflectively to enforce rules defined by annotations like @NotNull or @Size. These mechanisms rely on runtime retention to enable such dynamic behaviors without compile-time code generation. Performance considerations arise due to reflection's inherent overhead, as accessing annotations involves proxy-based invocation and security checks that bypass direct bytecode access, potentially hindering Just-In-Time (JIT) compiler optimizations. Reflective calls incur a performance overhead compared to direct method invocations, typically around 23% in benchmarks but potentially much higher in hot paths due to lack of JIT inlining and additional runtime checks, though this impact is negligible in infrequent or I/O-bound scenarios. To mitigate, applications should cache annotation results—such as storing retrieved Annotation instances in maps keyed by AnnotatedElement—for repeated queries, reducing redundant lookups in frameworks like Spring.

Practical Examples

Basic Usage Examples

Java annotations provide a way to add metadata to Java program elements such as classes, methods, and fields. A basic custom is declared using the @interface keyword, defining elements as abstract methods that represent the annotation's attributes. For example, the following declares a simple annotation type named SimpleAnno with a single string element msg() and specifies runtime retention using the @Retention meta-, allowing the annotation to be accessible via reflection during program execution.

java

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface SimpleAnno { [String](/page/String) msg(); }

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface SimpleAnno { [String](/page/String) msg(); }

This annotation can then be applied to a method by placing it above the method declaration, providing values for its elements within parentheses. In the example below, the test() method is annotated with SimpleAnno, assigning the value "Hello" to the msg element.

java

public class ExampleClass { @SimpleAnno(msg = "Hello") [public](/page/Public) void [test](/page/.test)() { [System](/page/System).out.println("Annotated method"); } }

public class ExampleClass { @SimpleAnno(msg = "Hello") [public](/page/Public) void [test](/page/.test)() { [System](/page/System).out.println("Annotated method"); } }

To read the at runtime, 's reflection API is used to inspect the method and retrieve the instance. The getAnnotation() method on a Method object returns the if present, allowing access to its elements. The following code demonstrates this by getting the SimpleAnno from the test() method, extracting the msg value, and printing it. This requires the to have RetentionPolicy.RUNTIME for visibility at runtime.

java

import java.lang.reflect.Method; public class AnnotationReader { public static void main(String[] args) throws Exception { Method method = ExampleClass.class.getMethod("test"); SimpleAnno anno = method.getAnnotation(SimpleAnno.class); if (anno != null) { System.out.println("Message: " + anno.msg()); // Outputs: Message: Hello } } }

import java.lang.reflect.Method; public class AnnotationReader { public static void main(String[] args) throws Exception { Method method = ExampleClass.class.getMethod("test"); SimpleAnno anno = method.getAnnotation(SimpleAnno.class); if (anno != null) { System.out.println("Message: " + anno.msg()); // Outputs: Message: Hello } } }

Built-in annotations like @Override offer simple usage for common scenarios without custom declarations. This annotation is applied to a method in a subclass to indicate it overrides a superclass method, helping the compiler verify the override and catch errors. For instance, in a subclass Child extending Parent, the myMethod() is marked with @Override to explicitly signal the overriding intent.

java

class Parent { public void myMethod() { System.out.println("Parent method"); } } class Child extends Parent { @Override public void myMethod() { System.out.println("Child overriding method"); } }

class Parent { public void myMethod() { System.out.println("Parent method"); } } class Child extends Parent { @Override public void myMethod() { System.out.println("Child overriding method"); } }

Advanced Annotation Processing Example

To demonstrate advanced processing for code generation, consider a custom marker @Getter targeted at methods, used to indicate setter methods for which corresponding getter methods should be automatically generated. This has no elements and is defined as follows:

java

import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target(ElementType.METHOD) public @interface Getter {}

import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target(ElementType.METHOD) public @interface Getter {}

The @Target(ElementType.METHOD) meta-annotation restricts the annotation to method declarations, ensuring it applies only to methods such as setters. In practice, libraries like Project Lombok use similar annotations on fields to generate getters and setters, often via manipulation rather than source generation. An annotation processor for @Getter must implement the Processor interface, conventionally by extending AbstractProcessor from the javax.annotation.processing package. The processor declares support for the @Getter annotation via the @SupportedAnnotationTypes meta-annotation and overrides the process method to scan source elements. In this method, the processor uses the RoundEnvironment to retrieve elements annotated with @Getter, filters for method elements, and infers getter method signatures from the setter method names (e.g., transforming setProperty to getProperty). It then employs the Filer from the ProcessingEnvironment to generate a new source file for a companion class containing the getter methods. A simplified implementation might look like this (assuming the annotation is in package com.example):

java

import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import java.io.PrintWriter; import java.util.Set; @SupportedAnnotationTypes("com.example.Getter") @SupportedSourceVersion(SourceVersion.RELEASE_17) public class GetterProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Getter.class); for (Element element : ElementFilter.methodsIn(elements)) { ExecutableElement method = (ExecutableElement) element; if (!isValidSetter(method)) continue; TypeElement classElement = (TypeElement) element.getEnclosingElement(); String setterName = method.getSimpleName().toString(); String getterName = inferGetterName(setterName); VariableElement param = method.getParameters().get(0); String fieldName = param.getSimpleName().toString(); // Assume field name matches param String returnType = param.asType().toString(); generateGetter(classElement, getterName, returnType, fieldName); } return true; // Claim the annotations } private boolean isValidSetter(ExecutableElement method) { return method.getParameters().size() == 1 && method.getSimpleName().toString().startsWith("set"); } private String inferGetterName(String setterName) { return "get" + setterName.substring(3); } private void generateGetter(TypeElement classElement, String getterName, String returnType, String fieldName) { try { String className = classElement.getSimpleName() + "Getters"; String packageName = getPackageName(classElement); JavaFileObject file = processingEnv.getFiler().createSourceFile(packageName + "." + className); try (PrintWriter writer = new PrintWriter(file.openWriter())) { writer.println("package " + packageName + ";"); writer.println(); writer.println("import " + classElement.getQualifiedName() + ";"); writer.println(); writer.println("public class " + className + " {"); writer.println(" public static " + returnType + " " + getterName + "(" + classElement.getSimpleName() + " instance) {"); writer.println(" return instance." + fieldName + ";"); writer.println(" }"); writer.println("}"); } } catch (Exception e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), null); } } private String getPackageName(TypeElement classElement) { Element enclosing = classElement.getEnclosingElement(); if (enclosing instanceof PackageElement) { return ((PackageElement) enclosing).getQualifiedName().toString(); } return ""; } }

import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.util.ElementFilter; import javax.tools.JavaFileObject; import java.io.PrintWriter; import java.util.Set; @SupportedAnnotationTypes("com.example.Getter") @SupportedSourceVersion(SourceVersion.RELEASE_17) public class GetterProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Getter.class); for (Element element : ElementFilter.methodsIn(elements)) { ExecutableElement method = (ExecutableElement) element; if (!isValidSetter(method)) continue; TypeElement classElement = (TypeElement) element.getEnclosingElement(); String setterName = method.getSimpleName().toString(); String getterName = inferGetterName(setterName); VariableElement param = method.getParameters().get(0); String fieldName = param.getSimpleName().toString(); // Assume field name matches param String returnType = param.asType().toString(); generateGetter(classElement, getterName, returnType, fieldName); } return true; // Claim the annotations } private boolean isValidSetter(ExecutableElement method) { return method.getParameters().size() == 1 && method.getSimpleName().toString().startsWith("set"); } private String inferGetterName(String setterName) { return "get" + setterName.substring(3); } private void generateGetter(TypeElement classElement, String getterName, String returnType, String fieldName) { try { String className = classElement.getSimpleName() + "Getters"; String packageName = getPackageName(classElement); JavaFileObject file = processingEnv.getFiler().createSourceFile(packageName + "." + className); try (PrintWriter writer = new PrintWriter(file.openWriter())) { writer.println("package " + packageName + ";"); writer.println(); writer.println("import " + classElement.getQualifiedName() + ";"); writer.println(); writer.println("public class " + className + " {"); writer.println(" public static " + returnType + " " + getterName + "(" + classElement.getSimpleName() + " instance) {"); writer.println(" return instance." + fieldName + ";"); writer.println(" }"); writer.println("}"); } } catch (Exception e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage(), null); } } private String getPackageName(TypeElement classElement) { Element enclosing = classElement.getEnclosingElement(); if (enclosing instanceof PackageElement) { return ((PackageElement) enclosing).getQualifiedName().toString(); } return ""; } }

This processor uses ElementFilter to identify annotated methods, validates they are setters, derives the getter logic from method metadata including inferring the field from the parameter name, and invokes Filer.createSourceFile to produce a new .java file with the generated getter as a static method in a companion class, avoiding modification of the original source. The processingEnv.getFiler() provides the Filer instance during init. Returning true from process indicates the processor has handled the annotations, preventing further processing in subsequent rounds unless new sources are generated. For automatic discovery by the compiler, the processor is registered via the Java service loader mechanism. Create a file at META-INF/services/javax.annotation.processing.Processor in the processor's JAR, containing the fully qualified class name (e.g., com.example.GetterProcessor). This file lists available processors, allowing javac to load them without explicit specification. To compile and invoke the processor, place the processor JAR on the classpath or processor path and use the javac command with the -processor option. For instance, assuming a source file MyClass.java with a setter method annotated @Getter:

bash

javac -processor com.example.GetterProcessor MyClass.java

javac -processor com.example.GetterProcessor MyClass.java

This command triggers the processor during compilation, generating the companion getters class in a source directory (e.g., under a generated sources directory specified via -s), which is then compiled into the output. The resulting includes the automatically generated getters, enhancing code generation without manual implementation. If only is desired without full compilation, use -proc:only.

References

Add your contribution
Related Hubs
Contribute something
User Avatar
No comments yet.