How to get the name of the calling class in Java?

Viewed 25529

I would like some help on this matter,

Example:

public class A {
    private void foo() {
        //Who invoked me?
    }
}

public class B extends A {}

public class C extends A {}

public class D {
     C.foo();
}

This is basically the scenario. My question is how can method foo() know who is calling it?

EDIT: Basically I am trying to do a database Layer, and in class A I will create a method that will generate SQL statements. Such statements are dynamically generated by getting the values of all the public properties of the calling class.

13 Answers

if you using slf4j as your application logging system. you can using:

Class<?> source = org.slf4j.helpers.Util.getCallingClass();

I think it's faster than new Exception().getStackTrace(), since getStackTrace() alaways doing clone stacktrace.

I would use StackWalker

private static Class<?> getCallingClass(int skip) {
    StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
    Optional<? extends Class<?>> caller = walker.walk(frames ->
            frames.skip(skip).findFirst().map(StackWalker.StackFrame::getDeclaringClass)
    );
    return caller.get();
}

If you need the class of the calling method use skip=1.

With the following code, you obtain the first class which generated the stack of calls:

    public String getInvonkingClassName(boolean fullClassNameNeeded){

        StackTraceElement[] stack = new Exception().getStackTrace();
        String className = stack[stack.length-1].getClassName();


        if(!fullClassNameNeeded){
            int idx = className.lastIndexOf('.');
            className = className.substring(idx+1);
        }

        return className;
    }

Boolean argument is used to get the full name including package name, or just class name.

StackFrame

The state of one method invocation on a thread's call stack. As a thread executes, stack frames are pushed and popped from its call stack as methods are invoked and then return. A StackFrame mirrors one such frame from a target VM at some point in its thread's execution.

JVM Stack: From Frame 1 get Frame 2 details
    |                                           |
    |                                           |
    | Class2.function1()             [FRAME 1]  |
    |       executing the instructions          |
    |-------------------------------------------|
    |Class1.method1()                [FRAME 2]  |
    | called for execution Class2.function1()   |
    |-------------------------------------------|

Throwable::getStackTrace and Thread::getStackTrace return an array of StackTraceElement objects, which contain the class name and method name of each stack-trace element.

Throwable::getStackTrace contains the Stack with frames as Frame1(Top Frame) Current method, Frame2 calls Frame1 method for execution.

StackTraceElement[] stackTraceElements = (new Throwable()).getStackTrace();
// Frame1:Log4J.log(), Frame2:CallerClass

Thread::getStackTrace contains the stack with Frames:
Frame1:Thread.getStackTrace(), Frame2:Current Method, Frame3:Caller Method

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); // 

sun.misc.SharedSecrets.getJavaLangAccess()

sun.misc.JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess();
StackTraceElement frame = javaLangAccess.getStackTraceElement((new Throwable()), callerFrame-1 ); // Frame0:Log4J.log(), Frame1:CallerClass
System.out.format("SUN - Clazz:%s, Method:%s, Line:%d\n", frame.getClassName(), frame.getMethodName(), frame.getLineNumber());

Throwable throwable = new Throwable();
int depth = javaLangAccess.getStackTraceDepth(new Throwable());
System.out.println("\tsun.misc.SharedSecrets : "+javaLangAccess.getClass() + " - StackTraceDepth : "+ depth);
for (int i = 0; i < depth; i++) {
    StackTraceElement frame = javaLangAccess.getStackTraceElement(throwable, i);
    System.out.format("Clazz:%s, Method:%s, Line:%d\n", frame.getClassName(), frame.getMethodName(), frame.getLineNumber());
}

JDK-internal sun.reflect.Reflection::getCallerClass method. It is deprecated, removed in Java9 JDK-8021946

Any way by using Reflection API we can't find the Line Number of Function which it get called.

System.out.println("Reflection - Called from Clazz : "+ Reflection.getCallerClass( callerFrame )); // Frame1:Log4J.log(), Frame2:CallerClass

Example:

    static boolean log = false;

    public static void log(String msg) {
        int callerFrame = 2; // Frames [Log4J.log(), CallerClass.methodCall()] 
        StackTraceElement callerFrameStack = null;

        StackTraceElement[] stackTraceElements = (new Throwable()).getStackTrace(); // Frame1:Log4J.log(), Frame2:CallerClass
        //StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();// Frame1:Thread.getStackTrace(), Frame2:Log4J.log(), Frame3:CallerClass
        int callerMethodFrameDepth = callerFrame; // Caller Class Frame = Throwable:2(callerFrame), Thread.currentThread:2(callerFrame+1)
        for (int i = 0; i < stackTraceElements.length; i++) {
            StackTraceElement threadFrame = stackTraceElements[i];
            if (i+1 == callerMethodFrameDepth) {
                callerFrameStack = threadFrame;
                System.out.format("Called form Clazz:%s, Method:%s, Line:%d\n", threadFrame.getClassName(), threadFrame.getMethodName(), threadFrame.getLineNumber());
            }
        }

        System.out.println(msg);
        if (!log){
            Logger logger = Logger.getLogger(callerFrameStack.getClass());
            logger.info(msg);
        }
    }

    public static void main(String[] args) {
        Log4J.log("Log4J, main");
        Clazz1.mc1();
        Clazz21.mc12();
        Clazz21.mc11();
        Clazz21.mc21();
    }
}

class Clazz1 {
    public static void mc1() {
        Log4J.log("Clazz1 - mc1");
    }
}
class Clazz11 {
    public static void mc11() {
        Log4J.log("Clazz11 - mc11");
    }
    public static void mc12() {
        Log4J.log("Clazz11 - mc12");
        Clazz1.mc1();
    }
}
class Clazz21 extends Clazz11 {
    public static void mc21() {
        Log4J.log("Clazz21 - mc21");
    }
}

For Java 9 use Stack Walking API

I'm just answering this because for some reason the above answers started referring to exception handling - the original question had nothing to do with exceptions.

So, instead of trying to determine the caller of the method in question, and specifically to give more information dealing with the creation of a base class that generates SQL statements for its derived classes, here is an OO solution...

  1. Make the base class abstract and include abstract methods that return the data it needs to build a sql statement.

  2. This would include methods like...

    getColumnList() getFromTable() getJoinedTables() getFilterColumns()

  3. The base class then does not care who is calling it because it is going to call up to the derived class for all the details it needs to create the SQL statement. The base class knows the derived classes are going to provide the implementation of these methods because they are abstract.

Another way to implement this would be to have a SQLGenerator class that receives an interface with the methods described above and operates on the instances passed to it via those methods. For this, you would want to have the abstract methods described above moved into the interface, which all of your SQL related classes would implement.

List item

Maybe an answer is

public class CallerMain {

  public void foo(){
    System.out.println("CallerMain - foo");
    System.out.println(this.getClass()); //output- callerMain
  }
  public static void main(String[] args) {
    A a = new A();
    CallerMain cm = new CallerMain();
    cm.foo();
  }
}

class A{
  public void foo(){
    System.out.println("A - foo");
    System.out.println(this.getClass());//output- A
  }
}
Related