58

I wish to parse java source code files, and extract the methods source code.

I would need a method like this :

/** Returns a map with key = method name ; value = method source code */
Map<String,String> getMethods(File javaFile);

Is there a simple way to achieve this, a library to help me build my method, etc. ?

2
  • roaster offers a fluent API to work with Java code. Commented May 2, 2017 at 16:02
  • @koppor can it also parse catch blocks in the source? Commented Nov 11, 2019 at 6:03

2 Answers 2

63

Download the java parser from https://javaparser.org/

You'll have to write some code. This code will invoke the parser... it will return you a 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;

Note: SEDInputStream is a subclass of input stream. You can use a FileInputStream if you want.


You'll have to create a visitor. Your visitor will be easy because you're only interested in methods:

  public class MethodVisitor extends VoidVisitorAdapter
  {
        public void visit(MethodDeclaration n, Object arg)
        {
             // extract method information here.
             // put in to hashmap
        }
  }

To invoke the visitor, do this:

  MethodVisitor visitor = new MethodVisitor();
  visitor.visit(cu, null);
Sign up to request clarification or add additional context in comments.

10 Comments

Great answer. Appreciate the effort. Thanks.
Great answer is great. Thanks, it helps people even today ;)
The project is no longer maintained. Check code.google.com/p/javaparser/issues/detail?id=9#c32 which leads you to github.com/matozoid/javaparser
The project is maintained at github.com/javaparser/javaparser and we released version 2.1 (fully supporting Java 8) a few weeks ago. Enjoy!
The Javac compiler API has a fully accessible parsing API within the JDK. It's a bit convoluted, but you can get the system compiler (ToolProvider.getSystemJavaCompiler()), get its JavacTask via compiler.getTask(...), and have it parse via task.parse(), which returns a collection of CompilationUnitTrees. The Sun/Oracle parser is actually much faster than even the ECJ parser, though it does not have the same level of error-inference that ECJ is capable of (for example, ECJ can give suggestions on what you mean, or partially parse code that is "mostly" correct).
|
2

I implemented lee's suggestion, there is no need of third party libraries to achieve that, the following example prints the names of the methods (tested with Java 17 but should work with Java 1.6 with minor changes):

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

}

Note that other solutions except ANTLR don't support very latest versions of Java, javaparser doesn't fully support 19 currently (January 2023), JavaCC doesn't seem to support Java >= 9 according to its public documentation.

Federico Tomassetti wrote in 2016 that there was no parsing functionality as part of the JDK, I replied that he was wrong. I have nothing against third party libraries but providing false information to developers in order to promote her/his stuff is not honest and is not the kind of behavior I expect on StackOverflow. I use some classes and APIs available in Java since Java 1.6 released in December 2006.

4 Comments

Very nice ! I tested your code and it works perfectly ! could it be possible to say how to do the same to get class fields ?
Thank you for the compliment by the way, I got some downvotes for this detailed answer. Yes, you can replace MethodTree in the filter by VariableTree. Actually, I advise you to use the debug mode to look at the content of the variable classMemberList because there are many possibilities among those subinterfaces: docs.oracle.com/en/java/javase/20/docs/api/jdk.compiler/com/sun/… VariableTree doesn't only represent field declarations, it's used for local variable declarations too.
VariableTree ! Nice the class i was looking for ! I searched for fields and properties ... haven't thought about variable. Yes i saw that, seems Stack became since 10 years more and more unfriendly and form oriented than content... While I am on it, is possible to also obtain parent & implemented classes ?
Yes, getExtendsClause() returns the single tree of the parent and getImplementsClause() returns a list of trees, each tree represents an implemented interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.