java编程基础:注解(annotationprocessingtool)注解处理器利用注解解读类属性生成xml文件

zhangmingda      2022-06-05     780

关键词:

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>

 

 

spring5注解编程基础组件

查看详情

spring5注解编程基础组件

查看详情

p4开发实践—编程基础—annotations注解

目录文章目录目录Annotations注解UnstructuredAnnotationsStructuredAnnotations内建Annotations修改可控制实体FQN的AnnotationsAnnotations注解Annotations机制用于在不改变P4语法的前提下,对P4language的功能进行简单扩展的一种方式。P4Annotations使用@语法... 查看详情

p4开发实践—编程基础—annotations注解

目录文章目录目录Annotations注解UnstructuredAnnotationsStructuredAnnotations内建Annotations修改可控制实体FQN的AnnotationsAnnotations注解Annotations机制用于在不改变P4语法的前提下,对P4language的功能进行简单扩展的一种方式。P4Annotations使用@语法... 查看详情

java注解原理面试题,跳槽大厂必看!

...很牢固,因此这份笔记更适合温故而知新。Part2并发编程(架构师筑基必备)并发编程都掌握不好,你凭什么写出优质的代码?大厂必问并发编程技术栈,都在 查看详情

java基础:注解

一、什么是注解简单来说,需要对程序加以@注解名。但注解与注释最大的不同是,它可以被程序读取,有着自己的作用目标,以及保存的范围。二、内置注解@Override@Deprecated@SuppressWarnnings(value=***)这是Java内置的三个注解,意... 查看详情

[java基础]注解概念

查看详情

java基础教程(16)--注解

一.注解基础知识1.注解的格式??最简单的注解就像下面这样:@Entity[email protected]符号指示编译器其后面的内容是注解。在下面的例子中,注解的名称为Override:@OverridevoidsuperMethod(){...}??注解可以有若干个属性。可以在使用注解... 查看详情

深入理解java注解——注解基础(代码片段)

一直以来对Java注解的理解都不是特别深刻,但是在多年的软件开发生涯中接触了不少注解相关的东西,所以有必要深入理解一下Java注解知识,通过本篇博客记录学习Java注解的一些知识点。深入理解Java注解(二&#x... 查看详情

java注解基础入门(代码片段)

...深入的理解,在工作中可以巧妙的使用注解,完善自己对基础知识的理解和使用。目录  1.注解概述    2.注解作用   &n 查看详情

java注解与反射基础

注解与反射基础什么是注解Annotation注解Annotation的作用:不是程序本身,可以对程序做出解释。可以被其他程序(比如编译器等)读取annotation的格式:注解是以”@注释名“再代码中存在的,还可以添加一写参数值,例如@SupperWarn... 查看详情

day383.注解编程-spring5(代码片段)

注解编程⼀、注解基础概念1.什么是注解编程指的是在类或者⽅法上加特定的注解(@XXX),完成特定功能的开发。@ComponentpublicclassXXX2.为什么要讲解注解编程注解开发⽅便代码简洁开发速度⼤⼤提⾼Spring开发潮流Spring2.x引... 查看详情

java语言基础--枚举,注解,正则和反射

注解@Retention(RetentionPolicy.RUNTIME)//注解保留策略public@interfaceMyAnno{Stringstr();intval();}@MyAnno(str="测试注解",val=100)publicvoidtest(){}  所有注解都只包含方法声明,不能提供方法体。应用注解时,需要为注解成员提供值注解的保留策略,... 查看详情

java——零基础速成学习(代码片段)

...础速成实战第二天初识Java入门基础(下)11.网络编程11.1、概述11.2、**网络通信的要素**11.3、IP11.4、端口11.5、通信协议11.5.1**TCPUDP对比**11.6、TCP11.6.1文件上传11.6.2Tomcat11.7、DUP11.7.1发送接收消息11.7.2多线程发送接收消息11.8... 查看详情

大数据必学java基础(八十五):自定义注解

文章目录自定义注解一、如何自定义注解二、注解的内部三、使用注解自定义注解 查看详情

java基础之注解的使用

前言    注解在JDK源码、Spring源码、企业项目中都是运用的非常广泛,JDK源码中比较常见的有@Override、@Deprecated、@SuppressWarnings。我将系统性的介绍一下注解,以及注解的使用。 查看详情

java面试

...多线程需要理解机理(多线程原理和多线程安全)了解网络编程不需要精通,掌握以下知识点,面试基本没有问题。这里没有列举大数据方面的知识点若是有高并发,大数据,程序部署、项目架构的工作经验,如虎添翼Java基础编程... 查看详情

java编程思想之注解

注解(元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后的某个时刻非常方便的使用这些数据。注解在一定程度上是在把元数据与源代码文件结合在一起,而不是保存在外部文档中。注解是众多引入java... 查看详情