mysql java orm_手把手教你写一个java的orm(三)

使用反射解析class

上一篇我们完成了class到表映射关系的建立,但是这个并不能被代码正确处理,我们还需要让程序能够正确的识别这些映射关系。

这一篇主要讲的是建立一个从class到表的模型,使我们在class上添加的注解能够正确的被识别并处理。这里主要用到的是java中的反射相关的知识。不了解的同学请自行百度一下,不是很难~,另外这一篇也会稍微的提到一点反射的用法。

现在开始。

我们主要的需求是根绝我们添加的注解,生成各种类型的sql语句,所以我们首先要能够获取添加在java类名,属性,方法上的注解,并获取注解中的值。所以第一步:

获取特定的注解

获取class上的注解

在Java的Class中提供了.getAnnotation(annotationClass)的方法,

这里我在这个方法的基础上包了一层,主要是使用断言做了一些验证,在验证不通过的时候抛出我认识的异常信息。下面的方法都是如此处理的。

/**

* 获取类上的注解

*

* @param clz

* @param annotationClass

* @param

* @return

*/

public static T getAnnotation(Class> clz, Class annotationClass) {

Assert.notNull(clz, CLASS_NOT_NULL);

Assert.notNull(annotationClass, ANNOTATIONCLASS_NOT_NULL);

return clz.getAnnotation(annotationClass);

}

获取属性上的注解

/**

* 获取属性上的注解

*

* @param field

* @param annotationClass

* @param

* @return

*/

public static T getAnnotation(Field field, Class annotationClass) {

Assert.notNull(field, FIELD_NOT_NULL);

Assert.notNull(annotationClass, ANNOTATIONCLASS_NOT_NULL);

return field.getAnnotation(annotationClass);

}

这里我们获取注解的方法就写完了,可以通过这些方法获取我们需要的注解,并通过获取到的注解拿到其中的值。

大致是这样的:(这里的User.class)可以看 上一篇。

//代码(获取class上的注解)

@Test

public void getClassAnnotation() {

Table annotation = EntityUtils.getAnnotation(User.class, Table.class);

System.out.println(annotation.name());

}

//输出结果

user

//代码(获取field上的注解)

@Test

public void getFieldAnnotation() throws NoSuchFieldException {

Class userClass = User.class;

//getDeclaredField和getField是有一定区别的,这里用getDeclaredField

Field field = userClass.getDeclaredField("createDate");

Column annotation = EntityUtils.getAnnotation(field, Column.class);

System.out.println(annotation.name());

}

//输出结果

create_date

这样就可以获取到我们在class上添加的注解,以及注解中的值了。下面是第二步

获取Id以及Column

这里依然是通过反射实现,主要就是获取到这个class中的所有的属性(只属于这个class的,不包括父类)后,循环遍历一遍,根据每个属性上不同的注解加以区分就好了。这里为了简单,我定义了几个方法:

boolean isTable(Class aClass)

是不是添加了@Table

boolean isColumn(Field field)

是不是添加了@Column

boolean isId(Field field)

是不是添加了@Id

这几个方法的具体代码我就不贴出来了,很简单的。下面是取出一个class中所有属性的代码:

for (Field field : clz.getDeclaredFields()) {

if (isColumn(field)) {

//执行需要的操作。

}

}

在这个遍历个过程中我们可以新建一个类,里面用来存放表和class的各种对应关系。比如:

class属性名称与表字段名称的对应。

表中的id是class中哪一个属性。

表的字段名称对应的是class里的那个个属性。

等等~~

代码大致是这样的 EntityTableRowMapper.java:

/**

* id的字段名称

*/

private String idName = null;

/**

* table对应的class

*/

private Class tableClass = null;

/**

* 对应的数据库名称

*/

private String tableName = null;

/**

* 表中所有的字段

*/

private Set columnNames = null;

/**

* 表中所有的字段对应的属性名称

*/

private Set fieldNames = null;

/**

* 属性名称和数据库字段名的映射

* K: 属性名

* V:表字段名称

*/

private Map fieldNameColumnMapper = null;

/**

* 数据库字段名和class属性的映射

* K:表字段名称

* V:class属性

*/

private Map columnFieldMapper = null;

这些用来描述表和class之间的关系就已经够用了。只要按照关系将里面的数据一一填充完毕就好。我写了一个方法来填充这些数据,代码是这样的:

//这里只是示例

Class clz = User.class();

//这里是主要代码

EntityTableRowMapper mapper = new EntityTableRowMapper();

Map columnFieldMap = EntityUtils.columnFieldMap(clz);

int size = columnFieldMap.size();

Map fieldNameColumnMapper = new HashMap<>(size);

Set columnNames = new HashSet<>(size);

Set fieldNames = new HashSet<>(size);

mapper.setTableClass(clz);

mapper.setTableName(EntityUtils.tableName(clz));

mapper.setIdName(EntityUtils.idColumnName(clz));

mapper.setColumnFieldMapper(columnFieldMap);

for (Map.Entry entry : columnFieldMap.entrySet()) {

String columnName = entry.getKey();

Field field = entry.getValue();

String fieldName = field.getName();

fieldNameColumnMapper.put(fieldName, columnName);

fieldNames.add(fieldName);

columnNames.add(columnName);

}

mapper.setColumnNames(columnNames);

mapper.setFieldNameColumnMapper(fieldNameColumnMapper);

mapper.setFieldNames(fieldNames);

这里漏了一个Map columnFieldMap = EntityUtils.columnFieldMap(clz);的代码,在下面补上:

/**

* 获取Table的列名与Entity属性的映射Map

*

* @param clz

* @param

* @return

*/

public static Map columnFieldMap(Class clz) {

Field[] declaredFields = clz.getDeclaredFields();

Map map = new HashMap<>(declaredFields.length);

for (Field field : declaredFields) {

if (isColumn(field)) {

map.put(columnName(field), field);

}

}

return map;

}

这时候,解析class里面的工作就完成了,下一步就是要通过拿到的数据来拼装sql了。

我下一篇再写_~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值