Bagaimana cara menemukan pemanggil metode menggunakan stacktrace atau refleksi?

392

Saya perlu menemukan penelepon metode. Apakah mungkin menggunakan stacktrace atau refleksi?

Sathish
sumber
5
Hanya ingin tahu, tetapi mengapa Anda perlu melakukan ini?
Juliet
2
Saya memiliki kelas Induk (model MVC) dengan acara pemberi notifikasi dan hanya seter subclass saya yang memanggil metode ini. saya tidak ingin membuang kode saya dengan argumen yang berlebihan. Saya lebih suka membiarkan metode di kelas induk mengetahui setter yang memanggilnya.
Sathish
30
@Sathish Kedengarannya seperti Anda harus memikirkan kembali desain itu
krosenvold
7
@ Juliet Sebagai bagian dari refactoring sejumlah besar kode, baru-baru ini saya telah mengubah metode yang digunakan oleh banyak hal. Ada cara tertentu untuk mendeteksi jika kode menggunakan metode baru dengan benar, jadi saya mencetak nomor kelas dan garis yang memanggilnya dalam kasus-kasus itu. Di luar penebangan, saya tidak melihat tujuan nyata untuk hal seperti ini. Meskipun saya agak ingin menulis API sekarang yang melempar DontNameYourMethodFooExceptionjika metode panggilan bernama foo.
Cruncher
5
Saya menemukan bisa mendapatkan penelepon metode saya alat debugging yang sangat berharga: itulah cara pencarian web membawa saya ke sini. Jika metode saya dipanggil dari beberapa tempat, apakah itu dipanggil dari lokasi yang tepat pada waktu yang tepat? Di luar debugging atau logging, kegunaan mungkin terbatas pada yang terbaik, seperti yang disebutkan @Cruncher.
Ogre Psalm33

Jawaban:

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

Menurut Javadocs:

Elemen terakhir dari array mewakili bagian bawah tumpukan, yang merupakan permohonan metode terbaru dalam urutan.

Sebuah StackTraceElementmemiliki getClassName(), getFileName(), getLineNumber()dan getMethodName().

Anda harus bereksperimen untuk menentukan indeks mana yang Anda inginkan (mungkin stackTraceElements[1]atau [2]).

Adam Paynter
sumber
7
Saya harus mencatat bahwa getStackTrace () masih menciptakan Exception, jadi ini tidak terlalu cepat - hanya lebih nyaman.
Michael Myers
42
Perhatikan bahwa metode ini tidak akan memberi Anda penelepon, tetapi hanya tipe penelepon . Anda tidak akan memiliki referensi ke objek yang memanggil metode Anda.
Joachim Sauer
3
Hanya catatan tambahan, tetapi pada 1,5 JVM Thread.currentThread (). GetStackTrace () tampaknya jauh lebih lambat daripada membuat Pengecualian baru () (sekitar 3 kali lebih lambat). Tapi seperti yang sudah disebutkan, Anda tidak harus menggunakan kode seperti ini di area yang sangat kritis kinerja. ;) A 1,6 JVM hanya tampaknya ~ 10% lebih lambat dan, seperti yang dikatakan Software Monkey, itu menyatakan maksud lebih baik daripada cara "Pengecualian baru".
GaZ
21
@Eelco Thread.currentThread () murah. Thread.getStackTrace () mahal karena, tidak seperti Throwable.fillInStackTrace (), tidak ada jaminan metode ini dipanggil oleh utas yang sama dengan yang diperiksa, jadi JVM harus membuat "titik aman" - mengunci tumpukan dan tumpukan. Lihat laporan bug ini: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
David Moles
7
@ JoachimSauer apakah Anda tahu cara untuk mendapatkan referensi ke objek yang memanggil metode?
Jophde
216

Solusi alternatif dapat ditemukan dalam komentar untuk permintaan peningkatan ini . Ia menggunakan getClassContext()metode kustom SecurityManagerdan tampaknya lebih cepat daripada metode jejak tumpukan.

