APT的介绍:
APT(Annotation Processing Tool)是一种注解处理工具,它对源代码文件进行检测,并找出源文件所包含的注解信息,然后针对注解信息进行额外的处理。
使用APT工具处理注解时可以根据源文件中的注解生成额外的源文件和其他的文件(文件的具体内容由注解处理器的编写者决定),APT还会编译生成的源代码文件和原来的源文件,将它们一起生成class文件。
Hibernate自动生成XML模拟:
涉及知识点:
1、自定义注释使用原注释
@Target(ElementType.FIELD) //只能修饰变量,属性 @Retention(RetentionPolicy.SOURCE) // 保留在源代码中,编译时丢弃
2、自定义注解处理类,继承注解处理工具类javax.annotation.processing.AbstractProcessor重写抽象方法process 处理注解
-
- 形参RoundEnvironment类型的形参roundEnvironment接收被处理的类.java源文件
- getElementsAnnotatedWith(注解类.class)方法 获取被注解修饰的元素Element 的Set集合
- 遍历集合中Element元素
- 通过集合元素Element对象getEnclosedElements方法获取Element直接包含的子元素Element
- 元素的getKind()方法获取元素类型,其中ElementKind.FIELD表示成员变量
- Element.getAnnotation(注解类.class) 方法获取对应元素的实际注解,不存在则返回null
3、文件读写
-
- 字符流BufferedWriter(new FileWriter())
- 字符串StringBuilder和StringBuffer 节省内存
在早期Hibernate版本中,每写一个Java类文件,还必须额外地维护Hibemate映射文件(名为*.hbm.xml的文件,也有一些工具可以自动生成),下面我们使用注解来模拟简化操作。
TODO:
首先定义要生成Xml需要的三个注解:
1、用于修饰一个类的注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ClassName Presistent * @projectName: object1 * @author: Zhangmingda * @description: 该注解用来修饰数据库一个表 * date: 2021/5/19. */ @Target(ElementType.TYPE) //只能修饰类、接口(包括注解类型)或枚举定义 @Retention(RetentionPolicy.SOURCE) //注解只保留在源代码中,编译器直接丢弃这种注解 public @interface Presistent { String table(); }
2、用于修饰类中属性(变量) 的两个注解
用于标识这是个表格id字段
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ClassName Id * @projectName: object1 * @author: Zhangmingda * @description: 用来修饰字段是否为ID字段,以及特征属性 * date: 2021/5/19. */ @Target(ElementType.FIELD) //只能修饰变量(属性) @Retention(RetentionPolicy.SOURCE) // 只保留在源代码中,编译的时候丢弃 public @interface Id { String column(); String type(); String generator(); }
用于标识该字段的字段名和字段类型
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @ClassName Property * @projectName: object1 * @author: Zhangmingda * @description: 用来修饰普通字段性质 * date: 2021/5/19. */ @Target(ElementType.FIELD) //只能修饰变量,属性 @Retention(RetentionPolicy.SOURCE) // 保留在源代码中,编译时丢弃 public @interface Property { String column(); String type(); }
3、编写编译注解处理工具类
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.Set; /** * @ClassName Apt * @projectName: object1 * @author: Zhangmingda * @description: 注解处理工具类继承AbstractProcessor * date: 2021/5/19. */ @SupportedSourceVersion(SourceVersion.RELEASE_11) //支持的最新java版本 @SupportedAnnotationTypes({"Presistent","Property","Id"}) //可以处理的注解类型 public class Apt extends AbstractProcessor { /** * 该方法在命令行 java -processor Apt (本类类名) User.java时会自动执行 * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { //获取Presistent注解修饰的类 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Presistent.class); //遍历被修饰的类名,注解进行处理 for (Element element: elements){ //获取javax.lang.model.element.Name类名 Name className = element.getSimpleName(); //获取注解对象 Presistent presistent = element.getAnnotation(Presistent.class); /** * 创建我们对应的xml文件 */ try (BufferedWriter bw = new BufferedWriter(new FileWriter(className + "hbm.xml"))){ System.out.println(); //初始字符串初始化 StringBuilder stringBuilder = new StringBuilder("<?xml version=\"1.0\"?>\n<!DOCTYPE hibernate-mapping PUBLIC\n\t\"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n\t\"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd\">\n"); stringBuilder.append("<hibernate-mapping>\n"); //表格维度数据 stringBuilder.append("\t<class name=\"" + className + "\" table=\"" + presistent.table() + "\">\n"); //字段维度//获取所有直接包含的元素 List<? extends Element> fElements = element.getEnclosedElements(); //对所有元素判断是否被对应注解修饰,所有修饰的都处理 for (Element fElement: fElements){ //获取元素种类,如果判断为成员变量,做处理 if (fElement.getKind() == ElementKind.FIELD){ //获取成员变量上的注解 //判断否是ID注解修饰 Id id = fElement.getAnnotation(Id.class); Property property = fElement.getAnnotation(Property.class); if (id != null){ System.out.println(id); System.out.println(fElement.getSimpleName()); stringBuilder.append("\t\t<id name=\"" + fElement.getSimpleName() + "\" column=\"" + id.column() + "\" type=\"" + id.type() + "\">\n"); stringBuilder.append("\t\t\t<generator class=\"" + id.generator() + "\"/>\n"); stringBuilder.append("\t\t</id>\n"); } if (property != null){ System.out.println(property); System.out.println(fElement.getSimpleName()); stringBuilder.append("\t\t<property name=\"" + fElement.getSimpleName() + "\" column=\"" + property.column() + "\" type=\"" + property.type() + "\"/>\n"); } } } //表格维度结束 stringBuilder.append("\t</class>\n"); stringBuilder.append("</hibernate-mapping>"); //写入文件 bw.write(stringBuilder.toString()); } catch (IOException e) { e.printStackTrace(); } } return false; } }
4、数据库User表类
表类用Presistent注解修饰,字段用Id 和Property 注解修饰
/** * @ClassName User * @projectName: object1 * @author: Zhangmingda * @description: 用于生成XML文本的对象,只获取经过修饰符修饰的对象 * date: 2021/5/19. */ @Presistent(table = "user") public class User { @Id(column = "id", type = "int", generator = "auto") private int id; @Property(column = "name", type = "varchar") private String name; @Property(column = "age", type = "varchar") private String age; public User(int id, String name, String age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
用法:IDEA的CMD命令行执行
- 1、javac -encoding utf-8 Apt.java 编译注解处理工具类
- 2、javac -encoding utf-8 -processor Apt User.java 使用注解处理类处理表类,生成xml文件
查看生成的XML文件
<?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="User" table="user"> <id name="id" column="id" type="int"> <generator class="auto"/> </id> <property name="name" column="name" type="varchar"/> <property name="age" column="age" type="varchar"/> </class> </hibernate-mapping>