Обеспечение того, чтобы стек вызовов одного метода всегда включал другой метод в Java
У меня есть проблема проектирования в общей утилите, которую мы используем в нашем Java-проекте, где я хочу убедиться, что все вызывающие стороны определенного метода A обернуты другим методом B. Общая форма этого кода, как я его написал сегодня, такова::
x.B(new Runnable() {
y.A();
});
Runnable, который выполняется B, может иметь произвольный код и может вызывать A несколько раз, поэтому я не могу избавиться от runnable в этом коде, добавив вызов A непосредственно в B. Кроме того, A является сторонним код, поэтому мы не можем изменить его. Вполне возможно, что runnable мог бы снова вызвать B с другим вложенным вызовом A, но сегодня этого не происходит, так что я пока игнорирую этот случай.
Я вижу несколько вариантов:
- декларировать
A() throws BlahException
и сделайте так, чтобы B был единственным ловцом этого исключения. Это ужасно, потому что нет никаких исключений, которые действительно должны быть выброшены, но это хорошо, потому что компилятор обеспечил бы для меня иерархию вызовов. - Напишите какой-нибудь инструмент статического анализа, чтобы обеспечить это правило для меня. Я еще мало исследовал этот случай, так как он звучит как большая работа, чем что-либо еще (но, может быть, существует уже существующий инструмент, который может это сделать?).
- Добавьте к "началу 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();
}
}