Spring ‐ Aspect‐Oriented Programming (AOP) - Yash-777/MyWorld GitHub Wiki
Enabling
@AspectJ
Support with Java configuration
To enable @AspectJ
support with Java @Configuration
add the @EnableAspectJAutoProxy
annotation:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
RequestLoggingAspect
package com.github.myworld.aspects;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Aspect
@Component
@org.springframework.context.annotation.EnableAspectJAutoProxy
public class RequestLoggingAspect {
// @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping) " + //@RequestMapping(method = RequestMethod.GET)
// "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
// "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" + // @PostMapping(value = "")
// "|| @annotation(org.springframework.web.bind.annotation.PathVariable)" +
// "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
// "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
// )
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.GetMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.PostMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.PathVariable) " +
"|| @annotation(org.springframework.web.bind.annotation.PutMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)")
public void requestMapping() {
}
@Around("requestMapping()")
public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable {
org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
System.out.println("MethodSignature:"+ signature );
long startTime = System.currentTimeMillis();
// Log request details before method execution
logRequestDetails(joinPoint);
logDetails(joinPoint);
// Proceed with the original method execution
Object result = joinPoint.proceed();
// Log response details after method execution
long endTime = System.currentTimeMillis();
logResponseDetails(result, endTime - startTime);
return result;
}
public void printRequestMappingParam(org.springframework.web.bind.annotation.RequestMapping requestParam) {
//org.springframework.web.bind.annotation.RequestMapping requestParam = AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.RequestMapping.class);
if (requestParam != null) {// @RequestParam
String nameOfMapping = requestParam.name();
if (nameOfMapping != null && nameOfMapping.length() > 0) {
System.out.println("nameOfMapping:"+nameOfMapping);
}
String[] headers = requestParam.headers();
for (String header : headers) {
System.out.println("Header:"+header);
}
String[] produces = requestParam.produces();
for (String produce : produces) {
System.out.println("produces:"+produce);
}
String[] consumes = requestParam.consumes();
for (String consume : consumes) {
System.out.println("Consumes:"+consume);
}
RequestMethod[] requestedMethod = requestParam.method();
for (RequestMethod requestedMeth : requestedMethod) {
System.out.println("RequestMethod:"+requestedMeth);
}
String[] params = requestParam.params();
for (String param : params) {
System.out.println("Param:"+param);
}
String[] values = requestParam.value();
for (String value : values) {
System.out.println("values:"+value);
}
}
}
public Object forwordReq(ProceedingJoinPoint joinPoint) throws Throwable {
//long startTime = System.currentTimeMillis();
org.springframework.util.StopWatch sw = new org.springframework.util.StopWatch();
sw.start("logExecutionTime:");
Object result = joinPoint.proceed();
sw.stop();
long timeTaken = sw.getTaskInfo()[0].getTimeMillis(); //endTime = System.currentTimeMillis() - startTime;
System.out.println("Timetaken in MilliSec:"+timeTaken);
return result;
}
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
// Access the HttpServletRequest
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
// log.info("Request received: Method={}, Headers={}, QueryParams={}, PathVariables={}, RequestBody={}",
// request.getMethod(), request.getHeaderNames(), request.getParameterMap(),
// pathVariables, requestObject);
// Extract request details (headers, parameters, path variables, request body)
// Convert request body to JSON (if applicable)
// Log the details
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
System.out.println(headerNames.nextElement());
}
org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
System.out.println("MethodSignature:"+ signature );
java.lang.reflect.Method method = signature.getMethod();
// HttpComponentsClientHttpRequestFactory - method.getClass()
// AnnotationFilter JAVA_LANG_ANNOTATION_FILTER = AnnotationFilter.packages("java.lang.annotation")
//@org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[GET], name=, produces=[], params=[], value=[compensation/ratecard/{planId}], consumes=[])
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
//Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : declaredAnnotations) {
System.out.println("annotation:"+annotation.toString());
//@org.springframework.security.access.prepost.PreAuthorize(value=)
if (annotation instanceof org.springframework.web.bind.annotation.PathVariable) {// @PathVariable
org.springframework.web.bind.annotation.PathVariable pathVar = (PathVariable) annotation;
//org.springframework.web.bind.annotation.PathVariable pathVariable = AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.PathVariable.class);
System.out.println("Annotation - PathVariable - name:val = " + pathVar.name() + " : " + pathVar.value());
}
//Key: interface org.springframework.web.bind.annotation.RequestMapping
//Value: @org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[POST], name=, produces=[], params=[], value=[organizationalUnit], consumes=[])
if (annotation instanceof org.springframework.web.bind.annotation.RequestParam) { // @javax.ws.rs.QueryParam
org.springframework.web.bind.annotation.RequestParam requestPar = (RequestParam) annotation;
System.out.println("Annotation - RequestParam - name:val = " + requestPar.name() + " : " + requestPar.value());
}
if (annotation instanceof org.springframework.web.bind.annotation.RequestMapping) { // @javax.ws.rs.QueryParam
org.springframework.web.bind.annotation.RequestMapping requestParam = (RequestMapping) annotation;
//org.springframework.web.bind.annotation.RequestMapping requestParam = AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.RequestMapping.class);
System.out.println("Annotation - RequestMapping - name:val = " + requestParam.name() + " : " + requestParam.value());
printRequestMappingParam(requestParam);
}
}
Object result = forwordReq(joinPoint);
return result;
}
public void logDetails(ProceedingJoinPoint joinPoint) throws Throwable {
// Access the HttpServletRequest
System.out.println("----- logDetails -----");
org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
//System.out.println("MethodSignature:"+ signature );
java.lang.reflect.Method method = signature.getMethod();
// HttpComponentsClientHttpRequestFactory - method.getClass()
// AnnotationFilter JAVA_LANG_ANNOTATION_FILTER = AnnotationFilter.packages("java.lang.annotation")
//@org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[GET], name=, produces=[], params=[], value=[compensation/ratecard/{planId}], consumes=[])
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
for (Annotation annotation : declaredAnnotations) {
System.out.println("Method DeclaredAnnotations:"+annotation.toString());
//@org.springframework.security.access.prepost.PreAuthorize(value=hasPermission('/commissionrun/view', 'Feature Access'))
//@org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[GET], name=, produces=[], params=[], value=[commissionrundetails/{periodName}], consumes=[])
if (annotation instanceof org.springframework.web.bind.annotation.RequestMapping) {
org.springframework.web.bind.annotation.RequestMapping requestParam = (RequestMapping) annotation;
//org.springframework.web.bind.annotation.RequestMapping requestParam = AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.RequestMapping.class);
System.out.println("Annotation - RequestMapping - name:val = " + requestParam.name() + " : " + requestParam.value());
printRequestMappingParam(requestParam);
}
}
/*
* it's important to note that @QueryParam is not a Spring annotation; it's typically used in JAX-RS (Java API for RESTful Web Services).
* In Spring, query parameters are usually handled using @RequestParam. Below is an example of a Spring Rest API method that accepts
* @PathVariable, @RequestParam, and a query parameter (assuming it as @RequestParam): // @javax.ws.rs.QueryParam
*/
Annotation[] annotationsOnMethod = method.getAnnotations();
for (Annotation annotation : annotationsOnMethod) {
System.out.println("Method annotationsOnMethod:"+annotation.toString());
}
// if (annotation instanceof org.springframework.web.bind.annotation.PathVariable) {// @PathVariable
// org.springframework.web.bind.annotation.PathVariable pathVar = (PathVariable) annotation;
// //org.springframework.web.bind.annotation.PathVariable pathVariable = AnnotationUtils.findAnnotation(method, org.springframework.web.bind.annotation.PathVariable.class);
// System.out.println("Annotation - PathVariable - name:val = " + pathVar.name() + " : " + pathVar.value());
// }
// //Key: interface org.springframework.web.bind.annotation.RequestMapping
// //Value: @org.springframework.web.bind.annotation.RequestMapping(path=[], headers=[], method=[POST], name=, produces=[], params=[], value=[organizationalUnit], consumes=[])
// if (annotation instanceof org.springframework.web.bind.annotation.RequestParam) { // @javax.ws.rs.QueryParam
// org.springframework.web.bind.annotation.RequestParam requestPar = (RequestParam) annotation;
// System.out.println("Annotation - RequestParam - name:val = " + requestPar.name() + " : " + requestPar.value());
// }
System.out.println("----- logDetails -----");
}
private void logRequestDetails(ProceedingJoinPoint joinPoint) throws IOException {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// Log request method, URI, headers, query parameters, and request body
System.out.println("Request Method: " + request.getMethod());
System.out.println("Request URI: " + request.getRequestURI());
System.out.println("Request Headers: " + getRequestHeaders(request));
System.out.println("Query String: " + request.getQueryString()); // regionCode=TMPL
System.out.println("Query Parameters: " + getRequestParameters(request)); // {regionCode=[TMPL]} = /commissionrundetails/202310?regionCode=TMPL
// Log request body in JSON format
if (request.getInputStream() != null) {
// Handle the HttpServletRequest
ServletInputStream inputStream = request.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
Stream<String> lines = bufferedReader.lines();
Optional<String> reduce = lines.reduce(String::concat);
if (reduce.isPresent()) { // NoSuchElementException: No value present at java.util.Optional.get(Optional.java:135)
String requestBody = reduce.get();
System.out.println("HttpServletRequest Body String: " + requestBody );
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode requestBodyJson = objectMapper.valueToTree(requestBody);
System.out.println("HttpServletRequest Body JSON Node: " + requestBodyJson);
} catch (Exception e) {
System.err.println("Error parsing request body: " + e.getMessage());
}
}
}
}
}
private void logResponseDetails(Object result, long executionTime) {
// Log response details
System.out.println("Response: " + result);
System.out.println("Execution Time: " + executionTime + " ms");
}
private Map<String, String> getRequestHeaders(HttpServletRequest request) {
return Collections.list(request.getHeaderNames())
.stream()
.collect(Collectors.toMap(name -> name, request::getHeader));
}
private Map<Object, Object> getRequestParameters(HttpServletRequest request) {
return request.getParameterMap()
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> Arrays.toString(entry.getValue())));
}
}