Accessing source code from Java Annotation Processor

后端 未结 5 1357
悲哀的现实
悲哀的现实 2020-12-04 22:38

I am trying to access the actual original source code of a type from within a Java Annotation Processor. Is this possible somehow? Thanks!

5条回答
  •  情歌与酒
    2020-12-04 23:13

    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 {
    
    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.

提交回复
热议问题