[SomeClass, main]: main() started [AnotherClass, method]: hello [SomeClass, main]: main() finishedThere is a couple of ways how we can get information about caller in Java. First of all, Java has an internal `sun.reflect.Reflection.getCallerClass(int)` method, but it might not be good to use classes in `sun` package because they can be changed/removed/updated in any new Java release. Another thing is that you'll need a permission to access `sun` package if you run your application with a security manager (is anybody doing this?). Let's try to use public API.
First, we can use SecurityManager class. It has a protected getClassContext() method which returns the current execution stack as an array of classes. Here is an example how it can be used in a simple logger: If you run it, it's going to print the following:
[App]: main() started [App]: hello [App]: main() finishedThere are a couple of disadvantages of this approach. First, it doesn't let you get a method name. Then, it requires a runtime permission "createSecurityManager" if a security manager is enabled.
Another option is to use `Thread.currentThread().getStackTrace()`:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class App { | |
public static void main(String[] args) throws Throwable { | |
Logger.INSTANCE.log("started"); | |
Logger.INSTANCE.log("hello"); | |
foo(); | |
Logger.INSTANCE.log("finished"); | |
} | |
private static void foo() { | |
Logger.INSTANCE.log("hello from foo"); | |
} | |
private static class Logger extends SecurityManager { | |
public static final Logger INSTANCE = new Logger(); | |
public void log(String message) { | |
StackTraceElement ste = Thread.currentThread().getStackTrace()[2]; | |
String callerClass = ste.getClassName(); | |
String callerMethod = ste.getMethodName(); | |
System.out.printf("[%s, %s]: %s%n", callerClass, callerMethod, message); | |
} | |
} | |
} |
[App, main]: started [App, main]: hello [App, foo]: hello from foo [App, main]: finished
Now we have both class and method names, and this approach doesn't require any security permission.