Как уже упоминали другие, использование трассировки стека является одним из способов реализовать функциональность, которую вы ищете.Как правило, если нужно «заблокировать» вызывающих из метода public
, это может быть признаком плохого дизайна.Как правило, используйте модификаторы доступа, которые максимально ограничивают область действия.Однако создание метода package-private или protected
не всегда возможно.Иногда может потребоваться сгруппировать некоторые классы в отдельный пакет.В этом случае доступ по умолчанию (частный пакет) слишком ограничен, и для подкласса это обычно не имеет смысла, поэтому protected
также не помогает.
Если желательно ограничить вызов определенными классами,Вы можете создать метод, подобный следующему:
public static void checkPermission(Class... expectedCallerClasses) {
StackTraceElement callerTrace = Thread.currentThread().getStackTrace()[3];
for (Class expectedClass : expectedCallerClasses) {
if (callerTrace.getClassName().equals(expectedClass.getName())) {
return;
}
}
throw new RuntimeException("Bad caller.");
}
Использовать его очень просто: просто укажите, какие классы могут вызывать метод.Например,
public void stop() {
checkPermission(ShutdownHandler.class);
running = false;
}
Итак, если метод stop
вызывается классом , отличным от ShutdownHandler
, checkPermission
выдаст IllegalStateException
.
Вы можете задаться вопросом, почему checkPermission
жестко задан для использования четвертого элемента трассировки стека.Это потому, что Thread#getStackTrace()
делает последний вызванный метод первым элементом.Таким образом,
getStackTrace()[0]
будет вызовом самого getStackTrace
. getStackTrace()[1]
будет вызовом checkPermission
. getStackTrace()[2]
будет вызовом stop
. getStackTrace()[3]
будет методом, который вызвал stop
.Это то, что нас интересует.
Вы упомянули, что хотите, чтобы методы вызывались из определенного метода и , но checkPermission
проверяет только имена классов.Добавление функциональности для проверки имен методов требует только нескольких модификаций, поэтому я собираюсь оставить это как упражнение.