Come ottenere la class chiamante in Java

Voglio ottenere la class chiamante del metodo, vale a dire

class foo{ bar(); } 

Nella barra dei metodi, ho bisogno di ottenere il nome della class foo , e ho trovato questo metodo:

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

Tuttavia, anche se getCallerClass è public , quando provo a chiamarlo Eclipse dice:

Restrizione di accesso: il metodo getCallerClass () dal tipo Reflection non è accessibile a causa della restrizione sulla libreria richiesta C: \ Programmi \ Java \ jre7 \ lib \ rt.jar

Ci sono altre scelte?

È ansible generare una traccia dello stack e utilizzare le informazioni nello StackTraceElements .

Ad esempio, una class di utilità può restituire il nome della class chiamante:

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

Se chiami KDebug.getCallerClassName() da bar() , otterrai "foo" .

Supponiamo ora di voler conoscere la class della bar dei metodi di chiamata (che è più interessante e forse ciò che realmente volevi). Potresti usare questo metodo:

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

È quello per il debug? In caso contrario, potrebbe esserci una soluzione migliore al tuo problema.

Per ottenere il nome della class chiamante / callee utilizzare sotto il codice, funziona bene per me.

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

Questo dipende molto da quello che stai cercando … Ma questo dovrebbe ottenere direttamente la class e il metodo che ha chiamato questo metodo all’interno di questo object.

  • indice 0 = discussione
  • indice 1 = questo
  • indice 2 = chiamante diretto, può essere auto.
  • indice 3 … n = classi e metodi che si richiamano l’un l’altro per arrivare all’indice 2 e sotto.

Per Classe / Metodo / Nome file:

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

Per class:

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

Nota: Class.forName () genera una class ClassNotFoundException che NON è runtime. Dovresti provare a prendere.

Inoltre, se stai cercando di ignorare le chiamate all’interno della class stessa, devi aggiungere un po ‘di loop con la logica per verificare quella particolare cosa.

Qualcosa come … (Non ho testato questo pezzo di codice quindi attenzione)

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

Solo un pensiero....

SecurityManager ha un metodo protetto getClassContext

Creando una class di utilità che estenda SecurityManager, è ansible accedervi.

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

Utilizzare CallingClass.INSTANCE.getCallingClasses() per recuperare le classi chiamanti.

C’è anche una piccola biblioteca (disclaimer: la mia) WhoCalled che espone queste informazioni. Utilizza Reflection.getCallerClass quando disponibile, altrimenti torna a SecurityManager.

So che questa è una domanda vecchia ma credevo che il richiedente volesse la class, non il nome della class. Ho scritto un piccolo metodo che otterrà la vera lezione. È una specie di cheaty e potrebbe non funzionare sempre, ma a volte quando hai bisogno della class attuale, dovrai usare questo metodo …

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

Questo è il modo più efficiente per ottenere solo la class dei chiamanti. Altri approcci prendono un intero dump dello stack e ti danno solo il nome della class.

Tuttavia, questa class sotto il sun.* Che è davvero per uso interno. Ciò significa che potrebbe non funzionare su altre piattaforms Java o anche su altre versioni di Java. Devi decidere se questo è un problema o no.

Il messaggio di errore che l’OP sta incontrando è solo una funzione di Eclipse. Se sei disposto a bind il tuo codice a un produttore specifico (e anche a una versione) della JVM, puoi utilizzare efficacemente il metodo sun.reflect.Reflection.getCallerClass() . È quindi ansible compilare il codice all’esterno di Eclipse o configurarlo per non considerare questo errore diagnostico.

La peggiore configurazione di Eclipse è di disabilitare tutte le occorrenze dell’errore:

Project Properties / Java Compiler / Errors/Warnings / Enable project specific settings impostate su / Deprecated and restrited API / Forbidden reference (access rules) impostato su Warning o Ignore .

La migliore configurazione di Eclipse consiste nel disabilitare una specifica occorrenza dell’errore:

Project Properties / Java Build Path / Libraries / JRE System Library espandere / Access rules: selezionare / Edit... / Add... / Resolution: impostare su Discouraged o Accessible / Rule Pattern impostato su sun/reflect/Reflection .

sto usando il seguente metodo per ottenere il chiamante per una class specifica dallo 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; } } 

Poiché attualmente ho lo stesso problema, ecco quello che faccio:

  1. Preferisco com.sun.Reflection invece di stackTrace poiché una traccia dello stack sta solo producendo il nome non la class (incluso il classloader) stesso.

  2. Il metodo è deprecato ma ancora in giro in Java 8 SDK.

// Descrittore di metodo n. 124 (I) Ljava / lang / Class; (deprecato) // Firma: (I) Ljava / lang / Classe < *>; @ java.lang.Deprecated public static native java.lang.Class getCallerClass (int arg0);

  1. Il metodo senza argomento int non è deprecato

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

Dal momento che devo essere indipendente dalla piattaforma bla bla includendo Restrizioni di sicurezza, creo solo un metodo flessibile:

  1. Verifica se com.sun.Reflection è disponibile (le eccezioni di sicurezza disabilitano questo meccanismo)

  2. Se 1 è sì, ottieni il metodo con int o senza argomento int.

  3. Se 2 è sì chiamalo.

Se 3. non è mai stato raggiunto, utilizzo la traccia dello stack per restituire il nome. Io uso un object risultato speciale che contiene la class o la stringa e questo object dice esattamente di cosa si tratta e perché.

[Riepilogo] Uso lo stacktrace per il backup e per bypassare gli avvisi del compilatore di eclipse Uso le riflessioni. Funziona molto bene. Mantiene pulito il codice, funziona come un fascino e indica anche i problemi coinvolti correttamente.

Lo uso da parecchio tempo e oggi ho cercato una domanda correlata

Di seguito è riportato un semplice esempio che illustra come ottenere nomi di classi e metodi.

 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 ha getClassName() , getFileName() , getLineNumber() e getMethodName()