Java uses the annotation processor to generate code-Part 2: annotation Processor

Source: Internet
Author: User

Java uses the annotation processor to generate code-Part 2: annotation Processor

 


This article is part 2 of my "using annotation processors to generate code for Java" series. In the first part (please read here), we will introduce Java annotations and several common methods.

Now, in the second section, we will introduce annotation processors. This includes how to create annotation processors and how to run them.

Collation

Without a doubt, annotations are excellent. You can set any type of metadata and configuration through annotations, and annotations have very easy-to-define syntax, as well as a variety of different types that can be used.

So far, we have seen that annotations have many advantages over Javadoc, but they are not enough to prove their degree of integration into the Java language. Therefore, is it possible to interact with the annotation and obtain more functions from the annotation? The answer is yes:

During running, annotations of the RUNTIME life cycle type can be accessed through reflection. You can use the getAnnotation () and getAnnotations () Methods of the Class to accomplish this wonderful thing [1].

During compilation, the annotation processor, a special class, can process every annotation found in the compiled code.

Annotation processor API

When Java 5 introduced annotation for the first time, the annotation processor API was not mature and standardized. The processing Annotation requires an independent Tool named apt (Annotation Processor Tool, Annotation Processor Tool) and the mirror API included in the com. sum. Mirror package. Apt needs to use the Mirror API to customize the processor.

Since Java 6, annotation processors have been standardized and incorporated into the standard library through JSR 269 [2], and apt tools have been seamlessly integrated into Java compilation tool javac.

Although we only discuss the details of the new annotation processor API in Java 6, you can also find the apt and Mirror API Information in the Java 5 Documentation here or here, find the appropriate example in this article.

The annotation Processor does not simply implement the javax. annotaion. processing. Processor interface and complete the method defined in it. Therefore, Java provides a virtual class javax. annotation. processing. AbstractProcessor that has implemented common functions to facilitate the implementation of custom processors.

The custom annotation processor may use the following three annotations to configure itself:

Javax. annotation. processing. SupportedAnnotationTypes: Used to register annotation types that can be processed by the annotation processor. The available value is the complete name of the supported annotation type-Wildcards are also allowed.

Javax. annotation. processing. SupportedSourceVersion: Used to declare the source code version supported by the annotation processor.

Javax. annotation. processing. SupportOption: Used to register custom options (parameters) that may be passed from the command line ).

Finally, we need to implement our own process () method.

Write our first annotation Processor

Next let's start writing our first annotation processor. Following the general steps described above, we will create an annotation processor class that can handle the Complexity annotation of the sample code in the first section:

package sdc.assets.annotations.processors;import …@SupportedAnnotationTypes(sdc.assets.annotations.Complexity)@SupportedSourceVersion(SourceVersion.RELEASE_6)public class ComplexityProcessor extends AbstractProcessor {    public ComplexityProcessor() {        super();    }    @Override    public boolean process(Set  annotations,                           RoundEnvironment roundEnv) {        return true;    }}

The annotation processor class above registers the annotation type it supports as sdc. assets. annotations. Complexity, although this annotation processor did nothing when it was called. In this way, every time the Java compiler (Compilation) generates a class, if it finds that the Complexity annotation is used, the annotation processor will be executed, this annotation processor must be available in classpath (we will learn more about this later ).

To interact with the annotated class, the process () method provides two parameters:

Set of a java. lang. model. TypeElement object: The process of processing annotation can be completed only after one or more rounds. The annotation processor is called in each collection and receives a Set with the Type of the annotation Type processed in the current collection as an element.

A javax. annotation. processing. roundEnvironment object: This object can be used to access the Element elements processed in the current or previous collection (annotation: elements that can be annotated, such as classes, methods, parameters, and so on ), only the annotated elements registered by the annotation processor are processed.

In addition to the above two parameters, there is also a ProcessingEnvironment type Instance Object processingEvn can be used. This object can be used to access logs or other tools, some of which will be discussed later.

With the RoundEnvironment object and the reflection method of the annotated elements, we can write a simple annotation processor implementation class. The processing method of this annotation processor is to print all elements that can be found and annotated by Complexity:

for (Element elem : roundEnv.getElementsAnnotatedWith(Complexity.class)) {    Complexity complexity = elem.getAnnotation(Complexity.class);    String message = annotation found in  + elem.getSimpleName()                   +  with complexity  + complexity.value();    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);}return true; // no further processing of this annotation type
Package and register annotation Processors

The last step to complete our annotation processor is to package and register it. In this way, the Java compiler or other tools can find this annotation processor.

The simplest way to register a processor is to use the standard Java service mechanism:
* Package your annotation processor into a Jar package.
* The Jar package must contain a folder.META-INF/services.
* This folder contains a file named javax. annotation. processing. Processor.
* In this file, write the complete class names of all annotation processors in the Jar package. Each class name has a row.

The Java compiler or other tools will find this file in all declared classpath paths and use it to register the processor.

In our example, the project folder structure and file content are as follows:

After packaging, we can start to use it.

Run the processor through javac

