Cómo obtener la clase de llamante en Java

Quiero obtener la clase de llamada del método, es decir,

class foo{ bar(); } 

En la barra de métodos, necesito obtener el nombre de clase foo , y encontré este método:

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

Sin embargo, aunque getCallerClass es public , cuando bash llamarlo, Eclipse dice:

Restricción de acceso: El método getCallerClass () del tipo Reflection no es accesible debido a la restricción en la biblioteca requerida C: \ Program Files \ Java \ jre7 \ lib \ rt.jar

¿Hay alguna otra opción?

Puede generar un seguimiento de stack y usar la información en StackTraceElements .

Por ejemplo, una clase de utilidad puede devolverle el nombre de la clase llamante:

 public class KDebug { public static String getCallerClassName() { StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); for (int i=1; i 

Si llama a KDebug.getCallerClassName() desde la bar() , obtendrá "foo" .

Ahora supongamos que quiere saber la clase de la bar llamadas de método (que es más interesante y tal vez lo que realmente quería). Puedes usar este método:

 public static String getCallerCallerClassName() { StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); String callerClassName = null; for (int i=1; i 

¿Eso es para la depuración? Si no, puede haber una mejor solución a su problema.

Para obtener el nombre del nombre de la persona que llama / llama bajo el código, funciona bien para mí.

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

Esto depende altamente de lo que estás buscando … Pero esto debería obtener la clase y el método que llamaron a este método directamente dentro de este objeto.

  • índice 0 = Hilo
  • índice 1 = esto
  • índice 2 = llamador directo, puede ser uno mismo.
  • índice 3 … n = clases y métodos que se llamaron entre sí para llegar al índice 2 y a continuación.

Para Clase / Método / Nombre de archivo:

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

Para clase:

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

FYI: Class.forName () arroja una ClassNotFoundException que NO es tiempo de ejecución. Deberás intentar atraparlo.

Además, si está buscando ignorar las llamadas dentro de la clase en sí, tiene que agregar algunos bucles con lógica para verificar esa cosa en particular.

Algo así como … (No he probado esta pieza de código, así que ten cuidado)

 StackTraceElement[] stes = Thread.currentThread().getStackTrace(); for(int i=2;i 

Solo un pensamiento....

SecurityManager tiene un método protegido getClassContext

Al crear una clase de utilidad que amplía SecurityManager, puede acceder a esto.

 public class CallingClass extends SecurityManager { public static final CallingClass INSTANCE = new CallingClass(); public Class[] getCallingClasses() { return getClassContext(); } } 

Use CallingClass.INSTANCE.getCallingClasses() para recuperar las clases que llaman.

También hay una pequeña biblioteca (descargo de responsabilidad: mina) WhoCalled que expone esta información. Utiliza Reflection.getCallerClass cuando está disponible, sino que vuelve a SecurityManager.

Sé que esta es una vieja pregunta, pero creo que el solicitante quería la clase, no el nombre de la clase. Escribí un pequeño método que obtendrá la clase real. Es un poco engañoso y no siempre funciona, pero a veces cuando necesitas la clase real, deberás usar este método …

 /** * 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('.'))); } 

Esta es la forma más eficiente de obtener solo la clase de llamadas. Otros enfoques toman un volcado de stack completo y solo le dan el nombre de clase.

Sin embargo, esta clase está bajo el sun.* Que es realmente para uso interno. Esto significa que puede no funcionar en otras plataformas Java o incluso en otras versiones de Java. Tienes que decidir si esto es un problema o no.

El mensaje de error que OP encuentra es solo una característica de Eclipse. Si está dispuesto a vincular su código a un fabricante específico (e incluso a una versión) de la JVM, puede utilizar efectivamente el método sun.reflect.Reflection.getCallerClass() . Luego puede comstackr el código fuera de Eclipse o configurarlo para que no considere este diagnóstico un error.

La peor configuración de Eclipse es deshabilitar todas las apariciones del error por:

Project Properties / Java Compiler / Errors/Warnings / Enable project specific settings como marcadas / Deprecated and restrited API / Forbidden reference (access rules) configuradas en Warning o Ignore .

La mejor configuración de Eclipse es deshabilitar una ocurrencia específica del error mediante:

Project Properties / Java Build Path / Libraries / JRE System Library expand / Access rules: seleccionar / Edit... / Add... / Resolution: establecer en Discouraged o Accessible / Rule Pattern en sun/reflect/Reflection .

Estoy usando el siguiente método para obtener la persona que llama para una clase específica de 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; } } 

Dado que actualmente tengo el mismo problema aquí, es lo que hago:

  1. Prefiero com.sun.Reflection en lugar de stackTrace ya que un seguimiento de stack solo produce el nombre, no la clase (incluido el cargador de clases).

  2. El método está en desuso, pero todavía está en Java 8 SDK.

// Descriptor del método # 124 (I) Ljava / lang / Class; (obsoleto) // Firma: (I) Ljava / lang / Class <*>; @ java.lang.Deprecated nativo estático nativo java.lang.Class getCallerClass (int arg0);

  1. El método sin argumento interno no está en desuso

// Descriptor de método # 122 () Ljava / lang / Class; // Firma: () Ljava / lang / Class <*>; @ sun.reflect.CallerSensitive public static native native java.lang.Class getCallerClass ();

Como tengo que ser bla bla independiente de la plataforma, incluidas las Restricciones de seguridad, solo creo un método flexible:

  1. Compruebe si com.sun.Reflection está disponible (las excepciones de seguridad desactivan este mecanismo)

  2. Si 1 es sí, entonces obtenga el método con int o sin argumento int.

  3. Si 2 es sí, llámalo.

Si nunca se llegó a 3., uso el seguimiento de stack para devolver el nombre. Utilizo un objeto de resultado especial que contiene la clase o la cadena y este objeto dice exactamente qué es y por qué.

[Resumen] Uso stacktrace para copia de seguridad y para eludir las advertencias del comstackdor de eclipse. Uso reflexiones. Funciona muy bien Mantiene el código limpio, funciona como un amuleto y también establece los problemas involucrados correctamente.

Utilizo esto por bastante tiempo y hoy busqué una pregunta relacionada para

Encuentre a continuación un ejemplo simple que ilustra cómo obtener nombres de clases y métodos.

 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 tiene getClassName() , getFileName() , getLineNumber() y getMethodName()