name method java reflection methods

java - method - Obteniendo el nombre del método actualmente en ejecución



get method name c# (20)

¿Hay alguna forma de obtener el nombre del método que se ejecuta actualmente en Java?


¿Qué hay de malo con este enfoque?

class Example { FileOutputStream fileOutputStream; public Example() { //System.out.println("Example.Example()"); debug("Example.Example()",false); // toggle try { fileOutputStream = new FileOutputStream("debug.txt"); } catch (Exception exception) { debug(exception + Calendar.getInstance().getTime()); } } private boolean was911AnInsideJob() { System.out.println("Example.was911AnInsideJob()"); return true; } public boolean shouldGWBushBeImpeached(){ System.out.println("Example.shouldGWBushBeImpeached()"); return true; } public void setPunishment(int yearsInJail){ debug("Server.setPunishment(int yearsInJail=" + yearsInJail + ")",true); } }

Y antes de que la gente se vuelva loca con el uso de System.out.println(...) , siempre podría y debería crear algún método para poder redirigir la salida, por ejemplo:

private void debug (Object object) { debug(object,true); } private void dedub(Object object, boolean debug) { if (debug) { System.out.println(object); // you can also write to a file but make sure the output stream // ISN''T opened every time debug(Object object) is called fileOutputStream.write(object.toString().getBytes()); } }


Ambas opciones me funcionan con Java:

new Object(){}.getClass().getEnclosingMethod().getName()

O:

Thread.currentThread().getStackTrace()[1].getMethodName()


En caso de que el método cuyo nombre desea conocer sea un método de prueba de junit, puede usar la regla de prueba de junit: https://.com/a/1426730/3076107


Enero de 2009:
Un código completo sería (para usar con la advertencia de @Bombe en mente):

/** * Get the method name for a depth in call stack. <br /> * Utility function * @param depth depth in the call stack (0 means current method, 1 means call method, ...) * @return method name */ public static String getMethodName(final int depth) { final StackTraceElement[] ste = Thread.currentThread().getStackTrace(); //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName()); // return ste[ste.length - depth].getMethodName(); //Wrong, fails for depth = 0 return ste[ste.length - 1 - depth].getMethodName(); //Thank you Tom Tresansky }

Más en esta pregunta .

Actualización diciembre 2011:

Comentarios :

Uso JRE 6 y me da un nombre de método incorrecto.
Funciona si escribo ste[2 + depth].getMethodName().

  • 0 es getStackTrace() ,
  • 1 es getMethodName(int depth) y
  • 2 es el método de invocación.

La answer virgo47 (upvoted) en realidad calcula el índice correcto para aplicar con el fin de recuperar el nombre del método.


Esta es una expansión de la respuesta de virgo47 (arriba).

Proporciona algunos métodos estáticos para obtener los nombres de clase / método actuales e invocadores.

/* Utility class: Getting the name of the current executing method * https://.com/questions/442747/getting-the-name-of-the-current-executing-method * * Provides: * * getCurrentClassName() * getCurrentMethodName() * getCurrentFileName() * * getInvokingClassName() * getInvokingMethodName() * getInvokingFileName() * * Nb. Using StackTrace''s to get this info is expensive. There are more optimised ways to obtain * method names. See other posts eg. https://.com/questions/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection/2924426#2924426 * * 29/09/2012 (lem) - added methods to return (1) fully qualified names and (2) invoking class/method names */ package com..util; public class StackTraceInfo { /* (Lifted from virgo47''s answer) */ private static final int CLIENT_CODE_STACK_INDEX; static { // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6 int i = 0; for (StackTraceElement ste: Thread.currentThread().getStackTrace()) { i++; if (ste.getClassName().equals(StackTraceInfo.class.getName())) { break; } } CLIENT_CODE_STACK_INDEX = i; } public static String getCurrentMethodName() { return getCurrentMethodName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentMethodName(int offset) { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getMethodName(); } public static String getCurrentClassName() { return getCurrentClassName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentClassName(int offset) { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getClassName(); } public static String getCurrentFileName() { return getCurrentFileName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentFileName(int offset) { String filename = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getFileName(); int lineNumber = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getLineNumber(); return filename + ":" + lineNumber; } public static String getInvokingMethodName() { return getInvokingMethodName(2); } private static String getInvokingMethodName(int offset) { return getCurrentMethodName(offset + 1); // re-uses getCurrentMethodName() with desired index } public static String getInvokingClassName() { return getInvokingClassName(2); } private static String getInvokingClassName(int offset) { return getCurrentClassName(offset + 1); // re-uses getCurrentClassName() with desired index } public static String getInvokingFileName() { return getInvokingFileName(2); } private static String getInvokingFileName(int offset) { return getCurrentFileName(offset + 1); // re-uses getCurrentFileName() with desired index } public static String getCurrentMethodNameFqn() { return getCurrentMethodNameFqn(1); } private static String getCurrentMethodNameFqn(int offset) { String currentClassName = getCurrentClassName(offset + 1); String currentMethodName = getCurrentMethodName(offset + 1); return currentClassName + "." + currentMethodName ; } public static String getCurrentFileNameFqn() { String CurrentMethodNameFqn = getCurrentMethodNameFqn(1); String currentFileName = getCurrentFileName(1); return CurrentMethodNameFqn + "(" + currentFileName + ")"; } public static String getInvokingMethodNameFqn() { return getInvokingMethodNameFqn(2); } private static String getInvokingMethodNameFqn(int offset) { String invokingClassName = getInvokingClassName(offset + 1); String invokingMethodName = getInvokingMethodName(offset + 1); return invokingClassName + "." + invokingMethodName; } public static String getInvokingFileNameFqn() { String invokingMethodNameFqn = getInvokingMethodNameFqn(2); String invokingFileName = getInvokingFileName(2); return invokingMethodNameFqn + "(" + invokingFileName + ")"; } }


Esto se puede hacer usando StackWalker desde Java 9.

public static String getCurrentMethodName() { return StackWalker.getInstance() .walk(s -> s.skip(1).findFirst()) .get() .getMethodName(); } public static String getCallerMethodName() { return StackWalker.getInstance() .walk(s -> s.skip(2).findFirst()) .get() .getMethodName(); }

StackWalker está diseñado para ser perezoso, por lo que es probable que sea más eficiente que, por ejemplo, Thread.getStackTrace , que crea una matriz para toda la pila de llamadas. También vea el JEP para más información.


No sé cuál es la intención detrás de obtener el nombre del método ejecutado actualmente, pero si eso es solo para propósitos de depuración, entonces los marcos de registro como "logback" pueden ayudar aquí. Por ejemplo, en el registro de retorno, todo lo que necesita hacer es usar el patrón "% M" en su configuración de registro . Sin embargo, esto debe usarse con precaución ya que puede degradar el rendimiento.


Para obtener el nombre del método que llamó al método actual, puede usar:

new Exception("is not thrown").getStackTrace()[1].getMethodName()

Esto funciona en mi MacBook, así como en mi teléfono Android

También intenté:

Thread.currentThread().getStackTrace()[1]

pero Android devolverá "getStackTrace". Podría arreglar esto para Android con

Thread.currentThread().getStackTrace()[2]

Pero luego recibo la respuesta incorrecta en mi MacBook


Técnicamente esto funcionará ...

String name = new Object(){}.getClass().getEnclosingMethod().getName();

Sin embargo, se creará una nueva clase interna anónima durante el tiempo de compilación (por ejemplo, YourClass$1.class ). Así que esto creará un archivo .class para cada método que implementa este truco. Además, se crea una instancia de objeto que no se utiliza en cada invocación durante el tiempo de ejecución. Por lo tanto, este puede ser un truco de depuración aceptable, pero conlleva una sobrecarga significativa.

Una ventaja de este truco es que getEncosingMethod() devuelve java.lang.reflect.Method que se puede usar para recuperar toda la otra información del método, incluidas las anotaciones y los nombres de los parámetros. Esto hace posible distinguir entre métodos específicos con el mismo nombre (sobrecarga del método).

Tenga en cuenta que, de acuerdo con el getEnclosingMethod() de getEnclosingMethod() este truco no debe lanzar una getEnclosingMethod() SecurityException ya que las clases internas deben cargarse utilizando el mismo cargador de clases. Por lo tanto, no es necesario verificar las condiciones de acceso, incluso si hay un administrador de seguridad presente.

Se requiere usar getEnclosingConstructor() para los constructores. Durante los bloques fuera de los métodos (con nombre), getEnclosingMethod() devuelve un null .


Tengo solución usando esto (En Android)

/** * @param className fully qualified className * <br/> * <code>YourClassName.class.getName();</code> * <br/><br/> * @param classSimpleName simpleClassName * <br/> * <code>YourClassName.class.getSimpleName();</code> * <br/><br/> */ public static void getStackTrace(final String className, final String classSimpleName) { final StackTraceElement[] steArray = Thread.currentThread().getStackTrace(); int index = 0; for (StackTraceElement ste : steArray) { if (ste.getClassName().equals(className)) { break; } index++; } if (index >= steArray.length) { // Little Hacky Log.w(classSimpleName, Arrays.toString(new String[]{steArray[3].getMethodName(), String.valueOf(steArray[3].getLineNumber())})); } else { // Legitimate Log.w(classSimpleName, Arrays.toString(new String[]{steArray[index].getMethodName(), String.valueOf(steArray[index].getLineNumber())})); } }


Un método alternativo es crear, pero no lanzar, una Excepción, y usar ese objeto del cual obtener los datos de seguimiento de la pila, ya que el método de encapsulación estará típicamente en el índice 0, siempre que la JVM almacene esa información, como lo han hecho otros. mencionado anteriormente. Este no es el método más barato, sin embargo.

Desde Throwable.getStackTrace() (este ha sido el mismo desde Java 5 al menos):

El elemento cero de la matriz (suponiendo que la longitud de la matriz no es cero) representa la parte superior de la pila, que es la última invocación del método en la secuencia. Por lo general , este es el punto en el que se creó y lanzó este objeto de lanzamiento.

El fragmento de código siguiente asume que la clase no es estática (debido a getClass ()), pero eso es un hecho aparte.

System.out.printf("Class %s.%s/n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());


Usa el siguiente Código:

StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st String methodName = e.getMethodName(); System.out.println(methodName);


Usamos este código para mitigar la variabilidad potencial en el índice de seguimiento de la pila.

public class MethodNameTest { private static final int CLIENT_CODE_STACK_INDEX; static { // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6 int i = 0; for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { i++; if (ste.getClassName().equals(MethodNameTest.class.getName())) { break; } } CLIENT_CODE_STACK_INDEX = i; } public static void main(String[] args) { System.out.println("methodName() = " + methodName()); System.out.println("CLIENT_CODE_STACK_INDEX = " + CLIENT_CODE_STACK_INDEX); } public static String methodName() { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName(); } }

Parece una ingeniería excesiva, pero teníamos un número fijo para JDK 1.5 y nos sorprendió un poco que cambiara cuando nos mudamos a JDK 1.6. Ahora es lo mismo en Java 6/7, pero nunca se sabe. No es una prueba de los cambios en ese índice durante el tiempo de ejecución, pero es de esperar que HotSpot no lo haga tan mal. :-)


Util.java:

public static String getCurrentClassAndMethodNames() { final StackTraceElement e = Thread.currentThread().getStackTrace()[2]; final String s = e.getClassName(); return s.substring(s.lastIndexOf(''.'') + 1, s.length()) + "." + e.getMethodName(); }

SomeClass.java:

public class SomeClass { public static void main(String[] args) { System.out.println(Util.getCurrentClassAndMethodNames()); // output: SomeClass.main } }


Thread currentThread() . getStackTrace() generalmente contendrá el método desde el cual lo llamas, pero hay escollos (ver Javadoc ):

Algunas máquinas virtuales pueden, en algunas circunstancias, omitir uno o más marcos de pila de la traza de pila. En el caso extremo, se permite que una máquina virtual que no tenga información de seguimiento de la pila relativa a este hilo devuelva una matriz de longitud cero desde este método.


La forma más rápida que encontré es que:

import java.lang.reflect.Method; public class TraceHelper { // save it static to have it available on every call private static Method m; static { try { m = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class); m.setAccessible(true); } catch (Exception e) { e.printStackTrace(); } } public static String getMethodName(final int depth) { try { StackTraceElement element = (StackTraceElement) m.invoke( new Throwable(), depth + 1); return element.getMethodName(); } catch (Exception e) { e.printStackTrace(); return null; } } }

Accede al método nativo getStackTraceElement (int depth) directamente. Y almacena el Método accesible en una variable estática.


public class SomeClass { public void foo(){ class Local {}; String name = Local.class.getEnclosingMethod().getName(); } }

El nombre tendrá valor foo.


MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();


String methodName =Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println("methodName = " + methodName);


public static String getCurrentMethodName() { return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName(); }