How to create Custom Annotations in Java and Spring Boot
Usually when we are working with Java and Spring Boot, specific needs arise that require the use of not-so-common technologies such as AOP (Aspect-Oriented Programming). This is generally used to handle specific functions that must be executed based on certain guidelines, for example.
Use Case: A company needs to know how many times the user checks the account status service in a month.
Solution Proposal: Create an annotation that evaluates client identifiers, for example, an ID, and records the queries made by the clients to this service, saving them in a table that can be queried. For this example, we will do it in cache.
Step 1: Define the annotation with parameters
Let’s start by defining our custom annotation with parameters to detect certain values in HTTP requests:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SpecificParameter {
String value() default ""; // The value of the parameter to detect
}
In this annotation, we’ve defined a value
attribute that will represent the name of the parameter we want to detect in the requests.
Step 2: Using the annotation in a controller
Now, we can use our custom annotation in a Spring Boot controller to detect specific parameters in the requests:
import org.springframework.web.bind.annotation.*;
@RestController
public class ExampleController {
@GetMapping("/")
@SpecificParameter("card")
public String checkStatusCard(@RequestParam(name = "card") String card, @RequestParam String id) {
return "status account for client id, " + id+ "!"; //this is a simple example code
}
}
In this example, we’ve applied our @SpecificParameter
annotation to the checkStatusCard()
method and specified that we want to detect the parameter named "card".
Step 3: Accessing the annotation in an aspect
To access the annotation metadata at runtime, we’ll create a Spring aspect that intercepts annotated methods and checks if the specified parameter is provided in the request:
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.*;
import org.springframework.web.context.request.*;
@Aspect
@Component
public class SpecificParameterAspect {
private static final Map<String, Integer> queryCountMap = new ConcurrentHashMap<>();
public static void incrementQueryCount(String clientId) {
queryCountMap.put(clientId, queryCountMap.getOrDefault(clientId, 0) + 1);
}
public static int getQueryCount(String clientId) {
return queryCountMap.getOrDefault(clientId, 0);
}
@Before("@annotation(specificParameter)")
public void beforeAnnotatedMethod(JoinPoint joinPoint, SpecificParameter specificParameter) {
String parameterName = specificParameter.value();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String parameterValue = request.getParameter(parameterName);
if (parameterValue != null) {
System.out.println("The parameter '" + parameterName + "' was detected in the request with the value: " + parameterValue);
incrementQueryCount(parameterValue); // Increment query count for the client ID
} else {
System.out.println("The parameter '" + parameterName + "' was not detected in the request.");
}
}
}
With this cache implementation, you can increment the query count for each client ID and retrieve the query count for a specific client ID. This map can be accessed and updated by the annotation or any other part of the application as needed.
- The
AccountStatusCache
methodsincrementQueryCount
andgetQueryCount
are included in theSpecificParameterAspect
. - Inside the
beforeAnnotatedMethod
advice, when a parameter is detected in the request, theincrementQueryCount
method is called to increment the query count for the corresponding client ID.
Conclusion
In this example, we explored the creation of a custom annotation in Java and Spring Boot to address a specific use case where a company needs to track how many times users access the account status service. By leveraging aspects and annotations, we were able to design a solution that detects client identifiers in HTTP requests and records the queries made to the service in a cache map.
This tutorial demonstrated the power and flexibility of using custom annotations and aspects in Spring Boot applications. By extending the functionality of Spring’s AOP capabilities, developers can implement domain-specific logic in a modular and reusable manner, enhancing the overall maintainability and scalability of their applications.
Through this tutorial, you should now have a solid understanding of how to create and integrate custom annotations and aspects into your Java and Spring Boot projects, empowering you to address a wide range of business requirements with elegance and efficiency.
Thank you for reading