为了示范APT根据源文件中的注解来生成额外的文件,下面定义了3种注解类型,分别修饰持久化类、标识属性和普通成员属性。
1、@Persistent注解
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Persistent
{
String table();
}
@Persistent注解只能修饰类、接口等类型声明,这个注解使用@Retention元注解指定它仅在Java源文件中保留,运行时不能通过反射来读取该注解的信息。
2、下面是修饰标识属性的@Id注解,该注解与@Persistent注解相似,只是多了两个成员变量
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Id
{
String column();
String type();
String generator();
}
3、修饰普通成员属性的注解@Property
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface Property
{
String column();
String type();
}
定义完三个类以后,提供一个简单的Java类文件使用这三个注解来修饰。
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;
}
}
下面为这三个注解提供一个APT工具,该工具的功能是根据注解来生产Hibernate映射文件(只需要明白根据这些注解生成另一份XML文件)
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)上面的注解处理器很简单,与前面通过反射来获取注解信息不同的是,这个注解处理器使用RoundEnvironment来获取注解信息,RoundEnvironment包含一个getElementsAnnotatedWith()方法,可根据注解来获取需要处理的程序单元,这个程序单元由Element代表。
(2)Element包含一个getEnclosedElement()方法,该方法可以获取该Element里定义的所有程序单元,包括成员变量、方法、构造器、内部类等。
(3)接下来程序只处理成员变量前面的注解,因此程序先判断这个Element必须是ElementKind.FIELD(代码①)
(4)程序调用Element提供的getAnnotation(Class clazz)方法来获取修饰该Element的注解,如上程序②③处代码就是获取成员变量上的注解对象的带啊吗。获取带成员变量上的@Id、@Prpperty注解之后,接下来就是根据它们的信息执行输出。
提供上面注解器之后,就可使用带-processor 选项的javac.exe命令来编译Person.java了,例如如下命令:
javac -processor HilbernateAnnotationProcessor Person.java
通过上面命令编译Person.java后,将在相同路径下看到一个Person.hbm.xml文件,该文件就是更具Person.java里的注解生成的。该文件的内容:
<?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>
原文:https://www.cnblogs.com/weststar/p/12731047.html