Jak znaleźć obiekt wywołujący metodę używającą stacktrace lub refleksji?

390

Muszę znaleźć obiekt wywołujący metodę. Czy jest to możliwe przy użyciu stacktrace lub refleksji?

Satish
źródło
5
Zastanawiam się, ale dlaczego miałbyś to zrobić?
Juliet,
2
Mam klasę nadrzędną (model MVC) ze zdarzeniem powiadamiającym i tylko setery moich podklas wywołują tę metodę. nie chcę zaśmiecać mojego kodu zbędnym argumentem. Wolę, aby metoda w klasie nadrzędnej wymyśliła seter, który ją wywołał.
Sathish
30
@Sathish Wygląda na to, że powinieneś przemyśleć ten projekt
krosenvold
7
@Juliet W ramach refaktoryzacji dużego fragmentu kodu ostatnio zmieniłem metodę, która jest używana przez wiele rzeczy. Istnieje pewien sposób na wykrycie, czy kod prawidłowo używa nowej metody, więc wypisałem numer klasy i linii, który ją wywołał w tych przypadkach. Poza logowaniem nie widzę żadnego prawdziwego celu dla czegoś takiego. Chociaż chciałbym napisać API, które teraz rzucają a, DontNameYourMethodFooExceptionjeśli metoda wywołująca nazywa się foo.
Cruncher
5
Uważam, że mogę sprawić, by program wywołujący moją metodę był nieocenionym narzędziem do debugowania: w ten sposób sprowadziło mnie tutaj wyszukiwanie w sieci. Jeśli moja metoda jest wywoływana z wielu miejsc, czy jest wywoływana z właściwej lokalizacji we właściwym czasie? Poza debugowaniem lub rejestrowaniem użyteczność jest prawdopodobnie w najlepszym razie ograniczona, jak wspomina @Cruncher.
Ogre Psalm 33

Odpowiedzi:

412
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()

Według Javadocs:

Ostatni element tablicy reprezentuje spód stosu, który jest najnowszym wywołaniem metody w sekwencji.

StackTraceElementMa getClassName(), getFileName(), getLineNumber()i getMethodName().

Będziesz musiał eksperymentować, aby określić, który indeks chcesz (prawdopodobnie stackTraceElements[1]lub [2]).

Adam Paynter
źródło
7
Powinienem zauważyć, że getStackTrace () wciąż tworzy wyjątek, więc to nie jest tak naprawdę szybsze - po prostu wygodniejsze.
Michael Myers
41
Zauważ, że ta metoda nie da ci dzwoniącego, a jedynie rodzaj dzwoniącego . Nie będziesz mieć odwołania do obiektu wywołującego twoją metodę.
Joachim Sauer
3
Tylko uwaga dodatkowa, ale w 1.5 JVM Thread.currentThread (). GetStackTrace () wydaje się być dużo wolniejszy niż tworzenie nowego wyjątku () (około 3 razy wolniej). Ale jak już wspomniano, i tak nie powinieneś używać takiego kodu w obszarze krytycznym dla wydajności. ;) JVM 1.6 wydaje się być tylko ~ 10% wolniejszy i, jak powiedział Software Monkey, wyraża zamiar lepiej niż „nowy wyjątek”.
GaZ
21
@Eelco Thread.currentThread () jest tani. Thread.getStackTrace () jest drogi, ponieważ w przeciwieństwie do Throwable.fillInStackTrace (), nie ma gwarancji, że metoda zostanie wywołana przez ten sam badany wątek, więc JVM musi utworzyć „bezpieczny punkt” - blokując stos i stos. Zobacz ten raport o błędzie: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
David Moles
7
@ JoachimSauer, czy znasz sposób na uzyskanie odwołania do obiektu wywołującego metodę?
jophde
216

Alternatywne rozwiązanie można znaleźć w komentarzu do tej prośby o ulepszenie . Wykorzystuje getClassContext()metodę niestandardową SecurityManageri wydaje się być szybsza niż metoda śledzenia stosu.

Poniższy program testuje szybkość różnych sugerowanych metod (najciekawszy bit znajduje się w klasie wewnętrznej SecurityManagerMethod):

