springspring-bootaspectjspring-el

Using SPEL to call a method in the same class passing a variable taken from the actual method


I want to be able to call another method of my class by passing the value of a parameter of the calling method, so suppose:

public class MyClass{

   @MySpelAnnotation("#this.otherMethod()") //how to I pass "arg" as parameter?
   public void mainMethod(String arg){
        ...
   }

   public void otherMethod(String arg){

   }

How can I be able to take arg from the first method and pass it to the second one?


Solution

  • You need to evaluate the expression against an evaluation context that contains the argument bound as a variable under the #arg name:

    @MySpelAnnotation("#this.otherMethod(#arg)")
    

    You can use Spring's MethodBasedEvaluationContext for this:

    @Aspect
    static class MyAspect {
        @After("@annotation(annotation)")
        void after(JoinPoint joinPoint, MySpelAnnotation annotation) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    
            // expression should be cached for better performance
            Expression expression = new SpelExpressionParser()
                    .parseExpression(annotation.value());
    
            MethodBasedEvaluationContext context =
                    new MethodBasedEvaluationContext(
                            joinPoint.getTarget(),
                            signature.getMethod(),
                            joinPoint.getArgs(),
                            new DefaultParameterNameDiscoverer());
    
            expression.getValue(context);
        }
    }
    

    Note that parsing the expression is a non-trivial operation that should ideally be cached.