确保一个方法的调用堆栈始终包含Java中的另一个方法

Dan*_*Dan 5 java static-analysis call-hierarchy

我在我们的Java项目中使用的常见实用程序中存在设计问题,我希望确保特定方法A的所有调用者都被另一个方法B包装.我今天编写的这段代码的一般形式是:

x.B(new Runnable() {
    y.A();
});
Run Code Online (Sandbox Code Playgroud)

B执行的runnable可以有任意代码,并且可以多次调用A,所以我无法通过将A中的调用直接添加到B中来摆脱此代码中的runnable.此外,A是第三方代码,所以我们不能修改它.runnable可能会再次使用另一个嵌套的A调用来调用B,但是今天这种情况从未发生过,所以我现在可以忽略这种情况.

我看到几个选项:

  1. 声明A() throws BlahException并使其成为B是该异常的唯一捕手.这很难看,因为没有任何异常应该被抛出,但它很好,因为编译器会为我确保调用层次结构.
  2. 写一些静态分析工具来确保这个规则对我而言.我还没有调查过这个案例,因为它听起来比其他任何东西都要多(但也许有一个预先存在的工具可以做到这一点?).
  3. 添加一个断言到"A的开头"(实际上,这个代码必须存在于Runnble的自定义版本,因为我无法直接修改A)我们在调用B的内部运行.这可以使用一些额外的线程/对象本地状态或遍历调用堆栈本身,这两者都是丑陋的.

还有其他我没考虑过的选择吗?

Ser*_*nin 2

您是否考虑过使用AspectJ或其他一些面向方面的编程(AOP)工具?然后您可以拦截 method 的每个调用A,检查B堆栈跟踪中的 method 。如果它不存在,您可以抛出异常以阻止执行A,或将错误写入日志,或执行任何您喜欢的操作。像这样的东西:

@Aspect
public class CheckInsideMethodBAspect {

    @Around("execution(* com.example.AClass.A(..))")
    public void checkNestedMethod(ProceedingJoinPoint joinPoint) {

        // checking for method B in the call stack
        boolean isInsideB = false;
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element: stackTraceElements) {
            if (element.getClassName().equals("ClassB") && element.getMethodName().equals("B")) {
                isInsideB = true;
                break;
            }
        }

        // if not inside B, throwing exception
        if (!isInsideB) {
            throw new NotInsideBException();
        }

        // if inside B, then proceeding with method A execution
        joinPoint.proceed();
    }

}
Run Code Online (Sandbox Code Playgroud)