/**
 * Test the speed of various methods for getting the caller class name
 */
public class TestGetCallerClassName {

  /**
   * Abstract class for testing different methods of getting the caller class name
   */
  private static abstract class GetCallerClassNameMethod {
      public abstract String getCallerClassName(int callStackDepth);
      public abstract String getMethodName();
  }

  /**
   * Uses the internal Reflection class
   */
  private static class ReflectionMethod extends GetCallerClassNameMethod {
      public String getCallerClassName(int callStackDepth) {
          return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
      }

      public String getMethodName() {
          return "Reflection";
      }
  }

  /**
   * Get a stack trace from the current thread
   */
  private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Current Thread StackTrace";
      }
  }

  /**
   * Get a stack trace from a new Throwable
   */
  private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {

      public String getCallerClassName(int callStackDepth) {
          return new Throwable().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Throwable StackTrace";
      }
  }

  /**
   * Use the SecurityManager.getClassContext()
   */
  private static class SecurityManagerMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return mySecurityManager.getCallerClassName(callStackDepth);
      }

      public String getMethodName() {
          return "SecurityManager";
      }

      /** 
       * A custom security manager that exposes the getClassContext() information
       */
      static class MySecurityManager extends SecurityManager {
          public String getCallerClassName(int callStackDepth) {
              return getClassContext()[callStackDepth].getName();
          }
      }

      private final static MySecurityManager mySecurityManager =
          new MySecurityManager();
  }

  /**
   * Test all four methods
   */
  public static void main(String[] args) {
      testMethod(new ReflectionMethod());
      testMethod(new ThreadStackTraceMethod());
      testMethod(new ThrowableStackTraceMethod());
      testMethod(new SecurityManagerMethod());
  }

  private static void testMethod(GetCallerClassNameMethod method) {
      long startTime = System.nanoTime();
      String className = null;
      for (int i = 0; i < 1000000; i++) {
          className = method.getCallerClassName(2);
      }
      printElapsedTime(method.getMethodName(), startTime);
  }

  private static void printElapsedTime(String title, long startTime) {
      System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
  }
}

Przykład danych wyjściowych z mojego MacBooka Intel Core 2 Duo 2,4 GHz z Javą 1.6.0_17:

Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.

Metoda wewnętrznego odbicia jest znacznie szybsza niż inne. Pobieranie śladu stosu z nowo utworzonego Throwablejest szybsze niż pobieranie z bieżącego Thread. A wśród nie-wewnętrznych sposobów znajdowania klasy dzwoniącego zwyczaj SecurityManagerwydaje się najszybszy.

Aktualizacja

Jak lyomi wskazuje w tym komentarzusun.reflect.Reflection.getCallerClass() metoda została domyślnie wyłączona w Java 7 aktualizacji 40 i usunięte całkowicie w Javie 8. Więcej na ten temat w tym numerze w bazie danych błędów Java .

Aktualizacja 2

Jak stwierdził Zammbi , Oracle został zmuszony wycofać się ze zmiany, która usunęła sun.reflect.Reflection.getCallerClass(). Jest nadal dostępny w Javie 8 (ale jest przestarzały).

Aktualizacja 3

3 lata później: aktualizacja harmonogramu z aktualną maszyną JVM.

> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.
Johan Kaving
źródło
5
Tak, wydaje się, że tak. Pamiętaj jednak, że czasy podane w tym przykładzie dotyczą miliona połączeń - więc w zależności od tego, jak tego używasz, może to nie stanowić problemu.
Johan Kaving
1
Dla mnie usunięcie refleksji z mojego projektu spowodowało 10-krotny wzrost prędkości.
Kevin Parker
1
Tak, odbicie w ogóle jest powolny (patrz np stackoverflow.com/questions/435553/java-reflection-performance ), ale w tym konkretnym przypadku z wykorzystaniem wewnętrznego klasę sun.reflect.Reflection jest najszybszy.
Johan Kaving
1
W rzeczywistości nie musi. Możesz to zweryfikować, modyfikując powyższy kod, aby wydrukować zwróconą nazwę klasy (i sugeruję zmniejszenie liczby pętli do 1). Zobaczysz, że wszystkie metody zwracają tę samą nazwę klasy - TestGetCallerClassName.
Johan Kaving
1
getCallerClass jest przestarzały i zostanie usunięty w 7u40 .. smutny :(
lyomi
36

Wygląda na to, że próbujesz uniknąć podania odwołania do thismetody. Przekazywanie thisjest o wiele lepsze niż znalezienie dzwoniącego przez bieżący ślad stosu. Refaktoryzacja do projektu OO jest jeszcze lepsza. Nie powinieneś znać dzwoniącego. Przekaż obiekt zwrotny, jeśli to konieczne.

Craig P. Motlin
źródło
6
++ Znajomość dzwoniącego to zbyt wiele informacji. Jeśli musisz, możesz przekazać interfejs, ale istnieje spora szansa, że ​​potrzebne będzie poważne refaktoryzowanie. @satish powinien opublikować swój kod i pozwolić nam się z nim dobrze bawić :)
Bill K
15
Istnieją ważne powody, dla których warto to zrobić. Miałem kilka okazji, kiedy na przykład pomogłem.
Eelco
2
@chillenious Wiem :) Zrobiłem to sam, aby stworzyć metodę, w LoggerFactory.getLogger(MyClass.class)której nie musiałem przekazywać literału klasowego. Nadal rzadko jest to właściwe.
Craig P. Motlin
6
To ogólnie dobra rada, ale nie odpowiada na pytanie.
Navin
1
Konkretnym przykładem tego, kiedy uzyskanie informacji o dzwoniącym może być PRAWA decyzja projektowa, jest implementacja INotifyPropertyChangedinterfejsu .NET . Chociaż ten konkretny przykład nie jest w Javie, ten sam problem może się objawiać podczas próby modelowania pól / modułów pobierających jako ciągów dla Reflection.
Chris Kerekes
30

Java 9 - JEP 259: Interfejs API Walking-Walking

JEP 259 zapewnia wydajny standardowy interfejs API do chodzenia po stosie, który umożliwia łatwe filtrowanie i leniwy dostęp do informacji w śladach stosu. Przed interfejsem API Walking-Walking powszechne sposoby uzyskiwania dostępu do ramek stosu:

Throwable::getStackTracei Thread::getStackTracezwróć tablicę StackTraceElement obiektów, które zawierają nazwę klasy i nazwę metody każdego elementu śledzenia stosu.

SecurityManager::getClassContextjest chronioną metodą, która umożliwia SecurityManagerpodklasie dostęp do kontekstu klasy.

Wewnętrzna sun.reflect.Reflection::getCallerClassmetoda JDK, której i tak nie powinieneś używać

Korzystanie z tych interfejsów API jest zwykle nieefektywne:

Te interfejsy API wymagają, aby maszyna wirtualna chętnie rejestrowała migawkę całego stosu i zwracała informacje reprezentujące cały stos. Nie ma możliwości uniknięcia kosztu sprawdzenia wszystkich ramek, jeśli dzwoniący jest zainteresowany tylko kilkoma górnymi ramkami na stosie.

Aby znaleźć klasę bezpośredniego rozmówcy, najpierw uzyskaj StackWalker:

StackWalker walker = StackWalker
                           .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

Następnie albo zadzwoń getCallerClass():

Class<?> callerClass = walker.getCallerClass();

lub walkgdy StackFrames i uzyskać pierwszą poprzedzający StackFrame:

walker.walk(frames -> frames
      .map(StackWalker.StackFrame::getDeclaringClass)
      .skip(1)
      .findFirst());
Ali Dehghani
źródło
15

Oneliner :

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

Pamiętaj, że może być konieczne zastąpienie 2 przez 1.

Nir Duan
źródło
10

Ta metoda robi to samo, ale nieco prościej i być może nieco bardziej wydajna, a jeśli używasz odbicia, automatycznie pomija te klatki. Jedynym problemem jest to, że może nie być obecny w maszynach JVM innych niż Sun, chociaż jest zawarty w klasach wykonawczych JRockit 1.4 -> 1.6. (Chodzi o to, że nie jest to klasa publiczna ).

