【问题标题】:How to get the class code as String from Annotation Processor?如何从注释处理器获取类代码作为字符串?
【发布时间】:2021-05-08 11:43:34
【问题描述】:

我有一个基本的注释处理器

@SupportedAnnotationTypes("example.Annotation")
public class Processor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(annotation);
            for (Element element : elementsAnnotatedWith) {
                TypeElement typeElement = (TypeElement) element;
                // Here, typeElement.getQualifiedName() is accessible, but not the code nor file path.
            }
        }
        return false;
    }
}

这个注解只能用在类上。我知道目标类未编译,因此无法进行反射访问,但我想将类代码作为 String 以我自己的方式解析,而不是使用此 API。

有可能吗?我知道我可以获得限定名称,但在哪里查找文件?

【问题讨论】:

  • 真的需要完整的源码,还是反射信息(方法签名、字段声明、继承...)就够了?
  • @Tigger 我已经有很多基于解析类代码的代码,所以我想重用它。但似乎没有办法,所以我不得不使用这个 API (processingEnv.getElementUtils()) 重写我的代码。
  • 其实我还需要其他方法。用于将方法从注释类复制到生成的类...
  • 因为它发生在编译之前,你需要的所有源文件都必须在文件系统的某个地方,对吧?如果是这样,我敢打赌你可以使用一些环境变量。你如何编译/构建你的库(maven、gradle、...)?
  • 我使用 Gradle,但这不会让注释处理器只对我有用吗?

标签: java annotations annotation-processing


【解决方案1】:

TypeElement的源代码可以这样加载:

private String loadSource(TypeElement typeElement) throws IOException {
    final FileObject source = processingEnv.getFiler().getResource(
        StandardLocation.SOURCE_PATH,
        ((PackageElement) typeElement.getEnclosingElement()).getQualifiedName(),
        typeElement.getSimpleName() + ".java");
    
    try (Reader reader = source.openReader(true)) {
        final StringBuilder builder = new StringBuilder();
        final char[] buf = new char[1024];
        int read;
        while ((read = reader.read(buf)) != -1) {
            builder.append(buf, 0, read);
        }
        return builder.toString();
    }
}

测试的Processor jar 包含一个META-INF/services/javax.annotation.processing.Processor 文件,无需指定-process 选项:

  • Maven:好的
  • Gradle : 需要额外配置,假设src/main/java 是源目录
tasks.withType(JavaCompile) {
    configure(options) {
        options.setSourcepath(project.files('src/main/java'))
    }
}
  • 命令行:添加-sourcepath选项:

javac -cp path/to/processor.jar -sourcepath path/to/sources path/to/JavaFile.java

【讨论】:

  • 不幸的是,Gradle 中的 SOURCE_PATH 为空 :(
  • 我找到了一种让它与 Gradle 一起工作的方法,并更新了我的答案。我希望它对你有用。
猜你喜欢
  • 2020-01-20
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多