假设我有以下递归函数
public class MyClass{
public int foo(int arg){
...
}
}
如果arg的初始值为10,那么我想在一个方面抛出一个异常(之后它可以接受)。我是AspectJ的新手,但想出了以下似乎无法正常工作的内容。
public aspect CheckBounds{
pointcut initialCall(int x):
call(int MyClass.foo(int))
&& !cflow(call(int MyClass.foo(int)))
&& args(x);
before(int x) : initialCall(x){
if(x == 10){
throw new IllegalArgumentException("x must not be 10");
}
}
}
您有任何建议/推荐的方法来实现这一目标吗?
答案 0 :(得分:1)
首先,您自己的解决方案无法正常工作,因为它包含语法错误:!withincode(call(int MyClass.foo(int)))
无法编译,因为withincode()
不接受切入点参数,只接受签名。所以它应该是:!withincode(int MyClass.foo(int))
。
其次,我认为您真正想要的是与您的初始解决方案类似(但不完全相同),因为您自己的答案中的解决方案仅适用于直接递归,而不适用于间接递归。这是一个例子:
驱动程序应用程序:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
System.out.println("Directly recursive factorials:");
for (int i = 0; i < 12; i++)
System.out.printf("%2d! = %10d%n", i, application.factorial(i));
System.out.println("\nIndirectly recursive factorials:");
for (int i = 0; i < 12; i++)
System.out.printf("%2d! = %10d%n", i, application.factorial_indirect(i));
}
public int factorial(int i) {
return i > 1 ? i * factorial(i - 1) : 1;
}
public int factorial_indirect(int i) {
return helper(i);
}
public int helper(int i) {
return i > 1 ? i * factorial_indirect(i - 1) : 1;
}
}
如您所见,factorial(int)
通过直接递归计算阶乘,而factorial_indirect(int)
通过间接递归计算,因为它调用helper(int)
,而cflowbelow()
又调用原始方法。我将提出一个适用于这两种情况的方面,仅阻止初始调用,不直接或间接递归调用。
<强>方面:强>
您问题的原始切入点几乎是正确的,它应该使用cflow()
代替package de.scrum_master.aspect;
import de.scrum_master.app.Application;
public aspect CheckBounds {
pointcut factorialCall() :
call(int Application.factorial*(int));
pointcut initialFactorialCall(int i) :
factorialCall() &&
!cflowbelow(factorialCall()) &&
args(i);
pointcut initialFactorialCall2(int i) :
factorialCall() &&
!withincode(int Application.factorial*(int)) &&
args(i);
before(int i) : initialFactorialCall(i) {
if (i < 1 || i == 10) {
System.out.println(new IllegalArgumentException("x must be >=1 and != 10"));
}
}
}
。
请注意,我并没有真正抛出异常,只是为了演示目的而将它们记录下来,以免中断程序流程。
Directly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! = 3628800
11! = 39916800
Indirectly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! = 3628800
11! = 39916800
控制台日志:
initialFactorialCall2(i)
正如您所看到的,我的测试条件在直接和间接递归情况下记录初始值0和10的错误。现在,如果我们在before()
建议中切换到Indirectly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! = 3628800
java.lang.IllegalArgumentException: x must be >=1 and != 10
11! = 39916800
,则间接案例的日志将更改为:
11!
请注意factorial_indirect(10)
的错误反应,其中还记录了cflowbelow()
内部调用的异常。这显然是错误的,因此您希望改为使用payx()
解决方案。
答案 1 :(得分:0)
事实证明我使用了错误的切入点。我的目的是确保foo()的调用不是在foo中完成的(只是直接调用)。关于改变&#c; cflow&#39;来自内部代码&#39;该建议现在按预期运作:
public aspect CheckBounds{
pointcut initialCall(int x):
call(int MyClass.foo(int))
&& !withincode(int MyClass.foo(int))
&& args(x);
before(int x) : initialCall(x){
if(x == 10){
throw new IllegalArgumentException("x must not be 10");
}
}
}