假设我有以下递归函数
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");
}
}
}
您有什么建议/推荐的方法来实现这一目标吗?
最佳答案
首先,您自己的解决方案无法工作,因为它包含语法错误: !withincode(call(int MyClass.foo(int)))
无法编译,因为 withincode()
code> 不采用切入点参数,仅采用签名。所以它实际上应该是: !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
正如您所看到的,在直接和间接递归情况下,我的测试条件都会记录初始值 0 和 10 的错误。现在,如果我们在 before()
建议中切换到 initialFactorialCall2(i)
,间接情况的日志将更改为:
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!
的错误 react ,其中还记录了 factorial_indirect(10)
内部调用的异常。这显然是错误的,因此您需要改用 cflowbelow()
解决方案。
关于java - 使用 AspectJ 验证初始调用递归函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36722344/