Program berikut menguji kecepatan berbagai metode yang disarankan (bit paling menarik adalah di kelas batin 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.");
  }
}

Contoh output dari 2,4 GHz Intel Core 2 Duo MacBook saya yang menjalankan Java 1.6.0_17:

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

Metode Refleksi internal jauh lebih cepat daripada yang lain. Mendapatkan jejak stack dari yang baru dibuat Throwablelebih cepat daripada mendapatkannya dari saat ini Thread. Dan di antara cara-cara non-internal untuk menemukan kelas pemanggil kebiasaan SecurityManagertampaknya menjadi yang tercepat.

Memperbarui

Seperti yang ditunjukkan oleh lyomi dalam komentar ini , sun.reflect.Reflection.getCallerClass()metode ini telah dinonaktifkan secara default di Java 7 pembaruan 40 dan dihapus sepenuhnya di Java 8. Baca lebih lanjut tentang ini dalam masalah ini di database bug Java .

Perbarui 2

Seperti yang ditemukan zammbi , Oracle terpaksa mundur dari perubahan yang menghapus sun.reflect.Reflection.getCallerClass(). Ini masih tersedia di Java 8 (tetapi sudah usang).

Perbarui 3

3 tahun setelah: Pembaruan tepat waktu dengan JVM saat ini.

> 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
sumber
5
Ya, sepertinya begitu. Tetapi perhatikan bahwa waktu yang saya berikan dalam contoh ini adalah untuk sejuta panggilan - jadi tergantung pada bagaimana Anda menggunakan ini, itu mungkin tidak menjadi masalah.
Johan Kaving
1
Bagi saya menghapus refleksi dari proyek saya menghasilkan peningkatan kecepatan 10x.
Kevin Parker
1
Ya, refleksi pada umumnya lambat (lihat misalnya stackoverflow.com/questions/435553/java-reflection-performance ), tetapi dalam kasus khusus ini menggunakan internal sun.reflect.Kelas koreksi adalah yang tercepat.
Johan Kaving
1
Sebenarnya tidak perlu. Anda dapat memverifikasinya dengan memodifikasi kode di atas untuk mencetak className yang dikembalikan (dan saya sarankan mengurangi jumlah loop menjadi 1). Anda akan melihat bahwa semua metode mengembalikan className yang sama - TestGetCallerClassName.
Johan Kaving
1
getCallerClass sudah usang dan akan dihapus dalam 7u40 .. sedih :(
lyomi
36

Kedengarannya seperti Anda mencoba menghindari melewatkan referensi ke thisdalam metode. Melewati thislebih baik daripada menemukan penelepon melalui jejak tumpukan saat ini. Refactoring ke desain yang lebih OO bahkan lebih baik. Anda tidak perlu tahu penelepon. Lewati objek panggilan balik jika perlu.

Craig P. Motlin
sumber
6
++ Mengetahui penelepon adalah terlalu banyak informasi. Jika harus, Anda bisa lewat di antarmuka, tetapi ada kemungkinan besar diperlukan refactoring besar. @satish harus posting kode dan mari kita bersenang-senang dengan itu :)
Bill K
15
Ada alasan yang sah untuk melakukan hal ini. Saya memiliki beberapa kesempatan di mana saya merasa terbantu selama pengujian misalnya.
Eelco
2
@chillenious Saya tahu :) Saya sudah melakukannya sendiri untuk membuat metode seperti di LoggerFactory.getLogger(MyClass.class)mana saya tidak harus lulus dalam literal kelas. Masih jarang hal yang benar untuk dilakukan.
Craig P. Motlin
6
Ini adalah saran yang baik secara umum, tetapi tidak menjawab pertanyaan.
Navin
1
Contoh nyata kapan keputusan desain KANAN untuk mendapatkan informasi tentang pemanggil adalah ketika mengimplementasikan INotifyPropertyChangedantarmuka .NET . Meskipun contoh khusus ini tidak ada di Jawa, masalah yang sama dapat muncul dengan sendirinya ketika mencoba memodelkan bidang / getter sebagai string untuk Reflection.
Chris Kerekes
31