Suppose you have a Java project that requires some custom annotations and some available annotation processors. In Java 5, annotation compilation and processing are two different steps (and also completed by two different tools ), however, since Java 6, these two tasks have been integrated into the Java compilation tool javac.

If you add annotation processors to the classpath of javac and use the service mechanism mentioned above for registration, they will be called and executed by javac.

In our example, the following command will compile and process the Java source file that uses the Complexity annotation, the following command adds two jar packages containing the custom annotation and annotation processor to classpath ):

>javac -cp sdc.assets.annotations-1.0-SNAPSHOT.jar;     sdc.assets.annotations.processors-1.0-SNAPSHOT.jar     SimpleAnnotationsTest.java

The Java class used for testing is as follows:

package sdc.startupassets.annotations.base.client;import ...@Complexity(ComplexityLevel.VERY_SIMPLE)public class SimpleAnnotationsTest {    public SimpleAnnotationsTest() {        super();    }    @Complexity() // this annotation type applies also to methods                  // the default value 'ComplexityLevel.MEDIUM' is assumed    public void theMethod() {        System.out.println(consoleut);    }}

After executing the javac command, the output result is as follows:

Although the default javac parameter configuration is usually normal, there are some options that can help us run annotation processors in some cases:

-Akey [= value]: used to pass an option to the processor. Only the options registered with the SupportedOptions Annotation on the annotation processor can be passed in. -Proc: {none "only}: by default, javac runs the annotation processor and compiles all source files. If the proc: none option is used, all annotation processing processes will not be executed-this is useful when compiling annotation processors themselves. If the proc: only option is used, only the annotation processing process will be executed-it is useful for running internal verification of annotation processors like quality check tools or standard checkers. -Processorpath path: used to specify the annotation processor and its dependent location. This is optional. If it is not set, the compiler will search for it in the default classpath path. This is useful when clear separation is maintained between project dependencies and annotation processor dependencies (which are not required during running. -S dir: Specifies the location where the generated code is saved. Although the subdirectories of the corresponding source code package hierarchy are automatically created as needed, the specified parent directory must exist before running the javac command. -Processor class1 [, class2, class3…] : Specifies the complete Class Name of the annotation processor to be executed. If this option is specified, the process of searching annotation processors based on the service mechanism mentioned above will be ignored. This is useful when you have multiple registered annotation processors under classpath but only want to execute a few of them. Run the processor through Eclipse

Eclipse or other mainstream ides support annotation processors and integrate them into regular build processes.

In Eclipse, after you open the properties dialog box of the Java project, you can find the Annotation Processing option in the Java Compiler group.

On the Annotation Processing option tab, select the Annotation Processing option (not selected by default ). The processor option parameter can be passed through the form (during compilation) in this tab.

Similarly, select the annotation processor to be executed on the Factory Path option page:

Once the configuration is complete, the registered annotation processor is executed every time this project is compiled.

Run the processor through Maven

The annotation processor can also be integrated into the Apache Maven build tool for execution.

(In Maven), the automation (processing) level that we can access allows us to seamlessly integrate all task types into the build process. In the cycle of a project, a separate process is no longer required for standard verification and code generation. In addition, it allows seamless integration with the continuous integration engine.

Although there are other methods that integrate annotation processors into the Mavan build, we recommend that you use the methods discussed here. This method is based on the same Mojo (Maven plug-in,: Mojo indicates the specific implementation of a processing process, which is usually provided by the maven Plugin ), it can manage compiled tasks. In fact, because (actually) Java compilation tools are used, this method can generate a well-known standard practice.

Integration with Maven requires that our annotation and annotation processors be introduced in the form of Maven artifact at the same time.

We recommend that you save annotation and annotation processors to different artifact, because these annotation Processors may not be required in some customer projects to reduce the number of project dependencies.

In this method, we will create three different projects, each of which corresponds to a Maven artifact:

Artifact of the annotation. It only contains the custom annotation type. Artifact of the annotation processor. It contains annotation processors. It depends on the custom annotation that these processors need to use to complete their processing tasks, and add the artifact dependency containing the corresponding annotation. To compile the plug-in, you must configure the proc: none option so that the annotation processing process will not be executed when the artifact is compiled. Customer project. It contains specific business code and needs to depend on the previous two artifact.

The following is the structure of the artifact project folder containing the annotation and the POM content:

Pay attention to build the maven compilation plug-in version number of the artifact above. <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4NCjxwPs/Cw + assets/uxL/OxLz + Memory + DQo8cD48aW1nIGFsdD0 = "annotation" artifact = "" dir = "" processor = "" src = "http://www.bkjia.com/uploads/allimg/151022/04350CJ8-7.png" title = "\"/>

Note the services folder required during the packaging of the processor, the version of the Maven compilation plug-in, and the option proc: none used to prevent the processor from running during the artifact compilation process, and artifact dependencies that contain annotation types.

Finally, the folder structure and POM content of the customer project are as follows:

Note that artifact containing custom annotations and artifact containing annotation processors must be relied on here.

After completion, each time you execute the compile target of the maven build tool, the annotation processor will follow the preset execution.

[1]: view the Class interface document here for more information.
[2]: JSR269, dynamic annotation processor API, which can be viewed online here.

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.