[java] How to get the caller class in Java

I want to get the caller class of the method, i.e.

class foo{

  bar();

}

In the method bar, I need to get the class name foo, and I found this method:

Class clazz = sun.reflect.Reflection.getCallerClass(1);

However, even though getCallerClass is public, when I try to call it Eclipse says:

Access restriction: The method getCallerClass() from the type Reflection is not accessible due to restriction on required library C:\Program Files\Java\jre7\lib\rt.jar

Are there any other choices?

This question is related to java

The answer is


This is the most efficient way to get just the callers class. Other approaches take an entire stack dump and only give you the class name.

However, this class in under sun.* which is really for internal use. This means that it may not work on other Java platforms or even other Java versions. You have to decide whether this is a problem or not.


i am using the following method to get the caller for a specific class from the stacktrace:

package test.log;

public class CallerClassTest {

    public static void main(final String[] args) {
        final Caller caller = new Caller(new Callee());
        caller.execute();
    }

    private static class Caller {

        private final Callee c;

        public Caller(final Callee c) {
            this.c = c;
        }

        void execute() {
            c.call();
        }
    }

    static class Callee {

        void call() {
            System.out.println(getCallerClassName(this.getClass()));
        }
    }

    /**
     * Searches the current threads stacktrace for the class that called the given class. Returns {@code null} if the
     * calling class could not be found.
     * 
     * @param clazz
     *            the class that has been called
     * 
     * @return the caller that called the class or {@code null}
     */
    public static String getCallerClassName(final Class<?> clazz) {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        final String className = clazz.getName();
        boolean classFound = false;
        for (int i = 1; i < stackTrace.length; i++) {
            final StackTraceElement element = stackTrace[i];
            final String callerClassName = element.getClassName();
            // check if class name is the requested class
            if (callerClassName.equals(className)) classFound = true;
            else if (classFound) return callerClassName;
        }
        return null;
    }

}

SecurityManager has a protected method getClassContext

By creating a utility class which extends SecurityManager, you can access this.

public class CallingClass extends SecurityManager {
    public static final CallingClass INSTANCE = new CallingClass();

    public Class[] getCallingClasses() {
        return getClassContext();
    }
}

Use CallingClass.INSTANCE.getCallingClasses() to retrieve the calling classes.

There is also a small library (disclaimer: mine) WhoCalled which exposes this information. It uses Reflection.getCallerClass when available, else falls back to SecurityManager.


To get caller/called class name use below code, it works fine for me.

String callerClassName = new Exception().getStackTrace()[1].getClassName();
String calleeClassName = new Exception().getStackTrace()[0].getClassName();

Find below a simple example illustrating how to get class and method names.

public static void main(String args[])
   {
      callMe();
   }

   void callMe()
   {
      try
      {
         throw new Exception("Who called me?");
      }
      catch( Exception e )
      {
         System.out.println( "I was called by " + 
                             e.getStackTrace()[1].getClassName() + 
                             "." +
                             e.getStackTrace()[1].getMethodName() + 
                             "()!" );
      }
   }

e has getClassName(), getFileName(), getLineNumber() and getMethodName()...


The error message the OP is encountering is just an Eclipse feature. If you are willing to tie your code to a specific maker (and even version) of the JVM, you can effectively use method sun.reflect.Reflection.getCallerClass(). You can then compile the code outside of Eclipse or configure it not to consider this diagnostic an error.

The worse Eclipse configuration is to disable all occurrences of the error by:

Project Properties / Java Compiler / Errors/Warnings / Enable project specific settings set to checked / Deprecated and restrited API / Forbidden reference (access rules) set to Warning or Ignore.

The better Eclipse configuration is to disable a specific occurrence of the error by:

Project Properties / Java Build Path / Libraries / JRE System Library expand / Access rules: select / Edit... / Add... / Resolution: set to Discouraged or Accessible / Rule Pattern set to sun/reflect/Reflection.


Since I currently have the same problem here is what I do:

  1. I prefer com.sun.Reflection instead of stackTrace since a stack trace is only producing the name not the class (including the classloader) itself.

  2. The method is deprecated but still around in Java 8 SDK.

// Method descriptor #124 (I)Ljava/lang/Class; (deprecated) // Signature: (I)Ljava/lang/Class<*>; @java.lang.Deprecated public static native java.lang.Class getCallerClass(int arg0);

  1. The method without int argument is not deprecated

