Aspectj optional parameter binding

2.4k views Asked by At

I would like Aspectj to bind my method arguments using args.

Something like this:

    @Before("@annotation(authorized) && args(java.util.String)")
    public void authorize(JoinPoint joinPoint, Authorized authorized, String str)

However, I can not count on the String argument being present. I want the advice to be applied to all methods using that annotation, not only the methods with a String argument.

If the advised method does not have a String argument, I'd like to have str filled with a null value. Is this possible? Or is the only option to use joinPoint.getArgs()?

2

There are 2 answers

0
kriegaex On BEST ANSWER

I have an answer to the question you asked in the comment to Andy's answer:

Would it be possible to advice methods with unknown amount of arguments, but not ending with an argument of a specific type?

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Authorized {}
package de.scrum_master.app;

public class Application {
    @Authorized static void bla(String string, int i, int j) {}
    @Authorized static void baz(String string, int i, Integer integer) {}
    @Authorized static void zot(String string) {}
    @Authorized static void bar(Integer integer) {}
    @Authorized static void foo() {}

    public static void main(String[] args) {
        foo();
        bar(new Integer(11));
        zot("xxx");
        baz("yyy", 123, new Integer(22));
        bla("zzz", 123, 456);
    }
}
package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import de.scrum_master.app.Authorized;

@Aspect
public class MyAspect {
    @Before("@annotation(authorized) && execution(* *(..)) && !execution(* *(.., Integer))")
    public void authorize(JoinPoint joinPoint, Authorized authorized) {
        System.out.println(joinPoint);
    }
}

Console output:

execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot(String))
execution(void de.scrum_master.app.Application.bla(String, int, int))

As you can see, the two methods baz and bar not ending with a certain type - Integer in this example - are excluded from matching.

1
Andy Clement On

You can use getArgs(), the alternative would be to create multiple pieces of advice that delegate to the functionality you want to perform:

@Before("@annotation(authorized) && execution(* *())") // no string
public void authorize(JoinPoint joinPoint, Authorized authorized) {
  helper(joinPoint,authorized,null);
}

// 1 argument, which is the string
@Before("@annotation(authorized) && execution(* *(..)) && args(str)") 
public void authorize(JoinPoint joinPoint, Authorized authorized, String str) {
  helper(joinPoint,authorized,str);
}

Note I'm also including an execution pointcut element. It can be important to include that. Otherwise, if compiling with pure AspectJ your pointcut without it may match both the call and the execution joinpoint for your methods, running the advice twice.