跟我一起写ORM(一)————–窥视java标注声明

   好久都没有更新博客了,来学校之后一大堆的事.第一个星期完成物品管理系统的第一版,连续7,8天都从早上写代码到熄灯,三天时间学会Bootstrap,写前台,三天时间写后台,再有两天debug.第二个星期都忘了弄了什么了,第三个星期又忙着弄实习简历,现在终于有时间写点东西了.

   跟我一起写ORM,主要是针对之前我参考了JFinal和ETMVC部分源码写的一个叫qm86-ar的简单的ORM,源码已经上传GitHub(这里是链接)上了.由于之前有用Hibernate之类的ORM,觉得配置比较麻烦,JFinal的ORM部分又不够灵活,JFinal里Model中的对象属性名必须与DB中表的属性名字一样,这样的设计让我这个喜欢把列名写得很长的人感到很尴尬,要取值的时候还得写一长串的名字我实在受不了了.所以在挣扎了一段时间后我决定自己写一个ORM,于是乎需求来了.

功能需求:

  1. ORM,映射数据库表

  2. 基本的CRUD

  3. 声明式创建映射对象和对象属性,可以自由设置对象和属性的名字

  4. 声明式事务

举个例子说,就是像下面写的这样:

@Table(name = "tb_TestTable")

public class TestTable extends ActiveRecordBase{

   @Id(name = "tb_id")

   private int id;

   @Column

   private String name;

   @Column(name = "address")

   private String where;

   @Column

   private java.util.Date when;

(Some getters and setters)

}

@Table标注用来声明表映射到的model对象,表名为tb_testtable,由@Table的name属性指定,如果不写name属性,则缺省的以model对象的名字来查询数据库的表

@Id标注用来声明表中的主键,如果不写name属性则缺省以所声明的变量名为主键查询,上面例子中,如果把(name = "tb_id")删除,ORM就认为id是表中的主键名

@Column标注用来声明表中除主键外其它列的名字,用法和@Id相同

此外还有一些@ManyToOne,@OneToOne,@OneToMany标注以后再说吧

那如果实现标注声明呢?看看我写的源码在com.qm86.ar.annotation包下包含的就是标注的代码

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Column {

String name() default "_null";

}

这里标注的修饰也是用标注来实现的(汗~~).要对声明一个标注需要用@interface关键字,注意不是interface哦.

@interface上面的@Target标注是用来说明你所声明的标注(Column)修饰对象的范围,若为ElementType.FIELD,说明这个标注Column可以用来声明成员变量,若是ElememtType.METHOD自然是用来声明方法,ElementType.TYPE用来声明类,接口或者是枚举类型,参照上例的@Table,其它的看看API就懂了,@Target还可以有多种修饰例如@Target(ElementType.FIELD,ElememtType.METHOD)

@Retention定义了这个标注被保留的时长,有些标注只出现在源码中用RetentionPolicy.SOURCE修饰,编译源码时并不编译到它,有些标注只存在.class文件中用RetentionPolicy.CLASS修饰,JVM并不运行它,默认情况下用的是这种修饰,还有些标注JVM可以运行它,它可以用作反射机制中,它用RetentionPolicy.RUNTIME修饰.啥是反射机制?哈哈,慢慢来,我们马上就要讲到了.

现在标注声明好了,我们还可以为标注添加属性,来看上例中String name() default "_null"就是Column标注的一个属性,你也许会感到疑惑,声明的属性怎么还带有()?它是个方法吗?NONONO,它是一个变量,类型是String,java在这里允许这个变量后有(),并且可以给它设一个默认值,用default.用不加那个()可以不?我测试过是可以的,只是设默认值时不能和default,必须用=.加()的好处?我也不知道…我估计是在调用这个属性时用()看上去会舒服点?getAnnotation(Column.class).name和getAnnotation(Column.class).name()(顺便吐槽一下C#,我到现在还弄不清楚C#里访问属性的时什么时候用()什么时候不用…).

若这个属性的名字是value时,调用标注来声明的时候可以简写,比如

public @interface Column {

String value();

}

调用时可以用@Column(value = "xxxx")也可以@Column("xxxx"),注意在调用时属性是不能带()的,不能写成@Column(name() = "XXX")

现在你就可以调用标注声明了,先讲到这吧,后面一节要讲的是反射机制哦~

Leave a Reply

Your email address will not be published. Required fields are marked *