Is there an AST tool that allows easily extract metadata from a Java method?
For instance, using the following code snippet
/*
Checks if a target integer is present in the list of integers.
*/
public Boolean contains(Integer target, List<Integer> numbers) {
for(Integer number: numbers){
if(number.equals(target)){
return true;
}
}
return false;
}
the metadata would be:
metadata = {
"comment": "Checks if a target integer is present in the list of integers.",
"identifier": "contains",
"parameters": "Integer target, List<Integer> numbers",
"return_statement": "Boolean false"
}
This class was written a long time ago.. It was actually about four different classes - spread out in a package called JavaParserBridge
. It tremendously simplifies what you are trying to do. I have stripped out all the unneccessary stuff, and boiled it down to 100 lines. It took about an hour...
I hope this all makes sense. I usually add a lot of comments to code, but sometimes when dealing with other libraries - and posting on Stack Overflow - since this is literally just one big constructor - I will leave you with the documentation page for Java Parser
To use this class, just pass the source-code file for a Java Class as a single java.lang.String
, and the method named getMethods(String)
will return a Java Vector<Method>
. Each element of the returned Vector
will have an instance of Method
which shall have all of the Meta Information that you requested in your question.
IMPORTANT: You can get the JAR File for this package off of the github page. You need the JAR named:
javaparser-core-3.16.2.jar
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.type.ReferenceType;
import com.github.javaparser.ast.type.TypeParameter;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.Modifier; // Modifiers are the key-words such as "public, private, static, etc..."
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
import com.github.javaparser.printer.lexicalpreservation.PhantomNodeLogic;
import java.io.IOException;
import java.util.Vector;
public class Method
{
public final String name, signature, jdComment, body, returnType;
public final String[] modifiers, parameterNames, parameterTypes, exceptions;
private Method (MethodDeclaration md)
{
NodeList<Parameter> paramList = md.getParameters();
NodeList<ReferenceType> exceptionList = md.getThrownExceptions();
NodeList<Modifier> modifiersList = md.getModifiers();
this.name = md.getNameAsString();
this.signature = md.getDeclarationAsString();
this.jdComment = (md.hasJavaDocComment() ? md.getJavadocComment().get().toString() : null);
this.returnType = md.getType().toString();
this.modifiers = new String[modifiersList.size()];
this.parameterNames = new String[paramList.size()];
this.parameterTypes = new String[paramList.size()];
this.exceptions = new String[exceptionList.size()];
this.body = (md.getBody().isPresent()
? LexicalPreservingPrinter.print
(LexicalPreservingPrinter.setup(md.getBody().get()))
: null);
int i=0;
for (Modifier modifier : modifiersList) modifiers[i++] = modifier.toString();
i=0;
for (Parameter p : paramList)
{
parameterNames[i] = p.getName().toString();
parameterTypes[i] = p.getType().toString();
i++;
}
i=0;
for (ReferenceType r : exceptionList) this.exceptions[i++] = r.toString();
}
public static Vector<Method> getMethods(String sourceFileAsString) throws IOException
{
// This is the "Return Value" for this method (a Vector)
final Vector<Method> methods = new Vector<>();
// This asks Java Parser to parse the source code file
// The String-parameter 'sourceFileAsString' should have this
CompilationUnit cu = StaticJavaParser.parse(sourceFileAsString);
// This will "walk" all of the methods that were parsed by
// StaticJavaParser, and retrieve the method information.
// The method information is stored in a class simply called "Method"
cu.walk(MethodDeclaration.class, (MethodDeclaration md) -> methods.add(new Method(md)));
// There is one important thing to do: clear the cache
// Memory leaks shall occur if you do not.
PhantomNodeLogic.cleanUpCache();
// return the Vector<Method>
return methods;
}
}