Java注解

1 总览

注解(也被称为原数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后的某个时刻非常方便的使用这些数据。 —《 java编程思想》

在这里插入图片描述

注解是jdk1.5引入的,目的是:

2 Java中的注解

2.1 java自带的注解

注解名称解释
@Override覆盖超类中的方法。用于检查是否覆盖成功,当没有覆盖上超类的方法,编译器就会报错
@Deprecated带该注解的方法编译器会发出警告,一般用于某个方法过时了
@SuppressWarnings关闭不当的编译器警告信息

2.2 Java元注解

元注解用于开发自定义注解。

注解名称用途
@Retention定义注解的保留策略
@Target定义注解的作用目标
@Documentt说明该注解将被包含在javadoc中
@Inherited说明子类可以继承父类中的该注解

@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

@Target(ElementType.TYPE) // 接口、类、枚举、注解
@Target(ElementType.FIELD) // 字段、枚举的常量
@Target(ElementType.METHOD) // 方法
@Target(ElementType.PARAMETER) // 方法参数
@Target(ElementType.CONSTRUCTOR) // 构造函数
@Target(ElementType.LOCAL_VARIABLE) // 局部变量
@Target(ElementType.ANNOTATION_TYPE) // 注解
@Target(ElementType.PACKAGE) // 包

2.3 第三方注解

常用框架的注解,这里先不添加

  1. Spring -
  2. SpringMVC -
  3. Mybatis -
  4. Hibernate -
  5. Struts2 -

3 开发自定义注解

3.1 注解定义

我们以编程思想中的一个自动生成数据库表例子为例,当然这个例子过于简单并不实用。主要是掌握注解的定义和如何运用反射+注解相关api来编写注解处理器。
1 先定义相关注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
	public String name() default "";
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
	boolean primaryKey() default false;

	boolean allowNull() default true;

	boolean unique() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
	int value() default 0;
	String name() default "";
	Constraints constraints() default @Constraints;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {

	String name() default "";
	Constraints constraints() default @Constraints;
}
public @interface Uniqueness {
	Constraints constraints() default @Constraints(unique=true);
}

2 给Bean类添加注解
我们希望通过给bean添加注解,能够直接生成对应的数据库表,完成自动的关系映射。

@DBTable(name = "MEMBER")
public class Member {
	@SQLString(30)
	String firstName;
	@SQLString(50)
	String lastName;
	@SQLInteger
	Integer age;
	@SQLString(value = 30, constraints = @Constraints(primaryKey = true))
	String handle;
	static int memberCount;

	public String getHandle() {
		return handle;
	}

	public String getFirstName() {
		return firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public Integer getAge() {
		return age;
	}

	@Override
	public String toString() {
		return handle;
	}

}

3 注解处理器
定义了注解,在bean类中添加了注解,现在我们必须有处理器处理这些注解。

public class TableCreator {
	public static void main(String[] args) throws Exception {
		// 如果没有参数,直接返回
		if (args.length < 1) {
			System.out.println("arguments: annotated classes");
			System.exit(0);
		}

		for (String className : args) {
			Class<?> cl = Class.forName(className); // 从类的全限定名字符串参数获取类对象
			DBTable dbTable = cl.getAnnotation(DBTable.class); // 获取一下DBTable.class注解对象

			if (dbTable == null) { // 如果是空的说明没有获取到
				System.out.println("No DBTable annotations n class "
						+ className);
				continue;
			}

			String tableName = dbTable.name(); // 获取表名
			if (tableName.length() < 1) { // 如果没获取到,就默认使用类名大小当表名
				tableName = cl.getName().toUpperCase();
			}
			
			List<String> columnDefs = new ArrayList<String>();
			for (Field field : cl.getDeclaredFields()) { // 获取成员
				String columnName = null;
				Annotation[] anns = field.getDeclaredAnnotations(); // 获取成员上的注解
				if (anns.length < 1) // 没有注解就继续找下一个字段
					continue;

				if (anns[0] instanceof SQLInteger) { // 如果是SQLInteger注解
					SQLInteger sInt = (SQLInteger) anns[0]; // 强转
					if (sInt.name().length() < 1) {
						columnName = field.getName().toUpperCase(); // 默认使用成员变量名称作为字段名
					} else {
						columnName = sInt.name(); 
					}
					columnDefs.add(columnName + " INT"
							+ getConstraints(sInt.constraints())); // getConstraints()
				}

				if (anns[0] instanceof SQLString) {
					SQLString sString = (SQLString) anns[0];
					if (sString.name().length() < 1) {
						columnName = field.getName().toUpperCase();
					} else {
						columnName = sString.name();
					}
					columnDefs.add(columnName + " VARCHAR(" + sString.value()
							+ ")" + getConstraints(sString.constraints()));
				}
				
				// 下面是构造一个数据库字段
				StringBuilder createCommand = new StringBuilder(
						" CREATE TABLE " + tableName + "(");
				for (String columnDef : columnDefs) {
					createCommand.append("\n    " + columnDef + ",");
				}
				String tableCreate = createCommand.substring(0,
						createCommand.length() - 1)
						+ ");";
				System.out.println("Table Creation SQL for " + className
						+ " is :\n" + tableCreate);

			}

		}

	}

	/**
	 * 根据Contraints对象,返回一个约束条件字符串
	 * 
	 * @param con
	 * @return 字段约束字符串
	 */
	private static String getConstraints(Constraints con) {
		String constraints = "";
		if (!con.allowNull()) {
			constraints += " NOT NULL";
		}
		if (con.primaryKey()) {
			constraints += " PRIMARY KEY";
		}
		if (con.unique()) {
			constraints += " UNIQUE";
		}
		return constraints;
	}
}

该处理器首先拿到一个要处理的类的全限定名,通过反射Class<?> cl = Class.forName(className);拿到class对象,通过DBTable dbTable = cl.getAnnotation(DBTable.class);拿到在类上注解的DBTable注解对象,对其进行解析获得要生成的数据库表名。
通过反射cl.getDeclaredFields()拿到该类的所有成员,然后遍历每个成员上的注解。代码Annotation[] anns = field.getDeclaredAnnotations();可以拿到一个成员上的所有注解,返回Annotation数组,本例每个成员上只有一个注解,所以我们直接解析anns[0],先用instanceof判断注解类型后将其强转,然后通过强转得到的注解对象拿到他的各个属性。根据属性我们就可以设置数据库表中字段名称,类型和限制条件了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值