Thinking in java - 注解(1)

第20章:注解(java.lang.annotation 为Java 编程语言注释设施提供库支持)

综述:
1.注解(也称之为元数据DAD,元数据:描述数据的数据,如定义数据库表的表头数据)
注解为我们在代码中国添加信息提供了一种形式化的方法,使我们在稍后某个时刻非常方便的使用这些数据。

2.注解的产生来源于C#等其他语言给Java造成的语言特性压力而做出的一种回应。

3.注解是JavaSE5的重要语言变化之一。用来完整的描述程序所需要的信息,而这些信息是无法用Java来表达的。因此,注解使得
我们能够有编译器来测试和验证的格式,存储有关程序的额外信息。注解可以用来生成描述符文件,甚至或是新的类定义,并且
有助于减轻编写“样板”代码的负担。注解使得Java代码更加干净易读,编译器类型检查。

4.JavaSE5内置了3中,定义在java.lang中的注解:
4.1 @Override,表示当前中的方法定义将覆盖超类中的方法。
4.2 @Deprecated,如果程序员使用了此注解,那么编译器会发出警告类信息,通常用来标注不建议使用的类,方法等。
4.3 @SuppressWarnings,关闭不当的编译器警告信息。

5.描述符:描述符的英文是descriptor,意思就是描述某个东西的物体。所以套接字描述符,文件描述符,或者中断寄存器描述符
都是一个类似作用的东西,用来描述所引用的对象和对象的一些特性。)

6.每当你创建描述符性质的类或者接口时,一旦其中包含了重复性的工作,那就可以使用注解来简化与自动化该过程。

7.注解的出现,可以替代某些现有的系统。例如:XDolect,它是一个独立的文档化工具,专门用来生成类似注解一样的文件。

package Unit20注解.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 
 *@Test的定义就像一个接口,@interface注解其实就是一个特殊的接口,在编译成class后也会生成class文件。
 *定义接口时,需要一些元注解(meta-annotation),如@Target和@Retention
 *
 *@Target:用来定义注解用于什么地方,(例如用于一个类,还是一个方法,一个域)
 *			ElementType包括以下几种:
 *			1.CONSTRUCTOR : 构造器的声明。
 *			2.FIELD:域声明(包括enum实例)
 *			3.LOCAL_VARIABLE:局部变量声明。
 *			4.METHOD:方法声明
 *			5.PACKAGE:包声明
 *			6.PARANETER:参数声明
 *			7.TYPE:类,接口(包括注解类型)或enum声明
 *
 *@Retention:用来定义注解在哪一个级别可以用(在源代码中(SOURCE),类文件中(CLASS),或者运行时(RUNTIME))
 *
 *@Documented 将此注解包含在Javadoc中。
 *
 *@Inherited 允许类继承父类中的注解。
 *
 *注解的元素就像接口中的方法,唯一的区别就是你可以为其指定默认值。
 *
 *没有元素的注解称为标记注解(Marker annotation)
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
}
package Unit20注解.annotation;
/**
 一下的代码,使用@Test对TestExecute()方法进行注解。该注解本
 身不做任何事情,但是该注解确保在其构建路径上必须有@Test的注解的定义 
 */
public class Testable {

	public void execute(){
		System.out.println("Executing ...");
	}
	@Test void testExecute(){execute();};
}

package Unit20注解.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 *
 * 下面是一个简单的注解,我们可以用它,跟踪项目中的用例。如果一个方法或是一组方法实现了某
 * 	个用例的需求,那么程序员可以为该方法加上改注解。于是,项目经理通过计算已经实现的用例,就可以很好的掌握项目的进展。
 *  而如果要更新或维护系统的业务逻辑,则维护改项目的开发人员也可以很容易的在代码中找到对应的用例。
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {//使用:@UseCase(id = 10,description = "这是一个例子")

	//以下是参数定义
	/*
	 * 注解的元素只可以使用以下几种类型:
	 * 	1.所有基本类型
	 * 	2.String
	 * 3.Class
	 * 4.enum
	 * 5.Annotation
	 * 6.以上类型的数组
	 * 
	 * 	如果你使用过了其他类型,那编译器就会报错。注意,也不允许使用任何其他包装类型,注解作为元素的类型,也就是说
	 * 注解可以嵌套。
	 *
	 * */
	public int id();
	public String description() default "no description";//和接口唯一的区别,可以有默认值
}
package Unit20注解.annotation;

import java.util.List;

public class PasswordUtils {

	@UseCase(id = 47 ,description = "Password  must contain at least ine numeric")
	public boolean validatePassword(String password){//验证密码是否合法
		return (password.matches("\\w*\\d\\w*"));
	}
	
	@UseCase(id = 48)
	public String encryptPassword(String password){//密码加密
		return new StringBuilder(password).reverse().toString();
	}
	
	@UseCase(id = 49 , description = "New password can't equal previously used ones")
	public boolean checkForNewPassword(//
			List<String> prevPassword , String password){
		return !prevPassword.contains(password);
	}
	
}
package Unit20注解.annotation;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UseCaseTracker {//注解处理器

	public static void trackUserCases(
			List<Integer> useCases , Class<?> cl){
		for(Method m : cl.getDeclaredMethods()){//getDeclaredMethods可以反射所有方法,包括私有
			
			UseCase uc = m.getAnnotation(UseCase.class);//获取该方法上的UseCase注解
			
			if(uc!=null){
				System.out.println("Found Use Case : " + uc.id()+" "
						+uc.description());
			
				useCases.remove(new Integer(uc.id()));
			}
		}
		for(int i : useCases)
			System.out.println("Warning : Missing use case -"+i);
	}
	
	public static void main(String[] args){
		List<Integer> useCases = new ArrayList<Integer>();
		Collections.addAll(useCases, 47,48,49,50);
		trackUserCases(useCases, PasswordUtils.class);
	}
}
以下是通过注解,来创建数据库表。

package Unit20注解.annotation.DB;

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)
public @interface DBtable {
	public String name() default  "";
}
package Unit20注解.annotation.DB;

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)
public @interface SQLInteger {//

	String name() default "";
	Constraints constraints() default @Constraints;
}
package Unit20注解.annotation.DB;

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)
public @interface SQLString {
	int value() default 0;
	String name() default "";
	Constraints constraints() default @Constraints;//注解嵌套
}
package Unit20注解.annotation.DB;


public @interface Uniqueness {
	Constraints constraints()
		default @Constraints(unique = true);
}
package Unit20注解.annotation.DB;

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)
public @interface Constraints {//主键的注解
	boolean primaryKey() default false;
	boolean allowNull() default true;
	boolean unique() default false;
}
package Unit20注解.annotation.DB;

@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;}
	public String toString(){return handle;}
}
package Unit20注解.annotation.DB;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class TableCreator {

		public static void main(String[] args) throws Exception{
			
			//System.out.println(System);
			
			args= new String[]{"Unit20注解.annotation.DB.Member"};
			 
			//Class.forName(args[0]);
			
			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);
				
				if(dbTable == null){
					System.out.println(
							"No DBTable annotations in class "+ className);
					continue;
				}
				
				String tableName = dbTable.name();
				
				//if the name is empty , use the class 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 sInt = (SQLInteger) anns[0];
						//Use field name , if naem not specified
						
						if(sInt.name().length() < 1)
							columnName = field.getName().toUpperCase();
						else
							columnName = sInt.name();
						
						columnDefs.add(columnName+ " INT"+
								getConstraints(sInt.constraints())); 
					}
					
					
					if(anns[0] instanceof SQLString){
						SQLString sString = (SQLString) anns[0];
						//Use field name if name not specified
						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+",");
					
					}
						//remove trailing comma
					String tableCreate = createCommand.substring(0 , createCommand.length()-1)+");";
					
					System.out.println("Table Creation SQL for "+
							className + " is : \n"+ tableCreate);
				}
				
			}
			
		}
		
		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;
		}
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值