2009-12-18 10 views
8

Ho un numero di riga di un file di origine Java e voglio ottenere il metodo di ricerca per quel numero di riga in modo programmatico.Come ottenere il metodo circostante nel file di origine Java per un determinato numero di riga

Ho cercato su ANTLR che non mi ha aiutato molto.

Janino (http://www.janino.net) sembra promettente, vorrei scansionare e analizzare (e se necessario compilare) il codice. Poi ho potuto usare JDI e

ReferenceType.locationsOfLine(int lineNumber) 

Ancora non so come usare JDI per fare questo e non ha trovato un tutorial che va da nessuna parte in questa direzione.

Forse c'è un altro modo che mi manca completamente.

+0

Stai parlando allo stesso modo diff -U sarà? per esempio. @@ -3452,6 +3452,59 @@ void MyMethod (int a, int b) – Pod

+0

Vuoi il nome del metodo o il testo del metodo? –

+0

Il nome del metodo è sufficiente, ma il problema è risolto a lungo. Grazie comunque :-) – roesslerj

risposta

11

Se stai utilizzando Java 6 e se non ti dispiace usare le API di Sun, puoi utilizzare the javac API. È necessario aggiungere tools.jar al classpath.

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

È possibile utilizzare il CodeVisitor ASM su retrieve the debugging line information da una classe compilata. Ciò consente di risparmiare l'analisi dei file di origine 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); 

Per la classe 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 } 

Questo produce:

<init> 
11 
x 
14 
15 
16 
y 
19 
20 

Se avete bisogno di queste informazioni in fase di esecuzione. È possibile creare un'eccezione e dare un'occhiata allo stack trace elements.

+0

Ciao! Grazie per questa buona risposta. Questo è quasi quello che stavo cercando. Apprezzo molto il vostro aiuto! – roesslerj

0

forse si può lanciare un'eccezione, catturarla, estrarre l'elemento stacktrace corrispondente per ottenere il nome del metodo.

+1

Non è necessario analizzare la traccia dello stack. Lo stack trace element (http://java.sun.com/javase/6/docs/api/java/lang/StackTraceElement.html) contiene le informazioni. –

+0

grazie per le informazioni – chburd

+0

Ci scusiamo per essere imprecisi. Devo ottenere il metodo di una classe che non sto usando. – roesslerj

Problemi correlati