AspectJ - 匹配具有通用参数的方法的切入点

AspectJ - pointcut to match a method that has generic parameters

我有一个通用方法,它接受任何类型作为其参数。
例如,我想要一个切入点,它匹配仅使用 'String' 类型作为其参数的方法的调用。最终要求是将执行建议的范围限制为 'String' 个参数。

这是我的通用 class 和方法:

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

Main class:我的应用使用布尔值和字符串作为参数调用该方法。

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
}

以下切入点对字符串和布尔参数均有效(实际上适用于任何类型)。但我想要一个切入点,仅在参数为 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(){}

以下对我不起作用:

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

我想知道是否可以在这里实现我想要实现的目标。我想用方法 return 类型做同样的事情。

您不能使用 AspectJ 或任何其他字节码操作库来做到这一点,因为泛型类型信息实际上已从编译的字节码中删除(从 Java 9 开始),因此您的泛型方法变为 public Object execute(Object s),因为类型参数 T 是无界的。有关详细信息,请参阅 Java 文档中的 Type Erasure

虽然原始方法签名以元数据的形式保留,编译器可以在针对泛型代码进行编译时检查是否遵守类型边界,但这不会以任何方式帮助您确定泛型类型参数class 的一个实例被实例化了,因为该信息根本不存在。

其他帖子提到的 Java 擦除是真的。

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.

您可以找到更多 here

但是,您可以执行以下操作:

  1. 捕获 Param.
  2. 的所有 execute 方法执行
  3. 使用 instanceof.
  4. 按参数类型过滤您对 String 参数的要求

请记住,需要加号 (+) 来表示通用。

这是一个例子,

@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");
            }
        }
    }
}