Java 9 - JEP 259: Stack-Walking API

JEP 259 menyediakan API standar yang efisien untuk tumpukan berjalan yang memungkinkan penyaringan mudah, dan akses malas ke, informasi dalam jejak tumpukan. Sebelum Stack-Walking API, cara umum mengakses frame stack adalah:

Throwable::getStackTracedan Thread::getStackTracemengembalikan array StackTraceElementobjek, yang berisi nama kelas dan nama metode setiap elemen stack-trace.

SecurityManager::getClassContextadalah metode yang dilindungi, yang memungkinkan SecurityManagersubkelas untuk mengakses konteks kelas.

sun.reflect.Reflection::getCallerClassMetode internal JDK yang seharusnya tidak Anda gunakan

Menggunakan API ini biasanya tidak efisien:

API ini membutuhkan VM untuk dengan penuh semangat menangkap snapshot dari seluruh tumpukan , dan mereka mengembalikan informasi yang mewakili seluruh tumpukan. Tidak ada cara untuk menghindari biaya memeriksa semua frame jika penelepon hanya tertarik pada beberapa frame teratas di stack.

Untuk menemukan kelas pemanggil langsung, pertama-tama dapatkan StackWalker:

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

Kemudian panggil getCallerClass():

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

atau walkyang StackFrames dan yang pertama sebelumnya StackFrame:

walker.walk(frames -> frames
      .map(StackWalker.StackFrame::getDeclaringClass)
      .skip(1)
      .findFirst());
Ali Dehghani
sumber
15

Oneliner :

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

Perhatikan bahwa Anda mungkin perlu mengganti 2 dengan 1.

Nir Duan
sumber
10

Metode ini melakukan hal yang sama tetapi sedikit lebih sederhana dan mungkin sedikit lebih berkinerja dan jika Anda menggunakan refleksi, ia melompati frame-frame itu secara otomatis. Satu-satunya masalah adalah itu mungkin tidak hadir dalam JVM non-Sun, meskipun itu termasuk dalam kelas runtime dari JRockit 1.4 -> 1.6. (Intinya, ini bukan kelas publik ).

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);

Sejauh apa realFramesToSkipnilainya, versi Sun 1.5 dan 1.6 VM java.lang.System, ada metode paket terproteksi yang disebut getCallerClass () yang memanggil sun.reflect.Reflection.getCallerClass(3), tetapi di kelas utilitas pembantu saya, saya menggunakan 4 karena ada bingkai tambahan dari kelas pembantu doa.

Nicholas
sumber
16
Penggunaan kelas implementasi JVM adalah ide yang sangat buruk.
Lawrence Dol
7
Dicatat. Saya memang menentukan bahwa itu bukan kelas publik, dan metode yang dilindungi getCallerClass () di java.lang.System hadir di semua 1.5+ VM yang telah saya lihat, termasuk IBM, JRockit dan Sun, tetapi pernyataan Anda cukup konservatif. .
Nicholas
6
@Software Monkey, seperti biasa, "semuanya tergantung". Melakukan sesuatu seperti ini untuk membantu debugging atau uji logging - terutama jika itu tidak pernah berakhir pada kode produksi - atau jika target penyebaran adalah PC pengembang, mungkin akan baik-baik saja. Siapa pun yang masih berpikir sebaliknya bahkan dalam kasus seperti itu: Anda harus benar-benar menjelaskan alasan " ide yang sangat buruk" lebih baik daripada hanya mengatakan itu buruk ...
8
Selain itu, dengan logika yang serupa, Anda juga bisa berargumen bahwa kapan pun Anda menggunakan fitur khusus Hibernate yang tidak kompatibel dengan JPA, itu selalu merupakan " ide yang sangat buruk". Atau jika Anda akan menggunakan fitur khusus Oracle yang tidak tersedia di database lain, itu adalah " ide yang sangat buruk". Tentu itu pola pikir yang lebih aman dan saran yang pasti bagus untuk penggunaan tertentu, tetapi secara otomatis membuang alat yang berguna hanya karena itu tidak akan bekerja dengan konfigurasi perangkat lunak yang Anda, eh .. tidak menggunakan sama sekali ? Itu agak terlalu tidak fleksibel dan agak konyol.
5
Penggunaan kelas-kelas khusus vendor yang tidak dijaga akan menghadirkan kemungkinan masalah yang lebih tinggi, tetapi seseorang harus menentukan jalur untuk menurunkan dengan anggun jika kelas tersebut tidak hadir (atau dilarang karena alasan tertentu). Kebijakan penolakan flat-out untuk menggunakan kelas spesifik vendor, menurut saya, sedikit naif. Lihatlah kode sumber dari beberapa perpustakaan yang Anda gunakan dalam produksi dan lihat apakah ada di antara mereka yang melakukan ini. (sun.misc.Unsafe mungkin?)
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();
      }

