As others have mentioned, using the stack trace is one way to implement the functionality that you are looking for. Generally, if one needs to "block" callers from a public
method, it could be a sign of poor design. As a rule of thumb, use access modifiers that restrict the scope as much as possible. However, making a method package-private or protected
is not always an option. Sometimes, one may want to group some classes in a separate package. In that case, the default (package-private) access is too restrictive, and it usually does not make sense to subclass, so protected
is not helpful either.
If restricting calling to certain classes is desired, you can create a method like:
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.");
}
Using it is very simple: just specify what class(es) can call the method. For example,
public void stop() {
checkPermission(ShutdownHandler.class);
running = false;
}
So, if the stop
method gets called by a class other than ShutdownHandler
, checkPermission
will throw an IllegalStateException
.
You may wonder why checkPermission
is hard-coded to use the fourth element of the stack trace. This is because Thread#getStackTrace()
makes the most recently called method the first element. So,
getStackTrace()[0]
would be the call to getStackTrace
itself.
getStackTrace()[1]
would be the call to checkPermission
.
getStackTrace()[2]
would be the call to stop
.
getStackTrace()[3]
would be the method that called stop
. This is what we are interested in.
You mentioned that you want methods to be called from a specific class and method, but checkPermission
only checks for class names. Adding the functionality to check for method names requires only a few modifications, so I'm going to leave that as an exercise.