【问题标题】:Programmatically invoke Annotation Processors以编程方式调用注释处理器
【发布时间】:2023-03-17 06:49:02
【问题描述】:

这是我第一次编写注释处理器,我想以编程方式调用它。有可能吗?

我已经为处理器编写了小代码:

@SupportedAnnotationTypes({"app.dev.ems.support.annotation.HBMModel"})
public class HBMModelProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(HBMModel.class);
        System.out.println(elements);
        return true;
    }

}

现在如果我想调用流程方法,那我该怎么做呢?我可以通过以下方式进行吗:

HBMModelProcessor modelProcessor = new HBMModelProcessor();
modelProcessor.process(annotations, roundEnv)

任何信息都会对我很有帮助。

谢谢。

【问题讨论】:

    标签: java annotations annotation-processing


    【解决方案1】:

    您可以在同一进程内以编程方式调用带有注释处理器的 Java 编译器,如下所示:

    import com.sun.tools.javac.processing.PrintingProcessor;
    import fi.jumi.actors.generator.JavaSourceFromString;
    import org.junit.*;
    import org.junit.rules.TemporaryFolder;
    
    import javax.annotation.processing.Processor;
    import javax.tools.*;
    import javax.tools.JavaCompiler.CompilationTask;
    import java.io.IOException;
    import java.util.Arrays;
    
    import static org.hamcrest.MatcherAssert.assertThat;
    import static org.hamcrest.Matchers.is;
    
    public class ExampleTest {
    
        @Rule
        public final TemporaryFolder tempDir = new TemporaryFolder();
    
        @Test
        public void example() throws IOException {
            JavaFileObject src = new JavaSourceFromString(
                    "com.example.GuineaPig",
                    "package com.example;\n" +
                    "public interface GuineaPig {\n" +
                    "    void foo();\n" +
                    "}"
            );
            compile(new PrintingProcessor(), src);
        }
    
        private void compile(Processor processor, JavaFileObject... compilationUnits) throws IOException {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(tempDir.getRoot()));
    
            CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, Arrays.asList(compilationUnits));
            task.setProcessors(Arrays.asList(
                    processor
            ));
            boolean success = task.call();
            for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                System.err.println(diagnostic);
            }
            assertThat("compile succeeded", success, is(true));
        }
    }
    

    如果您删除对setProcessors 的调用,那么它将根据类路径上的META-INF/services/javax.annotation.processing.Processor 文件自动检测注释处理器。

    【讨论】:

      【解决方案2】:

      jOOR 有一个 API 来简化access to javax.tools.JavaCompiler as shown in this answer。您可以按如下方式轻松触发:

      Reflect.compile(
          "com.example.MyClass",
          "package com.example; "
        + "@app.dev.ems.support.annotation.HBMModel "
        + "class MyClass {}",
          new CompileOptions().processors(new HBMModelProcessor())
      );
      

      这对于单元测试注释处理器特别有用。另请参阅此处的此博客文章: https://blog.jooq.org/2018/12/07/how-to-unit-test-your-annotation-processor-using-joor

      免责声明,我在 jOOR 背后的公司工作。

      【讨论】:

        【解决方案3】:

        这是my answer to a similar question的链接。

        您可以按照您在问题中建议的方式进行注释处理,但您必须以某种方式生成annotationsroundEnv

        注解处理的预期用途是在编译期间。我推荐一个两步编译过程。

        1. 以通常的方式编译您的注释处理器和相关文件。
        2. 编译其他文件(使用支持注释处理的编译器)。您可能需要向编译器提供一些参数:处理器路径、处理器的类名等。

        编译器将生成annotationsroundEnv 变量和处理器实例。 (大多数编译器要求您的处理器是公共的并且有一个公共构造函数。)然后编译器将调用process 方法。

        【讨论】:

        • 感谢您的回复。所以没有办法得到annotationsroundEnv这两个变量?
        • 当然有办法得到annotationsroundEnvannotations = new HashSet&lt;TypeElement&gt;(); annotations . add ( /* your annotations */) ;roundEnv = new RoundEnvironment ( ) { /* implementation */ } 您是否正在尝试对您的处理器进行单元测试?您可能可以使用模拟框架。
        • @emory,我想对注释处理器进行单元测试。欢迎提供样品,因为这是第一个 google 条目。
        • @Snicolas 我创建了一个可以帮助您入门的 ideone - ideone.com/7HhgzI
        • 我终于成功了。我将此用作灵感来源:today.java.net/pub/a/today/2008/04/10/…。我有一个样本来对处理器here 进行单元测试。该库使用此技术进行测试。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-01
        • 2020-07-06
        • 2019-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多