// Method descriptor #122 ()Ljava/lang/Class; // Signature: ()Ljava/lang/Class<*>; @sun.reflect.CallerSensitive public static native java.lang.Class getCallerClass();

Since I have to be platform independent bla bla including Security Restrictions, I just create a flexible method:

  1. Check if com.sun.Reflection is available (security exceptions disable this mechanism)

  2. If 1 is yes then get the method with int or no int argument.

  3. If 2 is yes call it.

If 3. was never reached, I use the stack trace to return the name. I use a special result object that contains either the class or the string and this object tells exactly what it is and why.

[Summary] I use stacktrace for backup and to bypass eclipse compiler warnings I use reflections. Works very good. Keeps the code clean, works like a charm and also states the problems involved correctly.

I use this for quite a long time and today I searched a related question so


You can generate a stack trace and use the informations in the StackTraceElements.

For example an utility class can return you the calling class name :

public class KDebug {
    public static String getCallerClassName() { 
        StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
        for (int i=1; i<stElements.length; i++) {
            StackTraceElement ste = stElements[i];
            if (!ste.getClassName().equals(KDebug.class.getName()) && ste.getClassName().indexOf("java.lang.Thread")!=0) {
                return ste.getClassName();
            }
        }
        return null;
     }
}

If you call KDebug.getCallerClassName() from bar(), you'll get "foo".

Now supposing you want to know the class of the method calling bar (which is more interesting and maybe what you really wanted). You could use this method :

public static String getCallerCallerClassName() { 
    StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
    String callerClassName = null;
    for (int i=1; i<stElements.length; i++) {
        StackTraceElement ste = stElements[i];
        if (!ste.getClassName().equals(KDebug.class.getName())&& ste.getClassName().indexOf("java.lang.Thread")!=0) {
            if (callerClassName==null) {
                callerClassName = ste.getClassName();
            } else if (!callerClassName.equals(ste.getClassName())) {
                return ste.getClassName();
            }
        }
    }
    return null;
 }

Is that for debugging ? If not, there may be a better solution to your problem.


I know this is an old question but I believed the asker wanted the class, not the class name. I wrote a little method that will get the actual class. It is sort of cheaty and may not always work, but sometimes when you need the actual class, you will have to use this method...

/**
     * Get the caller class.
     * @param level The level of the caller class.
     *              For example: If you are calling this class inside a method and you want to get the caller class of that method,
     *                           you would use level 2. If you want the caller of that class, you would use level 3.
     *
     *              Usually level 2 is the one you want.
     * @return The caller class.
     * @throws ClassNotFoundException We failed to find the caller class.
     */
    public static Class getCallerClass(int level) throws ClassNotFoundException {
        StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
        String rawFQN = stElements[level+1].toString().split("\\(")[0];
        return Class.forName(rawFQN.substring(0, rawFQN.lastIndexOf('.')));
    }

StackTrace

This Highly depends on what you are looking for... But this should get the class and method that called this method within this object directly.

  • index 0 = Thread
  • index 1 = this
  • index 2 = direct caller, can be self.
  • index 3 ... n = classes and methods that called each other to get to the index 2 and below.

For Class/Method/File name:

Thread.currentThread().getStackTrace()[2].getClassName();
Thread.currentThread().getStackTrace()[2].getMethodName();
Thread.currentThread().getStackTrace()[2].getFileName();

For Class:

Class.forName(Thread.currentThread().getStackTrace()[2].getClassName())

FYI: Class.forName() throws a ClassNotFoundException which is NOT runtime. Youll need try catch.

Also, if you are looking to ignore the calls within the class itself, you have to add some looping with logic to check for that particular thing.

Something like... (I have not tested this piece of code so beware)

StackTraceElement[] stes = Thread.currentThread().getStackTrace();
for(int i=2;i<stes.length;i++)
  if(!stes[i].getClassName().equals(this.getClass().getName()))
    return stes[i].getClassName();

StackWalker

StackWalker StackFrame

Note that this is not an extensive guide but an example of the possibility.

Prints the Class of each StackFrame (by grabbing the Class reference)

StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
    .forEach(frame -> System.out.println(frame.getDeclaringClass()));

Does the same thing but first collects the stream into a List. Just for demonstration purposes.

StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
    .walk(stream -> stream.collect(Collectors.toList()))
    .forEach(frame -> System.out.println(frame.getDeclaringClass()));