Reputation: 17903
Lets say I have a method classA.methodA()
and its calling classB.methodB()
. Now, inside the classB.methodB()
, is there any way to know that its being called by classA
(without passing any explicit info). I know this info is there in Java Runtime. My question is how to get the the class name of callee method ?
to make it more obvious
ClassA{
methodA(){
ClassB b = new ClassB();
b.methodB();
}
}
ClassB{
methodB(){
// Code to find that its being called by ClassA
}
}
Upvotes: 4
Views: 7196
Reputation: 1684
Warning (Potentially) Hotspot only and is not public API
Try sun.reflect.Reflection.getCallerClass(int numFramesToSkip); note that this API has been deprecated.
I last used this to do some evil ASM magics to re-write the log4j call on a third party library so that we could correct its dumb logging and get it to do log4j categories properly, no I will not mention what third party library as they are a company that is very touchy about reverse engineering.
Notes:
I can now hear the mob screaming about the none-public API example
Upvotes: 0
Reputation: 28316
You can use Thread.currentThread().getStackTrace()
to get a stack trace, then iterate through it to find which method is above yours in the stack.
For example (totally made up stack here), you might have a stack like this:
main()
|- Foo()
|- Bar()
|- MyFunction()
|- getStackTrace()
|- captureJavaThreadStack(...)
Starting from the bottom, you iterate up until you hit the getStackTrace()
method. You then know that the calling method is two methods up from that position, i.e. MyFunction()
called getStackTrace()
, which means that MyFunction()
will always be above getStackTrace()
, and whatever called MyFunction()
will be above it.
You can use the getClassName()
method on the StackTraceElement
class to pull out the class name from the selected stack trace element.
Docs:
http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#getStackTrace%28%29
http://docs.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html
Upvotes: 8
Reputation: 8707
Starting Java 5.0, you can use Thread.currentThread().getStackTrace()
to get a current stack trace.
To get caller class (and method) of current method:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
int i = 1;
while (MyClass.class.getName().equals(stackTraceElements[i].getClassName())) { i++; }
int lineNumber = stackTraceElements[i].getLineNumber();
String className = stackTraceElements[i].getClassName();
String methodName = stackTraceElements[i].getMethodName();
Please note! There is some kind of warning in javadocs regarding this method:
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this thread is permitted to return a zero-length array from this method.
I have not any trouble with this piece of code on Sun (Oracle) JVM and Mac OS X JVM. Please test your code carefully to be sure it works like you expect, especially if you use any other JVM.
Upvotes: 3
Reputation: 75376
Only by inspecting the call stack which is not directly supported, but you can get an almost reliable answer by looking at either a stack trace (just create a RuntimeException) or a ThreadDump (for Java 6).
If you want to have your code behave differently based on who called it, you are most definitively heading in the wrong direction. Pass down the needed information explictly or use sub-classes to provide different behavior.
Upvotes: 3
Reputation: 21419
You can use the stack trace to do that. Inside the called method, do the following
Throwable t = new Throwable();
StackTraceElement[] stackTraceElements = t.getStackTrace();
String calleeMethod = stackTraceElements [0].getMethodName();
String callerMethodName = stackTraceElements [1].getMethodName();
String callerClassName = stackTraceElements [1].getClassName();
System.out.println("Caller :" + callerClassName + "." + callerMethodName);
Upvotes: 2
Reputation: 220877
A not very reliable way is to look into
Thread.currentThread().getStackTrace()
It's not reliable, because there are various reasons why the callee is not what you'd expect, e.g. instrumentation, reflection utilities, etc. But maybe that's good enough for your use-case?
Upvotes: 1