我希望解析Java源代码文件,并提取方法的源代码。
我需要一个像这样的方法:
/** Returns a map with key = method name ; value = method source code */
Map<String,String> getMethods(File javaFile);
有没有简单的方法来实现这个功能,一个可以帮助我构建我的方法的库等?
我希望解析Java源代码文件,并提取方法的源代码。
我需要一个像这样的方法:
/** Returns a map with key = method name ; value = method source code */
Map<String,String> getMethods(File javaFile);
有没有简单的方法来实现这个功能,一个可以帮助我构建我的方法的库等?
从https://javaparser.org/下载Java解析器。
您需要编写一些代码,该代码将调用解析器...它将返回一个CompilationUnit:
InputStream in = null;
CompilationUnit cu = null;
try
{
in = new SEDInputStream(filename);
cu = JavaParser.parse(in);
}
catch(ParseException x)
{
// handle parse exceptions here.
}
finally
{
in.close();
}
return cu;
注意:SEDInputStream是输入流的一个子类。如果需要,可以使用FileInputStream。
您需要创建一个访问者。由于您只关心方法,因此您的访问者将很容易:
public class MethodVisitor extends VoidVisitorAdapter
{
public void visit(MethodDeclaration n, Object arg)
{
// extract method information here.
// put in to hashmap
}
}
调用访问者,只需执行以下操作: MethodVisitor visitor = new MethodVisitor();
visitor.visit(cu, null);
ToolProvider.getSystemJavaCompiler()
),通过compiler.getTask(...)
获取其JavacTask
,并通过task.parse()
进行解析,返回一个CompilationUnitTree
集合。Sun/Oracle解析器实际上比ECJ解析器更快,尽管它没有ECJ能力那么高的错误推断水平(例如,ECJ可以提供您意图的建议,或解析“大多数”正确的代码)。 - Lee我实现了lee的建议,无需第三方库即可实现,以下示例打印方法名称(在Java 17上测试过,但在Java 1.6上应该只需要进行微小的更改):
import com.sun.source.util.JavacTask;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Main {
public static void main(final String[] args) throws Exception {
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)) {
final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(new File(args[0])));
final JavacTask javacTask = (JavacTask) compiler.getTask(null, fileManager, null, null, null, compilationUnits);
final Iterable<? extends CompilationUnitTree> compilationUnitTrees = javacTask.parse();
final ClassTree classTree = (ClassTree) compilationUnitTrees.iterator().next().getTypeDecls().get(0);
final List<? extends Tree> classMemberList = classTree.getMembers();
final List<MethodTree> classMethodMemberList = classMemberList.stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.collect(Collectors.toList());
// just prints the names of the methods
classMethodMemberList.stream().map(MethodTree::getName)
.forEachOrdered(System.out::println);
}
}
}
VariableTree
替换MethodTree
。实际上,我建议您使用调试模式查看变量classMemberList
的内容,因为在那些子接口中有许多可能性:https://docs.oracle.com/en/java/javase/20/docs/api/jdk.compiler/com/sun/source/tree/Tree.html VariableTree
不仅代表字段声明,还用于局部变量声明。 - gouessej