sadhana gm
sadhana gm

Reputation: 21

How to print the caller method name as the caller name in the aspect

Why does the Aspect print the caller class name instead of the calling method name in the caller information? When attempting to print the calling method name, why does it result in a StackOverflow error?

when printing information about the caller, the Aspect prints the name of the class containing the method instead of the name of the calling method itself.

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.JoinPoint;

@Aspect
public class AspectJAspect {
private static long aspectStartTime;
private static int serialNumber = 1;

// Pointcut to capture the main method of any class across any package
@Pointcut("execution(public static void main(String[]))")
public void mainMethod() {}

// Advice triggered before entering the main method
@Before("mainMethod()")
public void beforeMainMethodExecution(JoinPoint joinPoint) {
    aspectStartTime = System.currentTimeMillis(); 
    System.out.println("\"main\"" + ", \"" + serialNumber++ + "\"" + ", \"SYSTEM\"" + ", \"System Start\", \" \"");
    System.out.println("\"main\"" + ", \"" + serialNumber++ + "\"" + ", \"SYSTEM\"" + ", \"Thread Start\", \"main\"");
    System.out.println("\"main\"" + ", \"" + serialNumber++ + "\"" + ", \"SYSTEM\"" + ", \"Type Load\", \"class=java.lang.Object\"");
    System.out.println("\"main\"" + ", \"" + serialNumber++ + "\"" + ", \"SYSTEM\"" + ", \"Type Load\", \"class=" + joinPoint.getSignature().getDeclaringType().getName() + "\"");
}

// Pointcut to capture any method execution
@Pointcut("execution(* *(..))")
public void anyMethod() {}

// Pointcut to capture any constructor execution
@Pointcut("call(*.new(..))")
public void anyConstructor() {}

// Pointcut to capture field updates within methods
@Pointcut("set(* *) && !within(AspectJAspect)")
public void fieldUpdate() {}

// Advice triggered before any method execution
@Before("anyMethod()")
public void beforeMethodExecution(JoinPoint joinPoint) {
    // Get thread name, method name, and source information
    String threadName = Thread.currentThread().getName();
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getName();
    String callerName = joinPoint.getSourceLocation().getWithinType().getSimpleName();
    String calleeName = signature.getDeclaringTypeName() + "." + signature.getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    
    // Print method call information
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Call\", \"caller = " + callerName + "\", \"target = " + methodName + "\"");
    // Print method entry message as already in the code
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Entry\", \"" + methodName + "\"");
}

// Advice triggered after a field update within a method
@After("fieldUpdate()")
public void afterFieldUpdate(JoinPoint joinPoint) {
    // Get field name, new value, thread name, and source information
    String fieldName = joinPoint.getSignature().getName();
    Object newValue = joinPoint.getArgs()[0];
    String threadName = Thread.currentThread().getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    
    // Check if the method signature represents a constructor
    boolean isConstructor = joinPoint.getSignature() instanceof MethodSignature &&
                             ((MethodSignature) joinPoint.getSignature()).getMethod().getName().equals("<init>");
    
    // Print field write message
    if (isConstructor) {
        System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Field Write\", \"" + fieldName + " is updated to " + newValue + "\"");
    } else {
        System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Field Write\", \"" + fieldName + " is updated to " + newValue + "\"");
    }
}

// Advice triggered after any method execution
@After("anyMethod()")
public void afterMethodExecution(JoinPoint joinPoint) {
    // Get thread name, method name, and source information
    String threadName = Thread.currentThread().getName();
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    // Print method exit message
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Exit\", \"" + methodName + "\"");
}

// Advice triggered before any constructor execution
@Before("anyConstructor()")
public void beforeConstructorExecution(JoinPoint joinPoint) {
    // Get thread name, constructor name, and source information
    String threadName = Thread.currentThread().getName();
    String constructorName = joinPoint.getSignature().getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    // Print constructor entry message
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Entry\", \"" + constructorName + "\"");
}

// Advice triggered after any constructor execution
@After("anyConstructor()")
public void afterConstructorExecution(JoinPoint joinPoint) {
    // Get thread name, constructor name, and source information
    String threadName = Thread.currentThread().getName();
    String constructorName = joinPoint.getSignature().getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    // Print constructor exit message
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Exit\", \"" + constructorName + "\"");
}  