sun.reflect.Reflection

    /** Returns the class of the method <code>realFramesToSkip</code>
        frames up the stack (zero-based), ignoring frames associated
        with java.lang.reflect.Method.invoke() and its implementation.
        The first frame is that associated with this method, so
        <code>getCallerClass(0)</code> returns the Class object for
        sun.reflect.Reflection. Frames associated with
        java.lang.reflect.Method.invoke() and its implementation are
        completely ignored and do not count toward the number of "real"
        frames skipped. */
    public static native Class getCallerClass(int realFramesToSkip);

Jeśli chodzi o realFramesToSkipwartość, w wersjach Sun 1.5 i 1.6 VM java.lang.System, istnieje metoda chroniona pakietem o nazwie getCallerClass (), która wywołuje sun.reflect.Reflection.getCallerClass(3), ale w mojej klasie narzędzi pomocniczych użyłem 4, ponieważ istnieje dodatkowa ramka klasy pomocniczej wezwanie.

Mikołaj
źródło
16
Korzystanie z klas implementacji JVM to naprawdę zły pomysł.
Lawrence Dol
7
Odnotowany. Podałem, że nie jest to klasa publiczna, a chroniona metoda getCallerClass () w java.lang.System jest obecna na wszystkich maszynach wirtualnych 1.5+, na które patrzyłem, w tym na IBM, JRockit i Sun, ale twoje twierdzenie jest zachowawcze. .
Nicholas
6
@ Software Monkey, jak zwykle „wszystko zależy”. Wykonanie czegoś takiego, aby pomóc w debugowaniu lub logowaniu testowym - szczególnie jeśli nigdy nie kończy się to w kodzie produkcyjnym - lub jeśli celem wdrożenia jest wyłącznie komputer programisty, prawdopodobnie będzie w porządku. Każdy, kto nadal myśli inaczej, nawet w takich przypadkach: trzeba lepiej wyjaśnić rozumowanie „ naprawdę zły pomysł” niż po prostu powiedzieć, że jest złe ...
8
Podobnie, z podobnej logiki można również argumentować, że za każdym razem, gdy używasz funkcji specyficznej dla hibernacji, która nie jest kompatybilna z JPA, zawsze jest to „ naprawdę zły pomysł”. Lub jeśli zamierzasz korzystać z funkcji specyficznych dla Oracle, które nie są dostępne w innych bazach danych, to „ naprawdę zły pomysł”. Pewnie, że jest to bezpieczniejsze nastawienie i zdecydowanie dobra rada dla niektórych zastosowań, ale automatycznie odrzuca przydatne narzędzia tylko dlatego, że nie będzie działać z konfiguracją oprogramowania, której ... nie używasz wcale ? To trochę za mało elastyczne i trochę głupie.
5
Niestrzeżone korzystanie z klas specyficznych dla dostawcy będzie wiązało się z większym prawdopodobieństwem problemów, ale należy określić ścieżkę do wdzięcznej degradacji, jeśli dana klasa nie jest obecna (lub z jakiegoś powodu jest zabroniona). Polityka bezwzględnej odmowy użycia jakichkolwiek klas specyficznych dla dostawców jest moim zdaniem trochę naiwna. Przeszukuj kod źródłowy niektórych bibliotek używanych w produkcji i zobacz, czy którakolwiek z nich to robi. (sun.misc.Unsafe może?)
Nicholas
7
     /**
       * 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 = new Throwable().getStackTrace();

        //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
        return ste[ste.length - depth].getMethodName();
      }

Na przykład, jeśli próbujesz uzyskać linię metody wywołującej w celu debugowania, musisz ominąć klasę Utility, w której
kodujesz te metody statyczne: (stary kod java1.4, tylko w celu zilustrowania potencjalnego użycia StackTraceElement)

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
          * From the Stack Trace.
          * @return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
          */
        public static String getClassMethodLine()
        {
            return getClassMethodLine(null);
        }

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
          * Allows to get past a certain class.
          * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
          * @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
          */
        public static String getClassMethodLine(final Class aclass)
        {
            final StackTraceElement st = getCallingStackTraceElement(aclass);
            final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
            +")] <" + Thread.currentThread().getName() + ">: ";
            return amsg;
        }

     /**
       * Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
       * Stored in array of the callstack. <br />
       * Allows to get past a certain class.
       * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
       * @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
       * @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
       */
      public static StackTraceElement getCallingStackTraceElement(final Class aclass)
      {
        final Throwable           t         = new Throwable();
        final StackTraceElement[] ste       = t.getStackTrace();
        int index = 1;
        final int limit = ste.length;
        StackTraceElement   st        = ste[index];
        String              className = st.getClassName();
        boolean aclassfound = false;
        if(aclass == null)
        {
            aclassfound = true;
        }
        StackTraceElement   resst = null;
        while(index < limit)
        {
            if(shouldExamine(className, aclass) == true)
            {
                if(resst == null)
                {
                    resst = st;
                }
                if(aclassfound == true)
                {
                    final StackTraceElement ast = onClassfound(aclass, className, st);
                    if(ast != null)
                    {
                        resst = ast;
                        break;
                    }
                }
                else
                {
                    if(aclass != null && aclass.getName().equals(className) == true)
                    {
                        aclassfound = true;
                    }
                }
            }
            index = index + 1;
            st        = ste[index];
            className = st.getClassName();
        }
        if(resst == null) 
        {
            //Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies 
            throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
        }
        return resst;
      }

      static private boolean shouldExamine(String className, Class aclass)
      {
          final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
            ) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
          return res;
      }

      static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
      {
          StackTraceElement   resst = null;
          if(aclass != null && aclass.getName().equals(className) == false)
          {
              resst = st;
          }
          if(aclass == null)
          {
              resst = st;
          }
          return resst;
      }
