1

I'm trying to get the fully qualified name of the superclass of a ClassTree-Object. At the moment I'm using the toString()-Method:

public class ClassScanner extends TreePathScanner<Object, Trees> {

    @Override
    public Object visitClass(ClassTree ct, Trees trees) {
        TreePath currentPath = getCurrentPath();
        TypeElement typeElement = (TypeElement) trees.getElement(currentPath);
        String s = typeElement.getSuperclass().toString();
        System.out.println(s);
        return super.visitClass(ct, trees);
    }
}

But this doesn't seem to be a future proof approach. Also I have to extract name, package, generic types, ... by myself. Is there an alternative?

Thanks

  • Now which part doesn't seem future-proof to you? – JimmyB Jun 09 '17 at 12:03
  • The use of the "toString"-Method. Of course the "toString"-Method will exist in future versions. But will the semantic and the syntax of the returned String the same? – user3737096 Jun 09 '17 at 12:14
  • Ok, have a look at [`getQualifiedName()`](https://docs.oracle.com/javase/7/docs/api/javax/lang/model/element/TypeElement.html#getQualifiedName%28%29) then. – JimmyB Jun 09 '17 at 12:16
  • getQualifiedName is available for the TypeElement. But the superclass is a Tree or a TypeMirror. – user3737096 Jun 09 '17 at 17:36
  • https://docs.oracle.com/javase/7/docs/api/javax/lang/model/type/DeclaredType.html – JimmyB Jun 10 '17 at 18:38

2 Answers2

0

How about

    Tree extendsClassTree = classTree.getExtendsClause();
    if (extendsClassTree != null) {
        superClassName = extendsClassTree.toString();
    } else {
        superClassName = "java.lang.Object";
    }

(Borrowed from here :))

JimmyB
  • 12,101
  • 2
  • 28
  • 44
  • Thanks but then I also have to use the toString()-Method and analyze the output. I would like to avoid any toString()-Method. I would like to have one or more methods that are reasonably document and/or named. – user3737096 Jun 09 '17 at 10:50
0

OK, I found a workaround:

In the Processor, store the rootElements somewhere:

@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("*")
public class AnnotationProcessor extends AbstractProcessor {

    private Trees trees;
    private List<TreeScanner<?, Trees>> scanners = new LinkedList<>();

    public void addScanner(TreeScanner<?, Trees> scanner) {
        scanners.add(scanner);
    }

    public void removeScanner(TreeScanner<?, Trees> scanner) {
        scanners.remove(scanner);
    }

    @Override
    public synchronized void init(final ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        trees = Trees.instance(processingEnvironment);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (!roundEnv.processingOver()) {
            ASTUtils.setRootElements(roundEnv.getRootElements());
            for (final Element element : roundEnv.getRootElements()) {
                CompilationUnitTree compilationUnit = trees.getPath(element).getCompilationUnit();
                for (TreeScanner<?, Trees> scanner : scanners) {
                    scanner.scan(compilationUnit, trees);
                }
            }
        }
        return true;
    }
}

In my case, I stored them in a helper class ASTUtils:

public class ASTUtils {

    private static Set<? extends Element> rootElements = new HashSet<>();

    public static Set<? extends Element> getRootElements() {
        return rootElements;
    }

    public static void setRootElements(Set<? extends Element> rootElements) {
        ASTUtils.rootElements = rootElements;
    }
}

Then you can determine the TreePath:

public static TreePath find(Tree tree, Trees trees) {
    for (Element e : ASTUtils.getRootElements()) {
        CompilationUnitTree compilationUnit = trees.getPath(e).getCompilationUnit();
        TreePath path = TreePath.getPath(compilationUnit, tree);
        if (path != null) {
            Tree classTree = trees.getTree(trees.getElement(path));
            if (classTree != null && classTree.getKind() == kind) {
                return path;
            }
        }
    }
    return null;
}

Now it is possible to use the TreePath of the superclass to get the corresponding CompilationUnitTree and read the package or get the TypeElement and read the qualified name (see answers/initial post before).