AspectJ - pointcut to match a method that has generic parameters

丶灬走出姿态 提交于 2020-02-24 06:22:20

问题


I have a generic method that accepts any type as its parameter.
For example, I would like a pointcut that matches the calls made to the method only with 'String' type as its parameter. Ultimately the requirement is to limit the scope which the advices get executed for to 'String' parameters.

Here is my generic class and method:

public class Param<T> {
    public T execute(T s){
        return s;
    }
}

Main class: My app makes calls to the method with both Boolean and String as parameters.

public static void main(String[] args) {
    Param<String> sp = new Param<String>();
    String rs = sp.execute("myString"); //want a joint point

    Param<Boolean> bp = new Param<Boolean>();
    Boolean rb = bp.execute(true); //dont want a joint point
}

Below pointcuts are valid for both String and Boolean parameters (work for any type actually). But I would like a pointcut to intercept method calls only when parameter is of type String.

@Pointcut("call(* com.amazon.auiqa.aspectj.generics.Param.execute(**))")
void param(){}

@Pointcut("execution(Object com.amazon.auiqa.aspectj.generics.Param.execute(Object))")
void param(){}

Below ones did not work for me:

 @Pointcut("execution(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")
 @Pointcut("call(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")

I was wondering if it is possible to achieve what I want to achieve here. I would like to do the same thing with method return types.


回答1:


You cannot do that with AspectJ, nor with any other bytecode manipulation library as generic type information is actually erased from the compiled bytecode (as of Java 9), so your generic method becomes public Object execute(Object s), since the type argument T is unbounded. See Type Erasure at the Java Documentation for further info.

While the original method signature is preserved in the form of metadata, the compiler can check whether type bounds are respected or not while compiling against generic code, but this will not help you in any way to determine what generic type argument an instance of that class was instantiated with, because that information is simply not present at all.




回答2:


It's true what the other posting mentioned about Java erasure.

AspectJ 5 does not allow the use of type variables in pointcut expressions and type patterns. Instead, members that use type parameters as part of their signature are matched by their erasure. Java 5 defines the rules for determing the erasure of a type as follows.

Let |T| represent the erasure of some type T. Then:

  • The erasure of a parameterized type T<T1,...,Tn> is |T|. For example, the erasure of List<String> is List.

  • The erasure of a nested type T.C is |T|.C. For example, the erasure of the nested type Foo<T>.Bar is Foo.Bar.

  • The erasure of an array type T[] is |T|[]. For example, the erasure of List<String>[] is List[].

  • The erasure of a type variable is its leftmost bound. For example, the erasure of a type variable P is Object, and the erasure of a type variable N extends Number is Number.

You can find more here.

However, you can do the following:

  1. Capture all execute method executions of Param.
  2. Filter your requirements of String arguments by the type of argument by using instanceof.

Remember, a plus sign (+) is needed to indicate a generic.

Here is an example,

@Component
@Aspect
public class ParamAspect {

    @Pointcut("execution(public * com.amazon.auiqa.aspectj.generics.Param+.execute(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void intercept(JoinPoint jp) {
        System.out.println(
                "Entering class: " + jp.getSignature().getDeclaringTypeName() +
                        " - before method: " + jp.getSignature().getName());

        // check for argument type of String 
        Object[] args = jp.getArgs();
        if (args.length == 1) {
            if (args[0] instanceof String) {
                System.out.println("1. parameter type is string");
            } else {
                System.out.println("2. parameter type is not string");
            }
        }
    }
}


来源:https://stackoverflow.com/questions/47264428/aspectj-pointcut-to-match-a-method-that-has-generic-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!