Annotations in Java are a form of metadata—they provide data about a program that is not part of the program itself. This project demonstrates how to define a custom annotation, apply it to methods, and use the Reflection API to "read" those annotations and trigger logic based on their values.
To create an annotation, we use the @interface keyword. We also use Meta-Annotations to define how this annotation behaves:
@Target(ElementType.METHOD): Restricts this annotation so it can only be placed on methods.@Retention(RetentionPolicy.RUNTIME): Crucial for this project; it ensures the annotation is available in the JVM during execution so our processor can see it.
This class simulates a real-world application where different actions require different permissions.
deleteDataBase()is marked with a high security level (10).postMessage()uses the default level (1).- We also included the built-in
@Deprecatedannotation to show how custom processors can interact with standard Java metadata.
This is the "Engine" of the project. It doesn't call the methods directly; instead, it inspects the SecurityService class using Reflection:
clazz.getDeclaredMethods(): Retrieves all methods inside the class.isAnnotationPresent(): Checks if a method is "tagged" with our specific annotation.getAnnotation(): Extracts the data (Role and Level) from the tag.
- Scanning: The
AnnotationProcessorloops through every method inSecurityService. - Discovery: It finds
deleteDataBaseand detects the@AuthorizeRoletag. - Extraction: It reads
value="ADMIN"andlevel=10. - Logic Execution: Because the level is , it prints a high-security warning.
- Standard Processing: It detects the
@Deprecatedtag onoldLoginMethodand alerts the developer.
This code demonstrates the power of Java Reflection combined with Custom Runtime Annotations. It shows how you can tag your code with metadata (the annotation) and then write another piece of code (the processor) to read and act upon that metadata while the program is running.
Here are the architectural and sequence diagrams breaking down this process.
This diagram shows the relationship between the three distinct parts of the system: the annotation definition, the class using the annotation, and the processor that inspects it using Java Reflection.
- Purple Component: The definition of the metadata rule (
@interface). - Blue Component: The standard application code that is "tagged" with the metadata.
- Green Component: The "meta-programming" logic that inspects the code at runtime.
graph TD
subgraph Annotation_Def ["Annotation Definition"]
Def["AuthorizeRoleAnnotation<br/>@interface AuthorizeRole<br/>(Retention: RUNTIME)"]
end
subgraph Target_Code ["Target Code (Annotated Class)"]
TargetClass["SecurityService Class"]
Method1["Method: deleteDataBase<br/>@AuthorizeRole(ADMIN, level=10)"]
Method2["Method: postMessage<br/>@AuthorizeRole(USER)"]
Method3["Method: oldLoginMethod<br/>@Deprecated"]
TargetClass --> Method1
TargetClass --> Method2
TargetClass --> Method3
end
subgraph Runtime_Processor ["Runtime Processor"]
Processor["AnnotationProcessor Class<br/>(main method)"]
end
%% Relationships
TargetClass -.->|Uses| Def
Processor -->|"1. Instantiates"| TargetClass
Processor ====>|"2. Inspects via Java Reflection API"| TargetClass
Processor -.->|"3. Reads Metadata at Runtime"| Def
%% UNIVERSAL THEME STYLING
style Def fill:#e1bee7,stroke:#4a148c,stroke-width:2px,color:#000
style TargetClass fill:#bbdefb,stroke:#0d47a1,stroke-width:2px,color:#000
style Processor fill:#c8e6c9,stroke:#1b5e20,stroke-width:2px,color:#000
style Method1 fill:#fff9c4,stroke:#fbc02d,stroke-width:1px,color:#000
style Method2 fill:#fff9c4,stroke:#fbc02d,stroke-width:1px,color:#000
style Method3 fill:#eeeeee,stroke:#bdbdbd,stroke-width:1px,color:#000
This diagram details the step-by-step execution of the AnnotationProcessor.main() method. It visualizes the loop iterating through methods and the specific reflection calls used to extract information.
sequenceDiagram
autonumber
actor JVM as Java Runtime (JVM)
participant Processor as AnnotationProcessor (main)
participant TargetClazz as Class<SecurityService>
participant MethodObj as java.lang.reflect.Method
participant AuthAnno as @AuthorizeRole Instance
Note over Processor: Start main() entry point
Note right of Processor: 1. Get Class Metadata
Processor->>JVM: new SecurityService().getClass()
JVM-->>Processor: Returns Class<SecurityService> Object
Note right of Processor: 2. Retrieve all declared methods
Processor->>TargetClazz: getDeclaredMethods()
TargetClazz-->>Processor: Returns Method[] array (deleteDataBase, postMessage, oldLoginMethod)
loop For each Method in Method[]
note right of Processor: --- Iteration Start ---
Note right of Processor: Check for Custom Annotation
Processor->>MethodObj: isAnnotationPresent(AuthorizeRole.class)
alt Annotation is Present (e.g., deleteDataBase)
MethodObj-->>Processor: true
Processor->>MethodObj: getAnnotation(AuthorizeRole.class)
MethodObj-->>Processor: Returns @AuthorizeRole instance proxy
note right of Processor: Read Annotation Attributes
Processor->>AuthAnno: value()
AuthAnno-->>Processor: Returns "ADMIN" (e.g.)
Processor->>AuthAnno: level()
AuthAnno-->>Processor: Returns 10 (e.g.)
Processor->>Processor: Print Role & Level values
opt If level > 5
Processor->>Processor: Print "🚩 HIGH SECURITY METHOD DETECTED"
end
else Annotation is NOT Present
MethodObj-->>Processor: false
end
Note right of Processor: Check for Standard Annotation
Processor->>MethodObj: isAnnotationPresent(Deprecated.class)
alt Annotation is Present (e.g., oldLoginMethod)
MethodObj-->>Processor: true
Processor->>Processor: Print "Method is DEPRECATED!"
end
note right of Processor: --- Iteration End ---
end
Note over Processor: End main()
- Decoupling: The security logic is not hardcoded inside the business methods. It is "declared" on top of them.
- Automation: You could easily extend this to prevent method execution if a user doesn't meet the
levelrequirement—this is exactly how Spring Security works behind the scenes. - Runtime Flexibility: The application changes its behavior based on annotations without needing to change the core logic of the
SecurityService.