Can I get a reference to the calling class in a static method?

I have a static Java method where I want to know who is calling it. Is it possible to get this information in Java?

+4
source share
4 answers

It is possible, but it is expensive and somewhat remotely similar to a normal case, it is a very bad idea. You almost certainly want to approach a problem that you solve differently. (And if you post a new question about the problem that you are solving, I bet that someone will help you with this! :-))

Two ways to create a stack trace:

1) Via Throwable

... by throwing and catching an exception, and then using Exception#getStackTrace

 try { throw new Exception(); } catch (Exception e) { // Get the stack trace StackTraceElement[] entries = e.getStackTrace(); } 

... or as lscoughlin points out (please vote for it), more directly , just new Throwable :

 StackTraceElement[] entries = new Throwable().getStackTrace(); 

Each of these StackTraceElement s then provides you with information about this point in the stack trace. In your case, you probably want to look at the StackTraceElement getClassName . If you really need a reference to the object of the calling class, you can pass this string to the class name in Class.forName , but warn that in complex environments, you can get another instance (or not an instance) of the class if the calling user did interesting things with the loaders classes.

2) Using Thread#getStackTrace

MRalwasser cautiously points out below that in Java 5 or higher (and I assume you are probably using Java 5 or higher), you can use Thread.currentThread().getStackTrace() instead of actually throwing an exception. I don't know if it will be easier or not (since getting a stack trace can be so expensive that it throws an exception), but it is definitely cleaner.

In a quick and dirty test, counter-intuitively actually throwing an exception seemed faster than through Thread (and pretty much the same as new Throwable ), but the vagaries of naive profiling of JVM applications are well documented, your mileage may vary ...

But then again, not only does the stack trace be an expensive process, but using caller information that the caller did not pass to you through the method signature is a serious design problem in anything other than (say) a debugger or an error used only for development . The main answer here should be: do not do this unless you have a really good reason.

+11
source

Sorry to resurrect this thread, but the mechanism that I have used for centuries to do the same without the cumbersome use of stacktraces.


 class ClassloaderUtil { public static Class getCallingClass() { return CallerResolver.getCallerClass(2); } private static final class CallerResolver extends SecurityManager { private static final CallerResolver CALLER_RESOLVER = new CallerResolver(); private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned protected Class[] getClassContext() { return super.getClassContext(); } /* * Indexes into the current method call context with a given * offset. */ private static Class getCallerClass(int callerOffset) { return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET + callerOffset]; } private static int getContextSize() { return CALLER_RESOLVER.getClassContext().length - CALL_CONTEXT_OFFSET; } } } 

Then using this, simply:

 public class ClassloaderUtilTest { @Test public void test() { Class c = ClassloaderUtil.getCallingClass(); Assert.assertNotNull(c); c = foo(); Assert.assertNotNull(c); } private Class foo() { return ClassloaderUtil.getCallingClass(); } } 

The first class will be some junit environment class, while foo () will return ClassloaderUtilTest as a class.

This is definitely not perfect. However, it has its occasional use. I agree with people who have already answered this question with the fact that it is incredibly expensive.

+5
source

It is simpler and slightly safer just for the new, as in:

  Throwable t = new Throwable(); StackTraceElement directCaller = t.getStackTrace()[1]; 

But, generally speaking, this is still a terrible idea, and it is expensive.

+4
source

Check out this solution using ASM for a similar previous question . Unfortunately my own answer was not quite that good. But I agree with some of the bad idea.

+1
source

All Articles