Skip to content

harman-04/java-custom-annotations-reflection

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Java Custom Annotations & Reflection API

Overview

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.


Core Components

1. Defining the Annotation (@AuthorizeRole)

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.

2. The Service Layer (SecurityService)

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 @Deprecated annotation to show how custom processors can interact with standard Java metadata.

3. The Annotation Processor (Reflection API)

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.

Code Execution Flow

  1. Scanning: The AnnotationProcessor loops through every method in SecurityService.
  2. Discovery: It finds deleteDataBase and detects the @AuthorizeRole tag.
  3. Extraction: It reads value="ADMIN" and level=10.
  4. Logic Execution: Because the level is , it prints a high-security warning.
  5. Standard Processing: It detects the @Deprecated tag on oldLoginMethod and 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.

1. High-Level Architecture / Component Diagram

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
Loading

2. Sequence Diagram: The Introspection Flow

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()

Loading

Key Takeaways

  • 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 level requirement—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.

About

A deep dive into Java Annotations and Reflection API. Implements a custom @AuthorizeRole annotation and a runtime processor to simulate a role-based security check.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages