Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically invoke Annotation Processors

This is the first time I am writing a Annotation Processor and I want to invoke it programmatically. 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.

like image 937
Tapas Bose Avatar asked May 12 '12 16:05

Tapas Bose


People also ask

How do I run an annotation processor?

Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors -> Enable Annotation Processing.

How does annotation processing work?

The annotation processing is done in multiple rounds. Each round starts with the compiler searching for the annotations in the source files and choosing the annotation processors suited for these annotations. Each annotation processor, in turn, is called on the corresponding sources.

What is Eclipse annotation processing?

A Java annotation processor is a compiler plug-in that can gather information about source code as it is being compiled, generate additional Java types or other resource files, and post warnings and errors.


2 Answers

You can call the Java compiler with annotation processors programmatically, inside the same process, like this:

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.

like image 101
Esko Luontola Avatar answered Sep 21 '22 01:09

Esko Luontola


jOOR has an API to simplify access to javax.tools.JavaCompiler as shown in this answer. 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

Disclaimer, I work for the company behind jOOR.

like image 36
Lukas Eder Avatar answered Sep 21 '22 01:09

Lukas Eder