// Advice triggered after the main method exits of any class across any package
@After("execution(public static void main(String[]))")
public void afterMainMethod(JoinPoint joinPoint) {
    // Capture end time of the aspect
    long aspectEndTime = System.currentTimeMillis();
    // Calculate aspect execution time
    long aspectExecutionTime = aspectEndTime - aspectStartTime;
    // Print aspect execution time
    System.out.println("Aspect execution time: " + aspectExecutionTime + " milliseconds");
}
}

Below is the code which resulted in StackOverFlow error

// Method to get the name of the calling method
private String getCallerMethodName() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

    // Start from index 3 to ignore getStackTrace, getCallerMethodName, and beforeMethodExecution
    for (int i = 3; i < stackTrace.length; i++) {
        StackTraceElement element = stackTrace[i];
        if (!element.getClassName().equals(AspectJAspect.class.getName())) {
            return element.getFileName() + "#" + element.getMethodName();
        }
    }

    // If no caller found, return "Unknown"
    return "Unknown";
}


// Advice triggered before any method execution
@Before("anyMethod()")
public void beforeMethodExecution(JoinPoint joinPoint) {
    // Get thread name, method name, and source information
    String threadName = Thread.currentThread().getName();
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getName();
    String callerName = getCallerMethodName();
    String calleeName = signature.getDeclaringTypeName() + "." + signature.getName();
    String sourceInfo = joinPoint.getSourceLocation().getFileName() + ":" + joinPoint.getSourceLocation().getLine();
    
    // Print method call information
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Call\", \"caller = " + callerName + "\", \"target = " + methodName + "\"");
    // Print method entry message as already in the code
    System.out.println("\"" + threadName + "\"" + ", \"" + serialNumber++ + "\"" + ", \"" + sourceInfo + "\"" + ", \"Method Entry\", \"" + methodName + "\"");
}
"main", "1", "SYSTEM", "System Start", " "
"main", "2", "SYSTEM", "Thread Start", "main"
"main", "3", "SYSTEM", "Type Load", "class=java.lang.Object"
"main", "4", "SYSTEM", "Type Load", "class=org.mazouz.aop.Main1"
"main", "5", "Main1.java:18", "Method Call", "caller = Main1", "target = main"
"main", "6", "Main1.java:18", "Method Entry", "main"
"main", "7", "Main1.java:20", "Method Entry", "<init>"
"main", "8", "Main1.java:13", "Field Write", "x is updated to 96"
"main", "9", "Main1.java:14", "Field Write", "m is updated to 9"
"main", "10", "Main1.java:15", "Field Write", "kl is updated to 10"
"main", "11", "Main1.java:20", "Method Exit", "<init>"
"main", "12", "Main1.java:26", "Method Call", "caller = Main1", "target = setX"
"main", "13", "Main1.java:26", "Method Entry", "setX"
"main", "14", "Main1.java:28", "Field Write", "x is updated to 42"
"main", "15", "Main1.java:29", "Field Write", "x is updated to 45"
"main", "16", "Main1.java:30", "Field Write", "x is updated to 78"
"main", "17", "Main1.java:26", "Method Exit", "setX"
"main", "18", "Main1.java:33", "Method Call", "caller = Main1", "target = setY"
"main", "19", "Main1.java:33", "Method Entry", "setY"
"main", "20", "Main1.java:35", "Field Write", "y is updated to 43"
"main", "21", "Main1.java:36", "Field Write", "z is updated to 3"
"main", "22", "Main1.java:33", "Method Exit", "setY"
"main", "23", "Main1.java:39", "Method Call", "caller = Main1", "target = setZ"
"main", "24", "Main1.java:39", "Method Entry", "setZ"
"main", "25", "Main1.java:41", "Field Write", "y is updated to 44"
"main", "26", "Main1.java:42", "Field Write", "z is updated to 8"
"main", "27", "Main1.java:39", "Method Exit", "setZ"
"main", "28", "Main1.java:18", "Method Exit", "main"

Upvotes: 0

Views: 48

Answers (0)

Related Questions