简体   繁体   English

以编程方式调用注释处理器

[英]Programmatically invoke Annotation Processors

This is the first time I am writing a Annotation Processor and I want to invoke it programmatically. 这是我第一次编写Annotation Processor,我想以编程方式调用它。 Is it possible? 可能吗?

I have written small code for processor: 我为处理器编写了小代码:

@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;
    }

}

Now If I want to invoke the process method, then how can I do this? 现在如果我想调用流程方法,那我该怎么做呢? Can I do it in following way: 我可以通过以下方式完成:

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

Any information will be very helpful to me. 任何信息对我都非常有帮助。

Thanks. 谢谢。

This is a link to my answer to a similar question . 这是我对类似问题的回答的链接。

You could do annotation processing the way you suggest in your question, but you would somehow have to produce the annotations and roundEnv . 您可以按照您在问题中建议的方式进行注释处理,但是您必须以某种方式生成annotationsroundEnv

The intended use of annotation processing is during compilation. 注释处理的预期用途是在编译期间。 I recommend a two step compilation process. 我建议两步编译过程。

  1. Compile your annotation processor and related files in the usual way. 以通常的方式编译注释处理器和相关文件。
  2. compile the other files (using a compiler that supports annotation processing). 编译其他文件(使用支持注释处理的编译器)。 You may have to some arguments to the compiler: the processor path, the class name of the processor, etc. 您可能需要编译器的一些参数:处理器路径,处理器的类名等。

The compiler will produce the annotations and roundEnv variables and an instance of your processor. 编译器将生成annotationsroundEnv变量以及处理器的实例。 (Most compilers require that your processor be public and have a public constructor.) The compiler will then invoke the process method. (大多数编译器要求您的处理器是公共的,具有公共构造函数。)然后,编译器将调用process方法。

You can call the Java compiler with annotation processors programmatically, inside the same process, like this: 您可以在同一进程中以编程方式使用注释处理器调用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));
    }
}

If you remove the call to setProcessors then it will detect annotation processors automatically based on the META-INF/services/javax.annotation.processing.Processor files on classpath. 如果删除对setProcessors的调用, setProcessors根据类路径上的META-INF/services/javax.annotation.processing.Processor文件自动检测注释处理器。

jOOR has an API to simplify access to javax.tools.JavaCompiler as shown in this answer . jOOR有一个API来简化javax.tools.JavaCompiler访问,如本答案所示 You can trigger it easily as follows: 您可以按如下方式轻松触发:

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

This is specifically useful for unit testing annotation processors. 这对于单元测试注释处理器特别有用。 See also this blog post here: https://blog.jooq.org/2018/12/07/how-to-unit-test-your-annotation-processor-using-joor 另请参阅此博客文章: https//blog.jooq.org/2018/12/07/how-to-unit-test-your-annotation-processor-using-joor

Disclaimer, I work for the company behind jOOR. 免责声明,我为jOOR背后的公司工作。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM