Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)
如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用。读取注解的工具叫作注解处理器。Java提供了两种方式来处理注解:第一种是利用运行时反射机制;另一种是使用Java提供的API来处理编译期的注解。
反射机制方式的注解处理器
仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解。下面结合例子来说明这种方式的处理方法。
Java中的反射API(如java.lang.Class、java.lang.reflect.Field等)都实现了接口java.lang.reflect.AnnotatedElement,来提供获取类、方法和域上的注解的实用方法。
通过JavaBean上定义的注解来生成相应的SQL。
1.1、定义注解
1.1.1、类注解映射表名
package com.zenfery.example.annotation.sql; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (ElementType.TYPE) //定义注解应用于类 @Retention (RetentionPolicy.RUNTIME) //定义注解在JVM运行时保留 public @interface TableSQL { String value() default "" ; //指定对应的表名 } |
定义注解@TableSQL,只定义一个value值来映射表名,默认值为空,如果程序不给此值,将使用类名(小写)来作为表名。
1.1.2、属性与字段对应注解
package com.zenfery.example.annotation.sql; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (ElementType.FIELD) //定义注解应用于成员变量 @Retention (RetentionPolicy.RUNTIME) //定义注解在JVM运行时保留 public @interface TableColumnSQL { String value() default "" ; Constraint constraint() default @Constraint (); } |
定义注解@TableColumnSQL的目标为FIELD,仅能在类的属性上使用;value()属性定义对应的字段名;constraint()定义字段的约束,它是由注解@Constraint定义,其定义如下:
package com.zenfery.example.annotation.sql; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target (ElementType.FIELD) //定义注解应用于成员变量 @Retention (RetentionPolicy.RUNTIME) //定义注解在JVM运行时保留 public @interface Constraint { boolean allowNull() default true ; //是否允许为空 boolean isPrimary() default false ; //是否为主键 } |
@Constraint注解仅定义了两个注解元素,allowNull()指定字段是否允许为空值;isPrimary()指定字段是否是主键。
1.2、定义JavaBean
package com.zenfery.example.annotation.clazz; import com.zenfery.example.annotation.sql.Constraint; import com.zenfery.example.annotation.sql.TableColumnSQL; import com.zenfery.example.annotation.sql.TableSQL; /** * 定义User类与数据库映射 * @author zenfery */ @TableSQL () public class User { //定义id字段,与表user的列id相映射,指定约束为:不为空,为主键。 @TableColumnSQL (value= "id" ,constraint= @Constraint (allowNull= false ,isPrimary= true )) String id; //只为注解指定value字段,可省略value。 @TableColumnSQL ( "name" ) String name; } |
定义User类。类上使用@TableSQL来注解映射表名;字段id和name使用@TableColumnSQL来注解映射字段名。
1.2、注解处理器
在以上工作做完后,注解没有任何意义(它没有做任何事情),下面来为RUNTIME级别的注解来编写处理器,在此编写的处理器和真实的处理器相差比较多,无通用性,仅为演示理解用。详细代码如下:
package com.zenfery.example.annotation.clazz; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import com.zenfery.example.annotation.sql.Constraint; import com.zenfery.example.annotation.sql.TableColumnSQL; import com.zenfery.example.annotation.sql.TableSQL; public class TableSQLHandler { /** * 注解处理器:读取User类中注解,生成对应的SQL并打印出来 * 在此假设表的所有字段均为varchar(10) * @since JDK 1.6 * @param args */ public static void main(String[] args) { /** * 注解的@Retention均为JVM保留注解(RetentionPolicy.RUNTIME) * ,在此直接使用main方法启动JVM,通过Java提供的反射机制来处 * 理。 */ try { //指定在JVM需要处理注解的类 Class userClass = null ; //userClass = Class.forName("com.zenfery.example.annotation.clazz.User"); userClass = User. class ; //打印所有类的注解 Annotation[] annotations = userClass.getDeclaredAnnotations(); for ( int i= 0 ; i<annotations.length; i++){ System.out.println( "注解[" +(i+ 1 )+ "] = " +annotations[i].toString()); } //检查类是否有@TableSQL注解 if ( userClass.isAnnotationPresent(TableSQL. class ) ){ //sql String sql = "\nCREATE TABLE " ; //注解了TableSQL注解 TableSQL ts = (TableSQL)userClass.getAnnotation(TableSQL. class ); String tableName = ts.value(); if ( "" .equals(tableName)){ //如果获取的值为TableSQL的默认值,则使用类名来做为表名 tableName = userClass.getSimpleName().toLowerCase(); } System.out.println( "获取" +userClass.getName()+ "对应的表名为:" +tableName); sql += tableName + " ( \n" ; //从User类的属性中获取需要与数据库映射的字段 Field[] fields = userClass.getDeclaredFields(); List<String> primaryKeys = new ArrayList<String>(); //存储主键 for ( int i= 0 ; i<fields.length; i++){ Field field = fields[i]; if ( field.isAnnotationPresent(TableColumnSQL. class ) ){ TableColumnSQL tcs = (TableColumnSQL)field.getAnnotation(TableColumnSQL. class ); String fieldName = tcs.value(); //表中的字段名 Constraint c = tcs.constraint(); //字段对应的约束 boolean allowNull = c.allowNull(); //是否可为空 boolean isPrimary = c.isPrimary(); //是否为主键 //拼接SQL sql += "\t" + fieldName + " VARCHAR(10)" ; if (!allowNull) sql += " NOT NULL" ; //不允许为空 if (i<fields.length- 1 ) sql+= ",\n" ; //主键 if (isPrimary) primaryKeys.add(fieldName); } else { System.out.println( "字段" +field.getName()+ "未使用注解@TableColumnSQL!" ); } } if (primaryKeys.size()> 0 ){ StringBuilder keys = new StringBuilder(); for ( int k= 0 ; k<primaryKeys.size(); k++){ keys.append(primaryKeys.get(k)); if (k<primaryKeys.size()- 1 )keys.append( "," ); } sql += ",\n\tPRIMARY KEY " +keys.toString(); } sql += "\n) DEFAULT CHARSET=utf8" ; // ====> 打印SQL System.out.println( "生成的SQL:" +sql); } else { System.out.println( "警告:" +userClass.getName()+ "未使用@TableSQL注解!" ); } } catch (Exception e) { e.printStackTrace(); } } } |
- 获取使用了注解的User类。
- 根据类上的注解@TableSQL获取表名。
- 根据类中所有的字段上的注解@TableColumnSQL来获取字段名,并获取字段的特性。
- 根据获取的表名和字段名拼接SQL。
- 打印SQL。
运行TableSQLHandler的main()方法,输出:
注解[1] = @com.zenfery.example.annotation.sql.TableSQL(value=) 获取com.zenfery.example.annotation.clazz.User对应的表名为:user 生成的SQL: CREATE TABLE user ( id VARCHAR(10) NOT NULL, name VARCHAR(10), PRIMARY KEY id ) DEFAULT CHARSET=utf8 |
转载请注明:子暃之路 » Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)
Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)的更多相关文章
- Android中的自定义注解(反射实现-运行时注解)
预备知识: Java注解基础 Java反射原理 Java动态代理 一.布局文件的注解 我们在Android开发的时候,总是会写到setContentView方法,为了避免每次都写重复的代码,我们需要使 ...
- java 常用类库:操作系统System类,运行时环境Runtime
System类: System 类代表Java程序的运行平台,程序不能创建System类的对象, System类提供了一些类变量和类方法,允许直接通过 System 类来调用这些类变量和类方法. Sy ...
- Java 反射(二)运行时获取类的信息
目录 一.获得类的运行时结构 1. 获得类的名字 2. 获得类的属性 获取属性列表 获取指定属性 3. 获取类的方法 获得类的方法列表 获得指定方法 4. 获得的构造器 获得构造器列表 获得指定构造器 ...
- 通过SOFA看Java服务端如何实现运行时的模块化
本文阅读时间大约7分钟. 今天我们谈谈SOFA模块化,首先看一段SOFA的介绍: SOFABoot是蚂蚁金服开源的基于Spring Boot的研发框架,它在Spring Boot的基础上,提供了诸如 ...
- Java中获取类的运行时结构
获取运行时类的完整结构 通过反射获取运行时类的完整结构 Field(属性).Method(方法).Constructor(构造器).Superclass(父类).Interface(接口).Annot ...
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- Java虚拟机 - 结构原理与运行时数据区域
http://liuwangshu.cn/java/jvm/1-runtime-data-area.html 前言 本来计划要写Android内存优化的,觉得有必要在此之前介绍一下Java虚拟机的相关 ...
- iOS运行时编程(Runtime Programming)和Java的反射机制对比
运行时进行编程,类似Java的反射.运行时编程和Java反射的对比如下: 1.相同点 都可以实现的功能:获取类信息.属性设置获取.类的动态加载(NSClassFromString(@“clas ...
- Java源文件编译成功但是运行时加载不到文件
最近系统重装了一些,Java等环境变量都需要重新配置,配置好以后编写了一个Java源文件编译了一下,通过Javac编译源文件,编译成功,但是再通过Java运行时没找到报出找不到加载文件或者加载文件不存 ...
随机推荐
- FusionWidgets DrawingPad图
1.数据源 DrawingPad.xml: <?xml version="1.0" encoding="UTF-8"?> <chart bgC ...
- zTree实现地市县三级级联报错(二)
zTree实现地市县三级级联 1.具体报错如下 2014-05-10 23:29:13 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolT ...
- CentOS6.5 [ERROR] /usr/libexec/mysqld: Can't create/write to file '/var/lib/mysqld/mysqld.pid' (Errcode: 2)
环境是CentOS6.5,先贴个错误代码: 这个问题解决了大半天,浪费了好多时间,不过也算是值了. 事故起因是因为突然断电,mysql server直接干掉了,也没有备用电源,重启了之后看日志tail ...
- 转:SQL进阶之变量、事务、存储过程与触发器
一.变量那点事儿 1.1 局部变量 (1)声明局部变量 DECLARE @变量名 数据类型 DECLARE @name varchar(20) DECLARE @id int (2)为变量赋值 SET ...
- C#多线程编程(5)--线程安全1
当你需要2个线程读写同一个数据时,就需要数据同步.线程同步的办法有:(1)原子操作:(2)锁.原子操作能够保证该操作在CPU内核中不会被"拆分",锁能够保证只有一个线程访问该数据, ...
- JavaScript保留关键字2。
一些不做解释的关键字是在js中预留的东西. abstract 抽象 . arguments 参数 标识符arguments是指向实参对象的引用,实参对象是一个类数组对象. boolean 布尔值. ...
- 【UOJ207】共价大爷游长沙(Link-Cut Tree,随机化)
[UOJ207]共价大爷游长沙(Link-Cut Tree,随机化) 题面 UOJ 题解 这题太神了 \(\%\%\%myy\) 看到动态的维护边很容易的想到了\(LCT\) 然后能否堵住一条路 我们 ...
- [Luogu3066][USACO12DEC]逃跑的BarnRunning Away From…
题面 题目描述 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于l的点有多少个. 输入格式: Line 1: 2 integers, N and L (1 <= N <= 2 ...
- 两种插入排序算法java实现
两种方法都编译运行通过,可以当做排序类直接使用. 折半插入排序: public class Sort1 { public static void main(String[] args) { Inser ...
- ISAPI和CGI限制中没有ASP.NET v4.0
[服务器搭建]ISAPI和CGI限制中没有ASP.NET v4.0解决方式: 1.确保安装IIS时确实安装了ASP.NET,如果没有的话,勾上重新装一下,一般出现404.2时这么干 2.如果你是先装了 ...