Misalnya, jika Anda mencoba untuk mendapatkan garis metode pemanggilan untuk tujuan debug, Anda harus melewati kelas Utilitas tempat Anda mengkode metode statis tersebut:
(kode java1.4 lama, hanya untuk menggambarkan potensi penggunaan 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
sumber
Saya membutuhkan sesuatu yang berfungsi dengan Java 1.4 dan jawaban ini sangat membantu! Terima kasih!
RGO
6

Saya pernah melakukan ini sebelumnya. Anda bisa membuat pengecualian baru dan ambil jejak tumpukan tanpa membuangnya, lalu periksa jejak tumpukan tersebut. Seperti jawaban lain mengatakan, itu sangat mahal - jangan lakukan itu dalam lingkaran yang ketat.

Saya telah melakukannya sebelumnya untuk utilitas pencatatan pada aplikasi yang kinerjanya tidak terlalu berarti (Kinerja jarang penting sama sekali, sebenarnya - selama Anda menampilkan hasilnya pada tindakan seperti klik tombol dengan cepat).

Itu sebelum Anda bisa mendapatkan jejak stack, pengecualian baru saja. PrintStackTrace () jadi saya harus mengarahkan System.out ke aliran kreasi saya sendiri, lalu (Pengecualian baru ()). PrintStackTrace (); Redirect System.out kembali dan parsing aliran. Hal menyenangkan.

Bill K.
sumber
Keren; Anda tidak perlu membuangnya?
krosenvold
Tidak, Setidaknya begitulah yang saya ingat, saya belum melakukannya dalam beberapa tahun, tapi saya cukup yakin bahwa membuat pengecualian baru saja membuat objek, dan melempar pengecualian tidak melakukan apa-apa kecuali lulus ke tangkapan () klausa.
Bill K
Rapi. Saya cenderung membuangnya untuk mensimulasikan pengecualian yang sebenarnya.
Sathish
Tidak, karena Java 5 ada metode di Thread untuk mendapatkan stack saat ini sebagai array dari StackTraceElements; itu masih tidak murah, tapi lebih murah daripada solusi parsing eksepsi lama.
Lawrence Dol
@Software Monkey Meskipun saya yakin itu lebih tepat, apa yang membuat Anda mengatakan bahwa itu lebih murah? Saya berasumsi mekanisme yang sama akan digunakan, dan jika tidak, mengapa membuatnya lebih lambat ketika melakukan hal yang sama?
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_
sumber
0

Berikut adalah bagian dari kode yang saya buat berdasarkan petunjuk yang ditunjukkan dalam topik ini. Semoga ini bisa membantu.

(Jangan ragu untuk membuat saran untuk meningkatkan kode ini, tolong beri tahu saya)

Penghitung:

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);
    }

    (...)
}

Dan obyeknya:

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
sumber
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);
    }
}

ATAU

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
sumber
0

gunakan metode ini: -

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

Kode contoh metode penelepon ada di sini: -

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();
    }
}
Mulai Miranda
sumber