Accessing source code from Java Annotation Processor

I had a problem where I had to access some source code (the initializer code for a non-String/non-primitive constant) and got it solved by accessing the source code via the Compiler Tree API.

Here’s the general recipe:

1. Create a custom TreePathScanner:

private static class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> {

private String fieldName;

private String fieldInitializer;

public void setFieldName(String fieldName) {
    this.fieldName = fieldName;
}

public String getFieldInitializer() {
    return this.fieldInitializer;
}

@Override
public Object visitVariable(VariableTree variableTree, Trees trees) {
    if (variableTree.getName().toString().equals(this.fieldName)) {
        this.fieldInitializer = variableTree.getInitializer().toString();
    }

    return super.visitVariable(variableTree, trees);
}

2. In your AbstractProcessor, save a reference to the current compilation tree by overriding the init method:

@Override
public void init(ProcessingEnvironment pe) {
    super.init(pe);
    this.trees = Trees.instance(pe);
}

3. Get the initialization source code for the VariableElement (in your case an enum):

// assuming theClass is a javax.lang.model.element.Element reference
// assuming theField is a javax.lang.model.element.VariableElement reference
String fieldName = theField.getSimpleName().toString();
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
TreePath tp = this.trees.getPath(theClass);

codeScanner.setFieldName(fieldName);
codeScanner.scan(tp, this.trees);
String fieldInitializer = codeScanner.getFieldInitializer();

And that’s it! In the end the fieldInitiliazer variable is going to contain the exact line(s) of code used to initialize my constant. With some tweaking you should be able to use the same recipe to access the source code of other element types in the source tree (i.e. methods, package declarations, etc)

For more reading and examples read this article: Source Code Analysis Using Java 6 APIs.

Leave a Comment