4

I have a class like below.

public class Login {
    private Keyword browser;
    private String page;
}

Keyword is a class in different package. I want to get the fully qualified name of the class Keyword while parsing the Login class using javaparser.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • As @EJP hinted in his answer you will have to do at least a minimum amount of code analysis in addition to parsing the source. E.g. something like this: (1) see if the type reference is already a qualified name, (2) if not see if there exists an import, (3) otherwise append the types name to the package declaration. – Balder Mar 27 '14 at 10:23
  • Also note that JavaParser moved to GitHub https://github.com/javaparser/javaparser – Federico Tomassetti May 20 '15 at 20:37

7 Answers7

4

You cannot do that using JavaParser because JavaParser does not resolve symbols. To resolve the name Keyword to a class you need to do several things: * implements proper scope rules (you need to look for internal classes, then for other classes inside the same file, then to consider imports...) * it depends on the classpath used to compile: changing it the same class could be resolved differently

To do that a symbol resolver should be written: it is not trivial but doable. If you are interested in the subject you can read a post I just wrote How to build a symbol solver for Java, in Clojure. The post contains also a link to the code, freely available on GitHub.

Source: I am a JavaParser contributor

Federico Tomassetti
  • 2,100
  • 1
  • 19
  • 26
4

You can use the JavaParser Symbol Solver:

<dependency>
    <groupId>com.github.javaparser</groupId>
    <artifactId>javaparser-symbol-solver-core</artifactId>
    <version>3.14.5</version>
</dependency>

Then parse the code using the following configuration:

CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(), 
                                                     new JavaParserTypeSolver(sourceRoot));
final ParserConfiguration config = new ParserConfiguration()
                .setStoreTokens(true)
                .setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver));
SourceRoot root = new SourceRoot(Paths.get("/path/to/project/"));
root.parse("", config, (Path localPath, Path absolutePath, ParseResult<CompilationUnit> result) -> {
                // Do something with the CompilationUnit
                return Result.DONT_SAVE;
            });

We can now get the fully qualified identifier of any ReferenceType using:

ResolvedType type = referenceType.resolve();
String qualifiedName = type.getQualifiedName();
Simon Baars
  • 1,877
  • 21
  • 38
1

Nobody so far appears to have read the question, but if you're parsing the source code, either it is in the current package or it is imported by an import statement.

I would have expected a Java parser writer or user to know that.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • If the type in question comes from an wildcard import statement, it can be very hard to parse the qualified name. – Carlos Melo Dec 15 '16 at 12:59
1

I wrote a method that can get the fully qualified name on basis of a ClassOrInterfaceDeclaration object (latest version of JavaParser):

    private static String getFullyQualifiedName(ClassOrInterfaceDeclaration c2) {
        String name = "";
        ClassOrInterfaceDeclaration parentClass = c2.getParentNode().isPresent() ? getClass(c2.getParentNode().get()): null;
        if(parentClass!=null) {
            name+=getFullyQualifiedName(parentClass)+".";
        } else {
            CompilationUnit u = getCompilationUnit(c2);
            if(u!=null && u.getPackageDeclaration().isPresent()) {
                name+=u.getPackageDeclaration().get().getNameAsString()+".";
            }
        }
        return name+c2.getNameAsString();
    }

    private static ClassOrInterfaceDeclaration getClass(Node n1) {
        while (!(n1 instanceof ClassOrInterfaceDeclaration)) {
            if(n1.getParentNode().isPresent()) {
                n1 = n1.getParentNode().get();
            } else return null;
        }
        return (ClassOrInterfaceDeclaration)n1;
    }

    private static CompilationUnit getCompilationUnit(Node n1) {
        while (!(n1 instanceof CompilationUnit)) {
            if(n1.getParentNode().isPresent()) {
                n1 = n1.getParentNode().get();
            } else return null;
        }
        return (CompilationUnit)n1;
    }

A much simpler version can be used if you obtain the ClassOrInterfaceType of the class:

    private static String getFullyQualifiedName(ClassOrInterfaceType e) {
        String name = "";
        if(e.getScope().isPresent())
            name+=getFullyQualifiedName(e.getScope().get())+".";
        return name+e.getNameAsString();
    }

I hope this is of help to anyone!

Simon Baars
  • 1,877
  • 21
  • 38
0

If you are using the visitors, it seems that you only get the start and end indexes inside the source file for having the type name. That will not get you the fully qualified name.

So you should implement the visit(ImportDeclaration, A) method also in your custom visitor. This method then must store the import declarations, so you can later - when the method visit(FieldDeclaration, A) gets called - refer to the imported packages and assemble the fully qualified name.

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
0

JavaParser does not resolve imports (this isn't usually considered its job, anyway). You have to manually step through the import statements and search if the Keyword belongs to them. Keep in mind that Java implicitly does a import java.lang.*, otherwise you won't resolve types such as String.

Spring Roo has a JavaParserUtils class containing a method getJavaType(CompilationUnitServices compilationUnitServices, ClassOrInterfaceDeclaration cid). The class is not designed for usage outside of Roo, but you can use as a template for solving your problem.

nd.
  • 8,699
  • 2
  • 32
  • 42
-2

this might be a better solution for your problem,

using instance of.

use of "Instance of" in java

Community
  • 1
  • 1
Robert vd S
  • 342
  • 1
  • 6