Обеспечение того, чтобы стек вызовов одного метода всегда включал другой метод в Java

У меня есть проблема проектирования в общей утилите, которую мы используем в нашем Java-проекте, где я хочу убедиться, что все вызывающие стороны определенного метода A обернуты другим методом B. Общая форма этого кода, как я его написал сегодня, такова::

x.B(new Runnable() {
    y.A();
});

Runnable, который выполняется B, может иметь произвольный код и может вызывать A несколько раз, поэтому я не могу избавиться от runnable в этом коде, добавив вызов A непосредственно в B. Кроме того, A является сторонним код, поэтому мы не можем изменить его. Вполне возможно, что runnable мог бы снова вызвать B с другим вложенным вызовом A, но сегодня этого не происходит, так что я пока игнорирую этот случай.

Я вижу несколько вариантов:

  1. декларировать A() throws BlahException и сделайте так, чтобы B был единственным ловцом этого исключения. Это ужасно, потому что нет никаких исключений, которые действительно должны быть выброшены, но это хорошо, потому что компилятор обеспечил бы для меня иерархию вызовов.
  2. Напишите какой-нибудь инструмент статического анализа, чтобы обеспечить это правило для меня. Я еще мало исследовал этот случай, так как он звучит как большая работа, чем что-либо еще (но, может быть, существует уже существующий инструмент, который может это сделать?).
  3. Добавьте к "началу A" утверждение (на самом деле, этот код должен был бы жить в пользовательской версии Runnble, поскольку я не могу изменить A напрямую), что мы выполняем внутри вызова B. Это может либо использовать некоторые дополнительное состояние потока / локального объекта или прохождение самого стека вызовов, оба из которых уродливы.

Есть ли другие варианты, которые я не рассмотрел?

1 ответ

Рассматривали ли вы использование AspectJ или других инструментов аспектно-ориентированного программирования (AOP)? Тогда вы могли бы перехватить каждый вызов метода Aпроверьте метод B в стеке трассировки. Если его там нет, вы можете выдать исключение, предотвращающее выполнение 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();
    }

}
Другие вопросы по тегам