VonC
źródło
Potrzebowałem czegoś, co działa z Javą 1.4 i ta odpowiedź była bardzo pomocna! Dziękuję Ci!
RGO
6

Zrobiłem to wcześniej. Możesz po prostu utworzyć nowy wyjątek i pobrać ślad stosu bez rzucania go, a następnie zbadać ślad stosu. Jednak jak mówi druga odpowiedź, jest to niezwykle kosztowne - nie rób tego w ciasnej pętli.

Zrobiłem to już wcześniej dla narzędzia do rejestrowania w aplikacji, w której wydajność nie miała większego znaczenia (Wydajność rzadko w rzeczywistości ma tak naprawdę duże znaczenie - pod warunkiem, że wyświetlasz wynik działania, takiego jak szybkie kliknięcie przycisku).

To było zanim można było pobrać ślad stosu, wyjątki miały po prostu .printStackTrace (), więc musiałem przekierować System.out do strumienia mojego własnego stworzenia, a następnie (new Exception ()). PrintStackTrace (); Przekieruj System.out z powrotem i przeanalizuj strumień. Zabawne rzeczy.

Bill K.
źródło
Fajne; nie musisz tego rzucać?
krosenvold
Nie, przynajmniej tak to pamiętam, nie robiłem tego od kilku lat, ale jestem prawie pewien, że nowy wyjątek jest po prostu tworzeniem obiektu, a zgłoszenie wyjątku nic z tym nie robi, oprócz przejścia do klauzuli catch ().
Bill K
Schludny. Byłem skłonny rzucić to, aby zasymulować rzeczywisty wyjątek.
Sathish
Nie, ponieważ w Javie 5 istnieje metoda wątku, aby uzyskać bieżący stos jako tablicę StackTraceElements; wciąż nie jest tanie, ale tańsze niż stare rozwiązanie analizujące wyjątki.
Lawrence Dol
@ Software Monkey Chociaż jestem pewien, że to bardziej odpowiednie, co sprawia, że ​​mówisz, że jest tańszy? Zakładam, że użyłby tego samego mechanizmu, a jeśli nie, to po co spowalniać, kiedy robi to samo?
Bill K
1
private void parseExceptionContents(
      final Exception exception,
      final OutputStream out)
   {
      final StackTraceElement[] stackTrace = exception.getStackTrace();
      int index = 0;
      for (StackTraceElement element : stackTrace)
      {
         final String exceptionMsg =
              "Exception thrown from " + element.getMethodName()
            + " in class " + element.getClassName() + " [on line number "
            + element.getLineNumber() + " of file " + element.getFileName() + "]";
         try
         {
            out.write((headerLine + newLine).getBytes());
            out.write((headerTitlePortion + index++ + newLine).getBytes() );
            out.write((headerLine + newLine).getBytes());
            out.write((exceptionMsg + newLine + newLine).getBytes());
            out.write(
               ("Exception.toString: " + element.toString() + newLine).getBytes());
         }
         catch (IOException ioEx)
         {
            System.err.println(
                 "IOException encountered while trying to write "
               + "StackTraceElement data to provided OutputStream.\n"
               + ioEx.getMessage() );
         }
      }
   }
