2

呼び出しスタックのイントロスペクションを通じて、呼び出されたメソッドのシグネチャを見つける方法はありますか?同じことを見つけるための代替案はありますか?ソースコードがなく、バイトコードファイルしかありません

前もって感謝します。

4

3 に答える 3

4

スタックイントロスペクションは、メソッドの呼び出し元、またはせいぜいメソッドのいくつかの詳細を提供します。正確なメソッドシグネチャを得るには、リフレクションを使用する必要があります。

StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

公式ドキュメントによると:

このスレッドのスタックダンプを表すスタックトレース要素の配列を返します。このスレッドが開始されていないか終了している場合、このメソッドは長さゼロの配列を返します。返された配列の長さがゼロ以外の場合、配列の最初の要素はスタックの最上位を表します。これは、シーケンス内の最新のメソッド呼び出しです。配列の最後の要素はスタックの最下部を表します。これは、シーケンス内で最も最近のメソッド呼び出しです。

このようにして、StackTraceからメソッド名、ファイル名、行番号を取得できます。

完全なメソッドシグネチャを作成するには、リフレクションを使用する必要があります

于 2012-06-08T08:13:59.870 に答える
3

JavaReflectionStackTraceElementを使用できます。

StackTraceElement[] elements = new Throwable().getStackTrace();

    String calleeMethod = elements[0].getMethodName();
    String callerMethodName = elements[1].getMethodName();
    String callerClassName = elements[1].getClassName();

    System.out.println("CallerClassName=" + callerClassName + " , Caller method name: " + callerMethodName);
    System.out.println("Callee method name: " + calleeMethod);
于 2012-06-08T09:49:42.500 に答える
0

StackTraceElementにはパラメーターに関する情報が含まれていないため、呼び出し元のクラスに同じ名前のメソッドが複数あり、どれを知りたい場合は、ソースにアクセスする必要があります。元の質問の場合、逆コンパイラーを使用してソースを再作成し、それらのソースからコンパイルしてから、スタックトレースを再作成し、再作成されたソースの行番号を確認することができます。

オーバーロードされたメソッドが問題にならない場合、これはあなたができることです:

public class TestTest {
    @Test
    public void overloaded1() throws Exception {
        doTheThing("foo", 42, this);
    }

    @Test
    public void overloaded2() throws Exception {
        doTheThing(1);
    }

    @Test
    public void notOverloaded() throws Exception {
        printMethodSignature();
    }

    public void doTheThing(int overloaded) throws Exception {
        printMethodSignature();
    }

    public void doTheThing(String dumm1, int dummy2, Object dummy3) throws Exception {
        printMethodSignature();
    }

    public void printMethodSignature() throws Exception {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        // elements[0] will contain java.lang.Thread.getStackTrace() here
        // elements[1] will contain this method: printMethodSignature()
        // elements[2] will contain the method from which printMethodSignature() was called

        System.out.println(elements[2] + " -> " + toSignature(elements[2]));
    }

    // Represent class & method as string
    public String toSignature(StackTraceElement st) throws Exception {
        Class callingClass = Class.forName(st.getClassName());
        return Stream.of(callingClass.getMethods())
            .filter(m -> m.getName().equals(st.getMethodName()))
            .map(m -> String.format("%s.%s(%s)", callingClass.getName(), m.getName(), toSignature(m)))
            .collect(Collectors.joining("\n"));
    }

    // Represent parameters as a String
    public String toSignature(Method method) {
        return Stream.of(method.getParameters())
            .map(p -> p.getParameterizedType().getTypeName())
            .collect(Collectors.joining(", "));
    }
}
于 2018-12-18T21:25:38.253 に答える