Thursday, March 23, 2017

Getting a caller's class and method names in Java

Sometimes a method needs to know which class and method called this method. For example, it can be helpful in a logger. A logger can print information about caller like this:

[SomeClass, main]: main() started
[AnotherClass, method]: hello
[SomeClass, main]: main() finished
There 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() finished

There 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()`: If you run it, you're going to see the following:

[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.