Java注解提供的一些基本对象/关系映射功能(一)

     如果希望提供一些基本的对象/关系映射功能,能够自动生成数据库表,用以存储JavaBean对象,可以使用XML描述文件,指明类的名字,每个成员以及数据库映射的相关信息,也可以使用注解,将所以的信息保存在JavaBean源文件中。这一点有点类似Hibernate JPA所做的,定义与Bean关联的数据库表的名字,以及与Bean属性关联的列的名字和SQL类型。下面就是这个功能的一些基本实现。

     首先是一个注解的定义,它告诉注解器,生成一个数据库的表。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
	public String name() default "";
}
     在@Target注解中指定了该注解适用于类(数据库表对应的实体类),@DBTable有一个name()元素,为创建的数据库表提供表名。

     接下来就是为修饰该实体类准备的注解。

@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;
}
    注解处理器通过@Constraints注解提取出数据库表的元数据,这里提供约束,数据库数据varchar,int类型注解。注意SQL类型的注解具有name()元素和constraint()元素。后者利用了嵌套注解的功能,将column类型的数据库约束嵌入其中。

    接下来就是一个简单的JavaBean类的定义,应用了以上的注解:

@DBTable(name = "PERSON")
public class Person {
	@SQLString(30) String name;
	@SQLInteger Integer age;
	@SQLString(10) String sex;
	@SQLString(value = 30, constraints = @Constraints(primaryKey = true)) String handle;
	static int count;
	
	public String getName() {
		return name;
	}
	public Integer getAge() {
		return age;
	}
	public String getHandle() {
		return handle;
	}
	public String getSex() {
		return sex;
	}
}
    类的注解@DBTable给了Person,它也作为数据库表的名字。注意handle这个属性的注解,首先handle是一个varchar类型的数据,同时它将成为这张表的主键,所以得同时使用@SQLString和primaryKey元素进行设定。

    Hibernate JPA中使用了单一的注解类column,估计是带了一个enum元素,该枚举定义了String,Integer以及Float等枚举实例。这样消除了每个SQL类型都需要一个@interface定义的负担。

    同样也可以使用多个注解来注解一个域,编译器允许对一个目标同时使用多个注解。但是使用多个注解时,同一个注解不能重复使用。

    下面是一个注解处理器的例子,它将读取一个文件,检查其上的数据库注解,并生成用来创建数据库的SQL命令。

public class TableCreator {
	
	public static void main(String args[]) throws Exception{
		TableCreator tc = new TableCreator();
		String tableCreateSql = tc.createSql("cn.zhouyi.javamindview.program.annotation.Person");
		System.out.println(tableCreateSql);
	}

	public String createSql(String className) throws Exception{
		Class<?> cls = Class.forName(className);
		DBTable dbTable = cls.getAnnotation(DBTable.class);
		if(null == dbTable){
			System.out.println("NO DBTable Annotations in class " + className);
			return null;
		}
		String tableName = dbTable.name();
		if(tableName.length() < 1){
			tableName = cls.getName().toUpperCase();
		}
		List<String> columnsDefs = new ArrayList<String>();
		String tableCreate = null;
		for(Field field : cls.getDeclaredFields()){
			String columnName = null;
			Annotation[] anns = field.getDeclaredAnnotations();
			if(anns.length < 1){
				continue;
			}
			if(anns[0] instanceof SQLString){
				SQLString sString = (SQLString)anns[0];
				if(sString.name().length() < 1){
					columnName = field.getName().toUpperCase();
				}else{
					columnName = sString.name();
				}
				columnsDefs.add(columnName + " VARCHAR(" + sString.value() + ") " + getConstraints(sString.constraints()));
			}
			if(anns[0] instanceof SQLInteger){
				SQLInteger sInt = (SQLInteger)anns[0];
				if(sInt.name().length() < 1){
					columnName = field.getName().toUpperCase();
				}else{
					columnName = sInt.name();
				}
				columnsDefs.add(columnName + " INT " + getConstraints(sInt.constraints()));
			}
			StringBuilder createCommand = new StringBuilder("CREATE TBALE " + tableName +" (");
			for(String columnDef : columnsDefs){
				createCommand.append("\n   " + columnDef + ",");
			}
			tableCreate = createCommand.substring(0, createCommand.length()-1) + " );";
		}
		return tableCreate;
	}
	
	private 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;
	}
}
//output
CREATE TBALE PERSON (
NAME VARCHAR(30) ,
AGE INT ,
SEX VARCHAR(10) ,
HANDLE VARCHAR(30) PRIMARY KEY );

     这里使用Class.forName()方法加载一个类,并使用getAnnotation(DBTable.class)检查该类是否带有@DBTable注解。如果有,就将发现的表名保存下来,然后读取这个类的所有域,并用instanceof来判断这些域的注解是否包含@SQLinteger和@SQLString,如果是又包含的话,在对应的处理块中构造出相应的column名的字符串片段。

     嵌套中的@Constraint注解被传递给getConstraints()方法,由它来负责构建一个包含SQL约束的String对象。

    上述的例子实现了一个简单的对象/关系映射,不过实际上对真实的对象/关系映射而言还远远不够。好了,这么晚了,要睡了,好困!睡觉


     

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值