简体   繁体   English

从Java Annotation Processor访问源代码

[英]Accessing source code from Java Annotation Processor

I am trying to access the actual original source code of a type from within a Java Annotation Processor. 我试图从Java Annotation Processor中访问类型的实际原始源代码。 Is this possible somehow? 这有可能吗? Thanks! 谢谢!

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 . 我有一个问题,我必须访问一些源代码(非String /非原始常量的初始化代码),并通过编译器树API访问源代码解决它。

Here's the general recipe: 这是一般食谱:

1. Create a custom TreePathScanner: 1.创建自定义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: 2.在AbstractProcessor中,通过覆盖init方法保存对当前编译树的引用:

@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): 3.获取VariableElement的初始化源代码(在您的情况下为枚举):

// 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. 最后,fieldInitiliazer变量将包含用于初始化常量的精确代码行。 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 (ie methods, package declarations, etc) 通过一些调整,您应该能够使用相同的配方来访问源树中其他元素类型的源代码(即方法,包声明等)

For more reading and examples read this article: Source Code Analysis Using Java 6 APIs . 有关更多阅读和示例,请阅读本文:使用Java 6 API进行源代码分析

Simple adaptation of @AdrianoNobre's answer . 简单改编@AdrianoNobre的答案 It reflects the intended use of visitor pattern bit better. 它更好地反映了访客模式的用途。

AbstractProcessor init: AbstractProcessor init:

private Trees trees;

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

MethodScanner MethodScanner

private static class MethodScanner extends TreePathScanner<List<MethodTree>, Trees> {
    private List<MethodTree> methodTrees = new ArrayList<>();

    public MethodTree scan(ExecutableElement methodElement, Trees trees) {
        assert methodElement.getKind() == ElementKind.METHOD;

        List<MethodTree> methodTrees = this.scan(trees.getPath(methodElement), trees);
        assert methodTrees.size() == 1;

        return methodTrees.get(0);
    }

    @Override
    public List<MethodTree> scan(TreePath treePath, Trees trees) {
        super.scan(treePath, trees);
        return this.methodTrees;
    }

    @Override
    public List<MethodTree> visitMethod(MethodTree methodTree, Trees trees) {
        this.methodTrees.add(methodTree);
        return super.visitMethod(methodTree, trees);
    }
}

Using the scanner to get method body: 使用扫描仪获取方法体:

MethodScanner methodScanner = new MethodScanner();
MethodTree methodTree = methodScanner.scan(methodElement, this.trees);
methodTree.getBody();

The Mirror API is an equivalent of the Reflection API, but at compile time. Mirror API与Reflection API等效,但是在编译时。 Reading the internal content of methods using this API is not possible. 无法使用此API读取方法的内部内容。 Anything else should be OK. 其他任何事都应该没问题。

If you really want to do this, then there might be hacks to get an input stream on the source files you want to read. 如果你真的想这样做,那么可能会有黑客攻击你想要阅读的源文件上的输入流。

  • Hibernate Metamodel Generator reads XML files using Filer.getResource(), in XmlParser.getInputStreamForResource() . Hibernate Metamodel Generator使用Filer.getResource()在XmlParser.getInputStreamForResource()中读取XML文件。 The problem is that only CLASS_OUTPUT and SOURCE_OUPUT are supported, so it might not be suitable for you. 问题是只支持CLASS_OUTPUT和SOURCE_OUPUT,因此它可能不适合您。

  • The other solution involves finding out the path of the source file, and then just open a regular input stream. 另一个解决方案涉及找出源文件的路径,然后只打开常规输入流。 I have done this kind of dirty hack for AndroidAnnotations, to read the AndroidManifest.xml file at compile time. 我已经为AndroidAnnotations做了这种肮脏的黑客攻击,在编译时读取AndroidManifest.xml文件。 See AndroidManifestFinder.findManifestFile() . 请参阅AndroidManifestFinder.findManifestFile()

Quick answer is that it's not possible. 快速回答是,这是不可能的。

From the Mirror API JavaDoc used in Annotation Processing in Sun's SDK 5: 来自Sun SDK 4中的注释处理中使用的Mirror API JavaDoc

The Mirror API is used to model the semantic structure of a program. Mirror API用于对程序的语义结构进行建模。 It provides representations of the entities declared in a program, such as classes, methods, and fields. 它提供了在程序中声明的实体的表示,例如类,方法和字段。 Constructs below the method level, such as individual statements and expressions, are not represented . 不表示方法级别下的构造,例如单个语句和表达式。

Java 6 Annotation Processing is based on a new API , but it still doesn't provide any more detail about the code structure. Java 6 Annotation Processing基于一个新的API ,但它仍然没有提供有关代码结构的更多细节。

you may try Compiler Tree API ( http://download.oracle.com/javase/6/docs/jdk/api/javac/tree/index.html ) 您可以尝试Compiler Tree API( http://download.oracle.com/javase/6/docs/jdk/api/javac/tree/index.html
this API is used by java compiler to work with abstract syntax tree of java programs. java编译器使用此API来处理java程序的抽象语法树。 it goes so far as Java language constructs such as statements, loops, expressions, etc. you can find jar library in your JDK directory (named tools.jar) 就Java语言构造(如语句,循环,表达式等)而言,您可以在JDK目录中找到jar库(名为tools.jar)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java 6 - 注释处理器和代码添加 - Java 6 - Annotation processor and code addition 来自Java注释处理器的@SuppressWarnings - @SuppressWarnings from a Java Annotation Processor 如何在java中处理类似“@PathParam(”“)”的java注释? 我们在哪里可以找到该特定注释处理器的源代码? - How are java annotations like “@PathParam(” “) ” processed in java? Where can we find the source code of that particular annotation processor? 如何让java注释处理器从projectA读取和处理注释,并为projectB生成java源文件 - How to have a java annotation processor read and process annotations from projectA and generate java source files for projectB Java注释处理器是否能够删除注释的代码 - Is Java annotation processor capable of removing annotated code Pluggable Annotation Processor API可以检索源代码注释吗? - Can the Pluggable Annotation Processor API retrieve source code comments? Java Annotation Processor:仅在不存在时生成源文件 - Java Annotation Processor: only generate a source file if it does not exist Java 注释处理器:如何从注释中提取 class 值 - Java Annotation Processor: how to extract class values from an annotation 用注释处理器替换代码 - Code replacement with an annotation processor 如何从Java源代码中获取自定义注释? - How to get custom annotation from source code in java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM