Javaソースファイル内の指定された行番号の周囲のメソッドを取得する方法

StackOverflow https://stackoverflow.com/questions/1928157

  •  20-09-2019
  •  | 
  •  

質問

Java ソース ファイルの行番号があり、その行番号を囲むメソッドをプログラムで取得したいと考えています。

調べてみた アントラー それはあまり役に立ちませんでした。

ジャニノ (http://www.janino.net) 期待できそうなので、コードをスキャンして解析 (必要に応じてコンパイル) してみます。それなら使えるよ JDI そして

ReferenceType.locationsOfLine(int lineNumber)

それでも、これを行うために JDI を使用する方法がわかりませんし、この方向に進むチュートリアルも見つかりませんでした。

もしかしたら、私が完全に見逃している他の方法があるかもしれません。

役に立ちましたか?

解決

は、Java 6を使用している、とあなたはSunのAPIを使用して気にしない場合、その後、あなたが使用できる場合は、<のhref = "http://java.sun.com/javase/6/docs/technotes/guides /javac/index.html」のrel = "noreferrer">のjavac API に。あなたは、あなたのクラスパスにtools.jarを追加する必要があります。

import java.io.IOException;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.LineMap;
import com.sun.source.tree.MethodTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreeScanner;
import com.sun.source.util.Trees;

public class MethodFinder {

    public static void main(String[] args) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnosticsCollector = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticsCollector, null, null);
        Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects("path/to/Source.java");
        CompilationTask task = compiler.getTask(null, fileManager, diagnosticsCollector, null, null, fileObjects);

        // Here we switch to Sun-specific APIs
        JavacTask javacTask = (JavacTask) task;
        SourcePositions sourcePositions = Trees.instance(javacTask).getSourcePositions();
        Iterable<? extends CompilationUnitTree> parseResult = null;
        try {
            parseResult = javacTask.parse();
        } catch (IOException e) {

            // Parsing failed
            e.printStackTrace();
            System.exit(0);
        }
        for (CompilationUnitTree compilationUnitTree : parseResult) {
            compilationUnitTree.accept(new MethodLineLogger(compilationUnitTree, sourcePositions), null);
        }
    }

    private static class MethodLineLogger extends TreeScanner<Void, Void> {
        private final CompilationUnitTree compilationUnitTree;
        private final SourcePositions sourcePositions;
        private final LineMap lineMap;

        private MethodLineLogger(CompilationUnitTree compilationUnitTree, SourcePositions sourcePositions) {
            this.compilationUnitTree = compilationUnitTree;
            this.sourcePositions = sourcePositions;
            this.lineMap = compilationUnitTree.getLineMap();
        }

        @Override
        public Void visitMethod(MethodTree arg0, Void arg1) {
            long startPosition = sourcePositions.getStartPosition(compilationUnitTree, arg0);
            long startLine = lineMap.getLineNumber(startPosition);
            long endPosition = sourcePositions.getEndPosition(compilationUnitTree, arg0);
            long endLine = lineMap.getLineNumber(endPosition);

            // Voila!
            System.out.println("Found method " + arg0.getName() + " from line " + startLine + " to line "  + endLine + ".");

            return super.visitMethod(arg0, arg1);
        }
    }
}

他のヒント

使用できます ASMの CodeVisitor へ デバッグ行情報を取得します コンパイルされたクラスから。これにより、Java ソース ファイルの解析が不要になります。

ClassReader reader = new ClassReader(A.class.getName());
reader.accept(new ClassVisitor() {
    public CodeVisitor visitMethod(int access, String name, String desc,
            String[] exceptions, Attribute attrs) {
        System.out.println(name);
        return new CodeVisitor() {
            public void visitLineNumber(int line, Label start) {
                System.out.println(line);
            }
        }
    }
}, false);

クラス A の場合:

11  class A {
12  
13    public void x() {
14        int x = 1;
15        System.out.println("Hello");
16    }
17
18    public void y() {
19        System.out.println("World!");
20    }
21 }

これにより、以下が生成されます。

<init>
11
x
14
15
16
y
19
20

実行時にこの情報が必要な場合。例外を作成して、 スタックトレース要素.

多分あなたは、メソッド名を取得するには、対応するスタックトレース要素を抽出し、それをキャッチし、例外をスローすることができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top