java Source Analysis-Compile-Time Annotation Processor

java Source Analysis-Compile-Time Annotation Processor

In the previous article, we took a general look at how runtime annotation processors work. In this film, we discuss the underlying implementation of compile-time annotation processors.

1.Annotation Processing Tool

1.1 Overview

The Java Compile-Time Annotation Processing Tool (APT) is a series of APIs that Java provides to developers to process annotations at compile time. The use of such APIs is widely used in a variety of frameworks, such as dubbo,lombok, and so on.

Annotation Processing Tool Annotation Processor is a tool that comes with javac to scan and process annotation information at compile time. You can register your own annotation processor for some annotations. A particular annotated processor takes the Java source code (or compiled byte code) as input and generates some files (usually.Java files) as output. That is, you can generate java code at compile time. These Java codes are being generated. In a Java file. So you can't change an existing Java class, such as adding a method. These generated Java files, like other manually written java source code, will be compiled by javac.

1.2API is obsolete

Apt's core API s are all at com. Sun. Mirror. Under apt package, as follows:

The interface AnnotationProcessor is a core interface of APT and has only one method process() inside it to check and process annotations in the source program.

As we can see from the figure above, all API s for this APT are out of date.

In fact, APT has been generated since JDK5, JDK7 has been marked as out of date and not recommended for use, JDK8 has been completely removed, and since JDK6 it can be replaced with the Pluggable Annotation Processing API. apt has been replaced for two main reasons:
1), api are all at com.sun.mirror under non-standard package
2) Not integrated into javac, additional runs are required

Now that it's obsolete, let's not go into details. Let's take a look at his alternative Plug-in Annotation Processor.

2.Pluggable Annotation Processing API

2.1 Overview

The Pluggable Annotation Processing API, a plug-in annotation processor, is also an annotation processor technology used at compile time. As an alternative to APT, he solves two problems with APT. When javac executes, it calls the program that implements the API, so that we can make some enhancements to the compiler. When javac executes the following procedure:

(1) parse the source file into an abstract grammar tree;

(2) Call the registered annotation processor;

- If the process generates a new source file, the compilation phase will repeat steps (1), (2);
- Each repetition is called a round;
- The first round of parsing deals with input to a source file already in the compiler;
- When the annotation processor is not generating a new source file, it will enter the last round.

(3) Generate byte code files.

2.2 Use scenarios

With this plug-in annotation processor, we can see several scenarios

(1) Define source code compilation rules and check the compiled source code;

(2) Modifying API s already in the source code, even those of the java compiler, is not recommended;

(3) New source code can be generated at compile time through this technology, similar to the @Data annotation in Lambok, that is, some Getter/Setter methods are generated at compile time.

2.3 Core API

The core API for Annotation Processor is the Processor interface, which is in javax. Annotation. Under the processing package, let's look at its source code:

public interface Processor {
    
    Set<String> getSupportedOptions();

   //This method gives the full name of the type of annotation that the annotation processor can handle, which annotation (or annotations) the current annotation processor is using to process.
    Set<String> getSupportedAnnotationTypes();

    
    SourceVersion getSupportedSourceVersion();

    //It is called by the annotation processor and the ProcessingEnviroment parameter is entered. ProcessingEnviroment provides a number of tool classes, Elements, Types, and Filer s.
    void init(ProcessingEnvironment processingEnv);

    //Evaluate and process annotated code and generate Java files. The main function equivalent to each processor
    boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);

   
    Iterable<? extends Completion> getCompletions(Element element,
                                                  AnnotationMirror annotation,
                                                  ExecutableElement member,
                                                  String userText);
}

2.4 Custom Annotation Processor

We can customize the annotation processor, get our customized annotation information, generate java files from the annotation information, or do other things. But instead of implementing the Processor interface directly, our custom annotation processor implements its abstract class AbstractProcessor.

Here's a simple implementation of a custom annotation processor that can be used to obtain method information for a custom annotation label at compile time through the annotation processor.

(1) Define a note

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface MethodTest {
    
}

(2) Define an annotation processor;

@SupportedAnnotationTypes("test.java.lang.annotation.MethodTest")
@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
public class MyMethodTestProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("start annotation process .");
        for (TypeElement typeElement : annotations){
            System.out.println(typeElement+","+typeElement.getSimpleName());
        }
        System.out.println(roundEnv);
        return true;
    }
}

@SupportedAnnotationTypes("test.java.lang.annotation.MethodTest"): Indicates the annotations that the current annotation processor can handle;

@SupportedSourceVersion(value = SourceVersion.RELEASE_8): Indicates the compiled version.

(3) Compile the main class, using annotations;

public class MyMethodTest {
    public static void main(String[] args){
        System.out.println("main start .");
        method();
    }

    @MethodTest
    public static void method(){
        System.out.println("method start .");
    }
}

(4) Specify processor

Check Enable annotation processing in Idea for setting->Build, Execution, Deployment->Compiler->Annotation Processors (I have not tried it)

Processor can also be specified in several ways:

  • Specify directly using compilation parameters; For example: javac-processor test. Java. Lang.annotation. MyMethodTest. Java
  • Specified through service registration is META-INF/services/javax. Annotation. Processing. Add test to the Processor file. Java. Lang.annotation. MyMethodTestProcessor;
  • Configure Maven's compilation plug-in; The following:
		<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
                <annotationProcessors>
                    <annotationProcessor>
                        test.java.lang.annotation.MyMethodTestProcessor
                    </annotationProcessor>
                </annotationProcessors>
            </configuration>
        </plugin>

It is worth noting that the precondition for these three points to work is test.java.lang.annotation.MyMethodTestProcessor Annotation Processor is already compiled. Otherwise, report an error:

[ERROR] Bad service configuration file, or exception thrown while
constructing Processor object: test.java.lang.annotation.MyMethodTestProcessor: 
Provider test.java.lang.annotation.MyMethodTestProcessor not found

I developed the Processor directly by using the compilation parameters specified, and the results are as follows:

As you can see, our annotation processor works at compile time.

Keywords: JDK

Added by Gladiator2043 on Thu, 03 Mar 2022 20:02:54 +0200