Java Annotation
一:简介
注解在日常开发中的应用之处很多、比如基于注解的Spring、SpringMVC的注解形式更是大大减少了XML配置文件的数量、和提高了代码书写的效率、还有Spring中注解形式的AOP的使用、对@AspectJ的支持等。理解Java中的Annotation的工作原理、语法以及如何使用Annotation更有益与学习各种框架中注解形式的理解和使用。
二:Annotation概念
Annotation,是Java语言中的一种特殊的元数据语法,可以被添加到Java代码中。类,方法,变量,参数,包都可以被标注。与Javadoc的标签不同,注解是可以被反射的,因为他们被编译器生成嵌入在 编译后文件,并保留在虚拟机中以便在运行时被索引。其是从Java SE5开始引入。
三:Java Annotation分类
1.五种Java中内置注解:
a) @Override :使用与方法级别、用于校验此方法是从父类或者接口中重写的方法。如果不符合重写标准则在编译期会报错。
b) @Deprecated :标识一个元素已经过时、并给出编译期警告。
c) @SuppressWarnings :关闭当我们使用不适当的类型、或者代码中有未使用的元素是的编译警告。比如在类中定义了一个变、或者方法、但是没有在任何地方使用或者调用他们、那么编译器一般会给出黄色下划线或者标志来给出警告、JavaSE5 以前不支持此属性。
d) @SafeVarargs : 关闭一个含有泛型的可变参数的方法或者构造器被调用时给出的编译期警告。Java 7 新增注解。
e) @FunctionalInterface :声明指定类型是函数接口。Java8 新特性。
2.四种元注解
a) @Target : 指定注解在类中可以使用的层次、如下:
i. COUNSTRUCTOR : 构造方法。
ii. FIELD :属性。
iii. LOCAL_VARIABLE :局部变量
iv. PACKAGE : 包
v. TYPE : 类、接口或者枚举
vi. PARAMETER :参数
b) @Retetion : 作用域、提供如下策略、RetentionPolicy.
i. SOURCE: 这个Annotation类型的信息只会保留在源码里,源码经过编译之后,Annotation的数据就会消失,并不会保留在编译好的.class文件里;
ii. CLASS : 这个Annotation类型的信息在源码保留,在.class文件也保留,但不会把这些信息加载到虚拟机(JVM)中,如果不设置,系统默认值是CLASS;
iii. RUNTIME :在源码,编译后的.class都保存信息,在执行的时候也会把这些信息加载到JVM中、可以使用反射机制获取其信息来做进一步处理、也是最常用的。
c) @Inherited : 允许子类继承父类注解
d) @Documented :将此Annotation生成Javadocs。
补充:
所有的Annotation类型默认实现了Annotation接口,Inherited注解。它们都使用了@Documented,@Documented的目的就是让这一个Annotation类型的信息能够显示在javaAPI说明文档上;没有添加的话,使用javadoc生成API文档的时候就会找不到这一个类型生成的信息.
四:元Annotation以及其相关源码浏览:
1.@Target:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
2.@Retetion:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
3.@Inherited:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
4.@Documented:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
5.ElementType:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE
}
6.RetetionPolicy:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
五:自定义注解生成Table创建语句
关键类:与Table对应的DTO——Member:
package org.andy.items.thkinjava.annotations;
/**
* Happy day, happy life.
*
* @author andy
* @version 1.0-SNAPSHOT
* Created date: 2014-11-26 19:37
*/
@SuppressWarnings("unused")
@DBTable(name = "MEMBER")
public class Member {
@SQLString(30)
private String firstName;
@SQLString(50)
private String lastName;
@SQLInteger
private Integer age;
@SQLString(value = 30,constraints = @Constraints(primaryKey = true))
private String handle;
private static int count;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Integer getAge() {
return age;
}
public String getHandle() {
return handle;
}
}
根据Member类中使用的关于创建表时使用的Annotation的值、使用反射构造建表语句的类——TableCreator:
package org.andy.items.thkinjava.annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Happy day, happy life.
*
* @author andy
* @version 1.0-SNAPSHOT
* Created date: 2014-11-26 19:47
*/
public class TableCreator {
public static void createTable(Class<?> ... classes) {
for (Class cl : classes) {
DBTable dbTable = (DBTable) cl.getAnnotation(DBTable.class);
if (dbTable == null) {
System.out.println("db table of class : " + cl.getName() + " is required.");
continue;
}
String tableName = dbTable.name();
//if the table name is empty, use the class name;
if (tableName.length() < 1) {
tableName = cl.getSimpleName().toUpperCase();
}
List<String> columnDefs = new ArrayList<String>();
for (Field field : cl.getDeclaredFields()) {
String columnName;
Annotation[] annotations = field.getAnnotations();
if (annotations.length < 1) {
continue;
}
if (annotations[0] instanceof SQLInteger) {
SQLInteger sqlInteger = (SQLInteger) annotations[0];
//use field name if name not specified
if (sqlInteger.name().length() < 1) {
columnName = field.getName().toUpperCase();
} else {
columnName = sqlInteger.name();
}
columnDefs.add(columnName + " INT" + getConstraints(sqlInteger.constraints()));
}
if (annotations[0] instanceof SQLString) {
SQLString sqlString = (SQLString)annotations[0];
if (sqlString.name().length() < 1) {
columnName = field.getName().toUpperCase();
} else {
columnName = sqlString.name();
}
columnDefs.add(columnName + " VARCHAR(" +
sqlString.value() + ")" +
getConstraints(sqlString.constraints()));
}
StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
for(String columnDef : columnDefs) {
createCommand.append("\n ").append(columnDef).append(",");
}
// Remove trailing comma
String tableCreate = createCommand.substring(
0, createCommand.length() - 1) + ");";
System.out.println("Table Creation SQL for " +
cl.getSimpleName() + " is :\n" + tableCreate);
}
}
}
private static String getConstraints(Constraints con) {
String constraints = "";
if (!con.allowNull()) {
constraints += "NOT NULL";
}
if (con.foreignKey()) {
constraints += "FOREIGN KEY";
}
if (con.primaryKey()) {
constraints += "PRIMARY KEY";
}
if (con.unique()) {
constraints +="UNIQUE";
}
return constraints;
}
}
其他类见:github相关源码。地址:源码github地址