静的メソッドを呼び出すクラスを取得する方法は?

Pavel_K:

これは私のコードです:

class A {

    public static void doIt() {
        //Class currentClass = new Object() { }.getClass().getEnclosingClass();
        //Class currentClass = MethodHandles.lookup().lookupClass();
        String currentClass = Thread.currentThread().getStackTrace()[1].getClassName();
        System.out.println("CALLING CLASS:" + currentClass);
    }
}

class B extends A { }

public class NewMain {

    public static void main(String[] args) {
        A.doIt();
        B.doIt();
    }
}

ご覧のとおりdoItの方法を呼び出すことができA、およびBクラス。doIt、私は、コール法(に使用されたものをクラス知りたいですAB)。出来ますか?私が試した三点の解決策が機能しなかった-それは常に言うAクラスが。

ジョン・クーン:

最初は、私は、Javaコンパイラが呼び出されるどの方法を見つけ出すと同じ命令を発することができるよう、これは不可能であると思いました。

それは実際にクラスが呼び出される方法を記録していることが判明。

だから、質問は今、次のようになります。

  • どのように我々は、メソッドが呼び出された場所を得るのですか?
  • どのように我々は、メソッドが呼び出される方法を取得するには、この情報を使用していますか?

一つ目は簡単です:私たちは私たちに与えることができStackWalker、使用バイトコードインデックスを

今、私たちは唯一のクラス、そのバイトコードインデックスの命令を見て、そしてこのメ​​ソッドが呼び出されたかの図アウトを解析する必要があります。

私はそのためにASMを使用しますが、それはここで間違っているツールであるかもしれません。

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.StackWalker.StackFrame;
import java.util.Set;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

class CallingClassVisitor extends ClassVisitor {

    private final StackFrame where;
    String ownerClass = null;

    public CallingClassVisitor(StackFrame where) {
        // We need a backing ClassWriter, so the Label is resolved.
        super(ASM8, new ClassWriter(0));
        this.where = where;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
            String[] exceptions) {
        MethodVisitor parent = super.visitMethod(access, name, descriptor, signature, exceptions);
        if (name.equals(where.getMethodName()) && descriptor.equals(where.getDescriptor())) {
            return new CallingMethodVisitor(where, parent);
        } else {
            return parent;
        }
    }

    class CallingMethodVisitor extends MethodVisitor {

        private final StackFrame where;
        public CallingMethodVisitor(StackFrame where, MethodVisitor parent) {
            super(ASM8, parent);
            this.where = where;
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
            Label lbl = new Label();
            visitLabel(lbl);
            if (lbl.getOffset() == where.getByteCodeIndex()) {
                ownerClass = owner; 
            }
            super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
        }
    }

    public String getOwnerClass() {
        return ownerClass;
    }
}



class A {

    static final StackWalker SW = StackWalker.getInstance(Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE));

    public static void doIt() {
        StackFrame sf = SW.walk(s -> s.skip(1).findFirst()).orElseThrow();
        InputStream source = sf.getDeclaringClass().getClassLoader()
                .getResourceAsStream(sf.getClassName().replace('.', '/') + ".class");
        try {
            CallingClassVisitor ccv = new CallingClassVisitor(sf);
            new ClassReader(source).accept(ccv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
            String how = ccv.getOwnerClass();
            System.out.println(how);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }

    }
}

class B extends A { }

public class NewMain {

    public static void main(String[] args) {
        A.doIt();
        B.doIt();
    }
}

あなたの要件はその努力の価値がある場合は最後に、私はよく分かりません。

おすすめ

転載: http://10.200.1.11:23101/article/api/json?id=400791&siteId=1