7 Replies Latest reply: Jan 4, 2010 9:36 AM by 843810 RSS

    How to get the full identifier name?

    843810
      I am using the Java Compiler API and walking through the AST to retrieve information. I was able to analyze this program:
        package com.test;
        import java.io.*;
      
        public class Test
        {
           public static void main(String[] args)
           {
                int x = FOO.ALL + BAR.NONE;
           }
       }
      When I try to dump out the identifierTree using getName(), all I see is FOO instead of FOO.ALL and BAR instead of BAR.NONE, Am I misinterpreting the meaning of an identifier? Here is the fragment of my visitor code:
         @Override
          public Object visitIdentifier(IdentifierTree identifierTree, TreePath tp)
          {
              // Print out the identifier name
               
              System.out.println("Identifier: " + identifierTree.getName().toString());
      
              return super.visitIdentifier(identifierTree, tp);
          }
      What should I do to extract the full FOO.ALL and BAR.NONE?

      Thanks for any ideas or suggestions.

      Edited by: scott2006 on Dec 29, 2009 6:54 PM
        • 1. Re: How to get the full identifier name?
          jschellSomeoneStoleMyAlias
          As a guess, you need to look at the Tree.Kind type. I would suspect that that should lead to a specific type that has the info you are looking for.
          • 2. Re: How to get the full identifier name?
            843810
            It turns out that my understanding of "what an identifier is" was wrong. Identifiers don't have any dots (".") inside them.

            The next issue that I am struggling with should be easy but I haven't been able to figure it out. How do I distinguish between a class and an interface? Both class and interface (and even enums) have the same visit method (visitClass). The tree kind is also CLASS for both of them. So, how do I know if I am dealing with a class or an interface?
            • 3. Re: How to get the full identifier name?
              843810
              I think you'll need to hang on to the fully qualified name, but it looks like you can do something like:
              JavacTask javac = ...;
              Elements elems = javac.getElements();
              CharSequence typeName = ...;
              TypeElement te = elems.getTypeElement(typeName);
              ElementKind kind = te.getKind();
              boolean isInterface = (kind == ElementKind.INTERFACE);
              The ElementKind.isInterface method will return true for either an interface or an annotation while the isClass method will return true for either a class or an enum.
              • 4. Re: How to get the full identifier name?
                843810
                Thanks, jschell and kschneid. I have made some progress but I remain stuck on being able to distinguish between a class or an interface.

                I found the bug 6570730 (http://bugs.sun.com/view_bug.do?bug_id=6570730) which confirms that this is an issue. However, the work around suggested in the bug appears not to work. The suggestion is to get the Element from "getElement(Tree)". However there is no such getElement(Tree) call, instead there is a getElement(TreePath) call.

                I tried it as follows:
                Trees trees = Trees.instance(jcTask);
                Iterable<? extends CompilationUnitTree> units = jcTask.parse();
                for (CompilationUnitTree cu : units) {
                    TreePath tp = new TreePath(CompilationUnit);
                    Element element = trees.getElement(tp);
                    System.out.println("Element: " + element);
                }
                element is always returned as 'null' no matter what TreePath I use.

                Looking for any further suggestions to move forward ...

                Edited by: scott2006 on Jan 1, 2010 3:28 PM
                • 5. Re: How to get the full identifier name?
                  843810
                  kschneid, I am also trying to follow up on your suggestion. But how do I extract typeName from elems in your code fragment:
                  JavacTask javac = ...;
                  Elements elems = javac.getElements();
                  CharSequence typeName = ...;
                  TypeElement te = elems.getTypeElement(typeName);
                  I presume that typeName is the names of the classes and interfaces in the compilation unit. However, how do I get typeName?
                  • 6. Re: How to get the full identifier name?
                    843810
                    My apology for posting my continuing efforts. I followed the method outlined by kschneid:
                    TypeElement te = elements.getTypeElement(typeName);
                    ElementKind kind = te.getKind();
                    However, te is being returned as null. I verified that typeName is a string with the correct fully qualified name. I obtained elements as follows:
                    CompilationTask task = jc.getTask(null, null, diagnostics, null, null, fileObjects);
                    JavacTask jcTask = (JavacTask)task;
                    Trees trees = Trees.instance(jcTask);
                    Iterable<? extends CompilationUnitTree> units = jcTask.parse();
                    Elements elements = jcTask.getElements();
                    Perhaps, my calls are not in the right sequence. Am I parsing twice? Is there a way to iterate through each "element" of "elements"?

                    I am running out of ideas. Any help is welcome.

                    Edited by: scott2006 on Jan 2, 2010 1:04 PM
                    • 7. Re: How to get the full identifier name?
                      843810
                      Here's a quick example:
                      import com.sun.source.tree.ClassTree;
                      import com.sun.source.tree.CompilationUnitTree;
                      import com.sun.source.tree.ExpressionTree;
                      import com.sun.source.tree.Tree;
                      import com.sun.source.tree.TreeVisitor;
                      import com.sun.source.util.JavacTask;
                      import com.sun.source.util.SimpleTreeVisitor;
                      import java.io.IOException;
                      import java.util.List;
                      import javax.lang.model.element.ElementKind;
                      import javax.lang.model.element.Name;
                      import javax.lang.model.element.TypeElement;
                      import javax.lang.model.util.Elements;
                      import javax.tools.JavaCompiler;
                      import javax.tools.JavaFileObject;
                      import javax.tools.StandardJavaFileManager;
                      import javax.tools.ToolProvider;
                      
                      public class Main {
                      
                          public static void main(String[] args) throws IOException {
                              JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                              StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
                              Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(args);
                              JavacTask task = (JavacTask)compiler.getTask(null, fileManager, null, null, null, fileObjects);
                              Elements elements = task.getElements();
                              TreeVisitor<Void, Void> visitor = new CompilationUnitVisitor(elements);
                              Iterable<? extends CompilationUnitTree> compilationUnitTrees = task.parse();
                              for (CompilationUnitTree compilationUnitTree : compilationUnitTrees) {
                                  compilationUnitTree.accept(visitor, null);
                              }
                          }
                      
                          private static class CompilationUnitVisitor extends SimpleTreeVisitor<Void, Void> {
                      
                              private final Elements elements;
                      
                              public CompilationUnitVisitor(Elements elements) {
                                  super();
                                  this.elements = elements;
                              }
                      
                              @Override
                              public Void visitCompilationUnit(CompilationUnitTree tree, Void ignore) {
                                  String currentPackagePrefix = "";
                                  ExpressionTree packageName = tree.getPackageName();
                                  if (packageName != null) {
                                      String packageNameString = String.valueOf(packageName);
                                      if (packageNameString.length() > 0) {
                                          currentPackagePrefix = packageNameString + ".";
                                      }
                                  }
                                  TreeVisitor<Void, String> visitor = new ClassVisitor(this.elements);
                                  List<? extends Tree> typeDeclTrees = tree.getTypeDecls();
                                  for (Tree typeDeclTree : typeDeclTrees) {
                                      typeDeclTree.accept(visitor, currentPackagePrefix);
                                  }
                                  return null;
                              }
                          }
                      
                          private static class ClassVisitor extends SimpleTreeVisitor<Void, String> {
                      
                              private final Elements elements;
                      
                              public ClassVisitor(Elements elements) {
                                  super();
                                  this.elements = elements;
                              }
                      
                              @Override
                              public Void visitClass(ClassTree tree, String currentPackagePrefix) {
                                  Name simpleName = tree.getSimpleName();
                                  String canonicalName = currentPackagePrefix + simpleName;
                                  TypeElement typeElement = elements.getTypeElement(canonicalName);
                                  ElementKind elementKind = typeElement.getKind();
                                  boolean isInterface = (elementKind == ElementKind.INTERFACE);
                                  System.out.println(canonicalName + " is an interface: " + isInterface);
                                  List<? extends Tree> memberTrees = tree.getMembers();
                                  String memberPrefix = canonicalName + ".";
                                  for (Tree memberTree : memberTrees) {
                                      memberTree.accept(this, memberPrefix);
                                  }
                                  return null;
                              }
                          }
                      }
                      Edited by: kschneid on Jan 4, 2010 10:33 AM
                      Modified ClassVisitor.visitClass method to handle nested classes/interfaces