11.4 Processing annotations at compile time


APT (Annotion Processing Tool) is an annotation tool that detects source code files, finds out the annotation information contained in the source files, and then performs additional processing on the annotation information.
When using the APT tool to process annotations, additional source files and other files can be generated based on the annotations in the source file (the content is determined by the author of the annotation processor). APT will also generate the source code files generated by the compilation together with the original source files. class file.
The main purpose of using APT is to simplify the workload of developers, because APT can generate some auxiliary files (such as source files, class files, program release description files, etc.) while compiling the source code of the program. The contents of these auxiliary files are all related to the source. Code related. In other words, the use of APT can mention the traditional maintenance of code information and attached files.
For early versions of Hibernate, every time you write a Java class file, you must additionally maintain a Hibernate mapping file (named * .hbm.xml file, there are some tools that can automatically generate a dictionary). The following uses annotations to simplify this operation:
The Javac.exe tool provided by Java has a -processor option, which specifies an annotation processor. If an annotation processor is specified by this option when compiling the Java source file, then this annotation is processed The compiler will extract and process the annotations in the Java source files at compile time.
Each annotation processor needs to implement the Processor interface under the javax.annotation.processing package. However, to implement this interface, all methods in it must be implemented, so the annotation processor is usually implemented by inheriting AbstractProcessor. An annotation processor can handle one or more annotation types.

1. Define 3 annotations

In order to demonstrate that APT generates additional files based on the annotations in the source file, three types of annotations are defined below, which modify the persistence class, identification attributes, and ordinary member attributes.
1. @Persistent annotation

import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Persistent
{
    String table();
}

The @Persistent annotation can only modify type declarations such as classes and interfaces. This annotation uses the @Retention 元 annotation to specify that it is only reserved in the Java source file, and the information of the annotation cannot be read by reflection at runtime.
2. The following is the @Id annotation that modifies the identity attribute. This annotation is similar to the @Persistent annotation, except that there are two more member variables

import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Id
{
    String column();
    String type();
    String generator();
}

3. Annotations to modify the attributes of ordinary members @Property

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Property
{
    String column();
    String type();
}

Second, provide a class using the above three annotations

After defining the three classes, provide a simple Java class file to use these three annotations to decorate.

package section4;
@Persistent(table = "person_inf")
public class Person
{
    @Id(column = "person_id",type="Integer",generator = "identity")
    private int id;
    @Property(column = "person_name",type="String")
    private String name;
    @Property(column = "person_age",type="Integer")
    private int age;
    //无参数构造器
    public Person()
    {}
    //初始化全部成员变量的构造器
    public Person(int id,String name,int age)
    {
        this.id=id;
        this.name=name;
        this.age=age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Three, write annotator

The following provides an APT tool for these three annotations. The function of this tool is to produce Hibernate mapping files based on the annotations (only need to understand that another XML file is generated based on these annotations)

import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.*;

import java.io.*;
import java.util.*;
@SupportedSourceVersion(SourceVersion.RELEASE_11)
// 指定可处理@Persistent、@Id、@Property三个注解
@SupportedAnnotationTypes({"Persistent", "Id", "Property"})
public class HibernateAnnotationProcessor
        extends AbstractProcessor
{
    // 循环处理每个需要处理的程序对象
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv)
    {
        // 定义一个文件输出流,用于生成额外的文件
        PrintStream ps = null;
        try
        {
            // 遍历每个被@Persistent修饰的class文件
            for (Element t : roundEnv.getElementsAnnotatedWith(Persistent.class))
            {
                // 获取正在处理的类名
                Name clazzName = t.getSimpleName();
                // 获取类定义前的@Persistent注解
                Persistent per = t.getAnnotation(Persistent.class);
                // 创建文件输出流
                ps = new PrintStream(new FileOutputStream(clazzName
                        + ".hbm.xml"));
                // 执行输出
                ps.println("<?xml version=\"1.0\"?>");
                ps.println("<!DOCTYPE hibernate-mapping PUBLIC");
                ps.println("	\"-//Hibernate/Hibernate "
                        + "Mapping DTD 3.0//EN\"");
                ps.println("	\"http://www.hibernate.org/dtd/"
                        + "hibernate-mapping-3.0.dtd\">");
                ps.println("<hibernate-mapping>");
                ps.print("	<class name=\"" + t);
                // 输出per的table()的值
                ps.println("\" table=\"" + per.table() + "\">");
                for (Element f : t.getEnclosedElements())
                {
                    // 只处理成员变量上的注解
                    if (f.getKind() == ElementKind.FIELD)   // ①
                    {
                        // 获取成员变量定义前的@Id注解
                        Id id = f.getAnnotation(Id.class);      // ②
                        // 当@Id注解存在时输出<id.../>元素
                        if (id != null)
                        {
                            ps.println("		<id name=\""
                                    + f.getSimpleName()
                                    + "\" column=\"" + id.column()
                                    + "\" type=\"" + id.type()
                                    + "\">");
                            ps.println("		<generator class=\""
                                    + id.generator() + "\"/>");
                            ps.println("		</id>");
                        }
                        // 获取成员变量定义前的@Property注解
                        Property p = f.getAnnotation(Property.class);  // ③
                        // 当@Property注解存在时输出<property.../>元素
                        if (p != null)
                        {
                            ps.println("		<property name=\""
                                    + f.getSimpleName()
                                    + "\" column=\"" + p.column()
                                    + "\" type=\"" + p.type()
                                    + "\"/>");
                        }
                    }
                }
                ps.println("	</class>");
                ps.println("</hibernate-mapping>");
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if (ps != null)
            {
                try
                {
                    ps.close();
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }
        return true;
    }
}

(1) The above annotation processor is very simple. Different from the previous way of obtaining annotation information through reflection, this annotation processor uses RoundEnvironment to obtain annotation information. Program unit, this program unit is represented by Element.
(2) Element contains a getEnclosedElement () method, which can get all program units defined in the Element, including member variables, methods, constructors, internal classes, etc.
(3) Next, the program only processes annotations in front of member variables, so the program first judges that this Element must be ElementKind.FIELD (code ①)
(4) The program calls the getAnnotation (Class clazz) method provided by Element to obtain annotations that modify the Element , The code at ②③ above is the band to get the annotation object on the member variable? After obtaining the @Id and @Prpperty annotations on member variables, the next step is to perform output based on their information.

Fourth, compile Person.lva

After providing the above annotator, you can use the javac.exe command with the -processor option to compile Person.java, for example, the following command:

javac -processor HilbernateAnnotationProcessor Person.java

After compiling Person.java by the above command, you will see a Person.hbm.xml file in the same path, which is generated by the annotation in Person.java. The contents of the file:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="Person" table="person_inf">
		<id name="id" column="person_id" type="integer">
		<generator class="identity"/>
		</id>
		<property name="name" column="person_name" type="string"/>
		<property name="age" column="person_age" type="integer"/>
	</class>
</hibernate-mapping>

Guess you like

Origin www.cnblogs.com/weststar/p/12731047.html