AspectJ 参数化类型不支持目标切入点
AspectJ parameterized types not support for target pointcuts
我想创建一个 class 指向列表接口中方法的切入点。在我将目标(列表)添加到我的建议之前,这似乎有效。我想在添加之前和之后查看列表的元素(例如)查看发生了什么变化,但我似乎无法像传递对象那样传递我的列表。到目前为止,这是我所拥有的,这不会 运行 有目标(列表)但 运行 没有它:
pointcut addPointCut() : call(boolean List.add(..));
before(List<Integer> list) : addPointCut() && target(list) {
System.out.println("testing");
for(Object i : list) {
System.out.println(i);
}
}
不支持在类型 target(...)
或 this(...)
切入点中使用泛型,编译将失败并出现此错误:parameterized types not supported for this and target pointcuts (erasure limitation)
。从列表中删除类型参数,它应该按预期工作。
Nándor 的回答是正确的,因为他描述了您看到的编译器错误。我想更进一步解释 为什么 你会收到这个错误:
首先,问题与 AspectJ 没有直接关系,而是与 Java 如何实现泛型有关。在继续阅读之前,请让自己熟悉一种叫做 type erasure 的现象。
好吧,因为类型擦除是 JVM 的现实,因为 target()
和 this()
是在运行时而不是编译时解析的 - 你可以从 getTarget()
和 getThis()
是 JoinPoint
而不是 JoinPoint.StaticPart
的方法 - 你想做的事情无法工作,因此会导致 AspectJ 编译器错误。您唯一可以做的就是使用 instanceof
来动态确定添加到目标列表中的内容。最优雅的方法是使用 if()
切入点表达式。
下面是一些示例代码:
驱动申请:
为了让事情变得更有趣,我们使用了两种类型的列表和两种类型的 add(..)
调用。目标应该是只拦截要添加到相应列表中的整数,无论 add(..)
方法具有哪个签名。
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(11);
integers.add(0, 22);
integers.add(33);
List<String> strings = new ArrayList<>();
strings.add("foo");
strings.add(0, "bar");
strings.add("zot");
}
}
看点:
package de.scrum_master.aspect;
import java.util.List;
@SuppressWarnings({"rawtypes", "unchecked"})
public aspect GenericsAspect {
pointcut addPointCut(List list, Object newElement) :
!within(GenericsAspect) && // avoid stack overflow due to recursion
call(* List.add(..)) && // intercept all calls to List.add
args(.., newElement) && // capture last method parameter
if(newElement instanceof Integer) && // only capture added int/Integer elements
target(list); // target is a List
before(List list, Object newElement) :
addPointCut(list, newElement)
{
System.out.println(thisJoinPoint + " -> new element = " + newElement);
for(Object i : list)
System.out.println(" " + i);
// Type erasure in action:
// During runtime there is no such thing as List<Integer>, only a raw List.
// Thus, we can easily add a String to a list declared as List<Integer>.
list.add("#" + newElement + "#");
}
}
控制台日志:
call(boolean java.util.List.add(Object)) -> new element = 11
call(void java.util.List.add(int, Object)) -> new element = 22
#11#
11
call(boolean java.util.List.add(Object)) -> new element = 33
22
#11#
11
#22#
还有问题吗?
我想创建一个 class 指向列表接口中方法的切入点。在我将目标(列表)添加到我的建议之前,这似乎有效。我想在添加之前和之后查看列表的元素(例如)查看发生了什么变化,但我似乎无法像传递对象那样传递我的列表。到目前为止,这是我所拥有的,这不会 运行 有目标(列表)但 运行 没有它:
pointcut addPointCut() : call(boolean List.add(..));
before(List<Integer> list) : addPointCut() && target(list) {
System.out.println("testing");
for(Object i : list) {
System.out.println(i);
}
}
不支持在类型 target(...)
或 this(...)
切入点中使用泛型,编译将失败并出现此错误:parameterized types not supported for this and target pointcuts (erasure limitation)
。从列表中删除类型参数,它应该按预期工作。
Nándor 的回答是正确的,因为他描述了您看到的编译器错误。我想更进一步解释 为什么 你会收到这个错误:
首先,问题与 AspectJ 没有直接关系,而是与 Java 如何实现泛型有关。在继续阅读之前,请让自己熟悉一种叫做 type erasure 的现象。
好吧,因为类型擦除是 JVM 的现实,因为 target()
和 this()
是在运行时而不是编译时解析的 - 你可以从 getTarget()
和 getThis()
是 JoinPoint
而不是 JoinPoint.StaticPart
的方法 - 你想做的事情无法工作,因此会导致 AspectJ 编译器错误。您唯一可以做的就是使用 instanceof
来动态确定添加到目标列表中的内容。最优雅的方法是使用 if()
切入点表达式。
下面是一些示例代码:
驱动申请:
为了让事情变得更有趣,我们使用了两种类型的列表和两种类型的 add(..)
调用。目标应该是只拦截要添加到相应列表中的整数,无论 add(..)
方法具有哪个签名。
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(11);
integers.add(0, 22);
integers.add(33);
List<String> strings = new ArrayList<>();
strings.add("foo");
strings.add(0, "bar");
strings.add("zot");
}
}
看点:
package de.scrum_master.aspect;
import java.util.List;
@SuppressWarnings({"rawtypes", "unchecked"})
public aspect GenericsAspect {
pointcut addPointCut(List list, Object newElement) :
!within(GenericsAspect) && // avoid stack overflow due to recursion
call(* List.add(..)) && // intercept all calls to List.add
args(.., newElement) && // capture last method parameter
if(newElement instanceof Integer) && // only capture added int/Integer elements
target(list); // target is a List
before(List list, Object newElement) :
addPointCut(list, newElement)
{
System.out.println(thisJoinPoint + " -> new element = " + newElement);
for(Object i : list)
System.out.println(" " + i);
// Type erasure in action:
// During runtime there is no such thing as List<Integer>, only a raw List.
// Thus, we can easily add a String to a list declared as List<Integer>.
list.add("#" + newElement + "#");
}
}
控制台日志:
call(boolean java.util.List.add(Object)) -> new element = 11
call(void java.util.List.add(int, Object)) -> new element = 22
#11#
11
call(boolean java.util.List.add(Object)) -> new element = 33
22
#11#
11
#22#
还有问题吗?