java - 使用 AspectJ 验证初始调用递归函数的参数

标签 java aspectj

假设我有以下递归函数

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/

相关文章:

java - 当我在 Java 中只有一个对象的引用时,如何将一个对象分配给另一个对象?

java - 枚举和 AspectJ - getEnumConstants() 返回 null

java - 使用 Spring 和 AspectJ 拦截私有(private)方法

java - Intellij 中的调用树

java - 为什么我的编译器告诉我有不可编译的源代码?

java - 如何在运行时设置 logback 配置文件?

java - Joda DateTime 不支持 Google App Engine 中的属性类型

Java 字节码检测到由 ASPECTJ 识别的方法

java - 如何通过aspectJ切入点不匹配强制编译错误

java - 使用 @AspectJ 语法作为抽象类和具体类实现的方面不适用于 Spring AOP