AZ_
źródło
0

Oto część kodu, który stworzyłem na podstawie wskazówek pokazanych w tym temacie. Mam nadzieję, że to pomoże.

(Prosimy o wszelkie sugestie dotyczące ulepszenia tego kodu, proszę powiedz mi)

Licznik:

public class InstanceCount{
    private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;


    public void count() {
        counterInstanceLog= new counterInstanceLog();
    if(counterInstanceLog.getIdHashCode() != 0){
    try {
        if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
         counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
    }

    counterInstanceLog.incrementCounter();

            instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
    }

    (...)
}

A przedmiot:

public class CounterInstanceLog{
    private int idHashCode;
    private StackTraceElement[] arrayStackTraceElements;
    private int instanceCount;
    private String callerClassName;

    private StackTraceElement getProjectClasses(int depth) {
      if(depth< 10){
        getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
        if(getCallerClassName().startsWith("com.yourproject.model")){
            setStackTraceElements(Thread.currentThread().getStackTrace());
            setIdHashCode();
        return arrayStackTraceElements[depth];
        }
        //+2 because one new item are added to the stackflow
        return getProjectClasses(profundidade+2);           
      }else{
        return null;
      }
    }

    private void setIdHashCode() {
        if(getNomeClasse() != null){
            this.idHashCode = (getCallerClassName()).hashCode();
        }
    }

    public void incrementaContador() {
    this.instanceCount++;
}

    //getters and setters

    (...)



}
Pmt
źródło
0
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

class DBConnection {
    String createdBy = null;

    DBConnection(Throwable whoCreatedMe) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        whoCreatedMe.printStackTrace(pw);
        try {
            createdBy = os.toString();
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable(
                "Connection created from DBConnectionManager");
        DBConnection conn = new DBConnection(createdBy);
        System.out.println(conn.createdBy);
    }
}

LUB

public static interface ICallback<T> { T doOperation(); }


public class TestCallerOfMethod {

    public static <T> T callTwo(final ICallback<T> c){
        // Pass the object created at callee to the caller
        // From the passed object we can get; what is the callee name like below.
        System.out.println(c.getClass().getEnclosingMethod().getName());
        return c.doOperation();
    }

    public static boolean callOne(){
        ICallback callBackInstance = new ICallback(Boolean){
            @Override
            public Boolean doOperation() 
            {
                return true;
            }
        };
        return callTwo(callBackInstance);
    }

    public static void main(String[] args) {
         callOne();
    }
}
Kanagavelu Sugumar
źródło
0

użyj tej metody:

 StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
 stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
 System.out.println(e.getMethodName());

Przykład metody wywołującej Kod znajduje się tutaj: -

public class TestString {

    public static void main(String[] args) {
        TestString testString = new TestString();
        testString.doit1();
        testString.doit2();
        testString.doit3();
        testString.doit4();
    }

    public void doit() {
        StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
        System.out.println(e.getMethodName());
    }

    public void doit1() {
        doit();
    }

    public void doit2() {
        doit();
    }

    public void doit3() {
        doit();
    }

    public void doit4() {
        doit();
    }
}
Reegan Miranda
źródło