首页 > 解决方案 > JavaParser:如何从 MethodDeclaration 中检索所有 ParentNode 名称?

问题描述

我正在使用JavaParser库 ( https://github.com/javaparser/javaparser ) 来解析 Java 方法声明。我想从不同的包、类、范围等中识别不同的方法声明,以便我可以准确地识别每个方法声明。

例如:

这是一个名为的 Java 文件MainClass.java

package com.company.packA.packB;

public class MainClass {
    void doTask(int x, int y) {
        //...
    }

    private class InnerClass {
        void doTask(int x, int y) {
            //...
        }
    }
}

class AnotherClassSameFile {
    void doTask(int x, int y) {
        //...
    }
}

请注意,上面的示例包含三个 void doTask(int x, int y)方法:

  1. com.company.packA.packB→<code>MainClass→<code>doTask(int x, int y)
  2. com.company.packA.packB→<code>MainClass→<code>InnerClass→<code>doTask(int x, int y)
  3. com.company.packA.packB→<code>AnotherClassSameFile→<code>doTask(int x, int y)

为了识别具有相同方法签名的不同方法声明,我需要遍历所有父节点,直到根节点。

到目前为止,我已经使用JavaParser库尝试了这段代码(简化):

class MethodStruct {    // the second example will be:
    String parentNodes; // com.company.packA.packB#MainClass#InnerClass
    String returnType;  // void
    String methodName;  // doTask
    String parameters;  // int,int
}

class JavaParserTest {
    // this is the method to be called from outside
    static List<MethodStruct> getMethodStructs(Reader reader) {
        CompilationUnit cu = JavaParser.parse(reader);

        List<MethodStruct> methodStructs = new LinkedList<>();
        cu.accept(new MethodVisitor(), methodStructs);

        return methodStructs;
    }

    static class MethodVisitor extends VoidVisitorAdapter<List<MethodStruct>> {
        @Override
        public void visit(MethodDeclaration methodDeclaration, List<MethodStruct> methodStructs) {
            super.visit(methodDeclaration, methodStructs);

            // adding individual methodStruct into the list
            methodStructs.add(getMethodStruct(methodDeclaration));
        }

        static MethodStruct getMethodStruct(MethodDeclaration methodDeclaration) {
            return new MethodStruct(
                    getParents(methodDeclaration),
                    methodDeclaration.getTypeAsString(),
                    methodDeclaration.getNameAsString(),
                    getParameterAsString(methodDeclaration.getParameters()));
        }

        // it is the method to be concerned for my question
        static String getParents(MethodDeclaration methodDeclaration) {
            StringBuilder parents = new StringBuilder();

            Node currentNode = methodDeclaration;
            while (currentNode.getParentNode().isPresent()) {
                // goto parent node
                currentNode = currentNode.getParentNode().get();

                //TODO: I'm stuck here. Help me please!
                //TODO: How to identify each node whether
                //      it is a package, innerClass, etc?
            }

            // convert StringBuilder into String and return the String
            return parents.toString();
        }

        static String getParameterAsString(NodeList<Parameter> parameters) {
            // easy task! convert parameter string list
            // into a single string (comma separated)
        }
    }
}

我在定义我的getParents(MethodDeclaration methodDeclaration)方法时遇到了困难。我该如何解决它(即,识别每个父节点)?我找不到任何有用的Node上课方法来实现我的目标。我可能错过了JavaParser图书馆里的一些东西。

标签: javaabstract-syntax-treejavaparser

解决方案


您应该尝试使用walk方法来查找具体方法声明的所有范围:

static String getParents(fina MethodDeclaration methodDeclaration) {
    final StringBuilder parents = new StringBuilder();

    methodDeclaration.walk(Node.TreeTraversal.PARENTS, node -> {
        if (node instanceof ClassOrInterfaceDeclaration) {
            path.insert(0, ((ClassOrInterfaceDeclaration) node).getNameAsString());
            path.insert(0, '$');
        }
        if (node instanceof ObjectCreationExpr) {
            path.insert(0, ((ObjectCreationExpr) node).getType().getNameAsString());
            path.insert(0, '$');
        }
        if (node instanceof MethodDeclaration) {
            path.insert(0, ((MethodDeclaration) node).getNameAsString());
            path.insert(0, '#');
        }
        if (node instanceof CompilationUnit) {
            final Optional<PackageDeclaration> pkg = ((CompilationUnit) node).getPackageDeclaration();
            if (pkg.isPresent()) {
                path.replace(0, 1, ".");
                path.insert(0, pkg.get().getNameAsString());
            }
        }
    });

    // convert StringBuilder into String and return the String
    return parents.toString();
}

推荐阅读