博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手把手教你写一个Java的orm框架(3)
阅读量:6928 次
发布时间:2019-06-27

本文共 4679 字,大约阅读时间需要 15 分钟。

使用反射解析class

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

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

现在开始。

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

获取特定的注解

  1. 获取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);}复制代码

  2. 获取属性上的注解
    /** * 获取属性上的注解 * * @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上的注解)@Testpublic void getClassAnnotation() {    Table annotation = EntityUtils.getAnnotation(User.class, Table.class);    System.out.println(annotation.name());}//输出结果user//代码(获取field上的注解)@Testpublic 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的,不包括父类)后,循环遍历一遍,根据每个属性上不同的注解加以区分就好了。这里为了简单,我定义了几个方法:

  1. boolean isTable(Class aClass)是不是添加了@Table
  2. boolean isColumn(Field field)是不是添加了@Column
  3. boolean isId(Field field)是不是添加了@Id

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

for (Field field : clz.getDeclaredFields()) {    if (isColumn(field)) {        //执行需要的操作。    }}复制代码

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

  1. class属性名称与表字段名称的对应。
  2. 表中的id是class中哪一个属性。
  3. 表的字段名称对应的是class里的那个个属性。
  4. 等等~~

代码大致是这样的 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<String, Field> 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了。

我下一篇再写^_^~

转载于:https://juejin.im/post/5c6dfb9451882562547ba7d1

你可能感兴趣的文章
Permutation Descent Counts(递推)
查看>>
Win10-64位 免安装版Mysql8下载安装运行
查看>>
Android自定义组件系列【1】——自定义View及ViewGroup
查看>>
Java XML解析工具 dom4j介绍及使用实例
查看>>
75. 颜色分类
查看>>
Nice Songs
查看>>
C语言中获取系统时间
查看>>
[ POI 2005 ] Bank Notes
查看>>
1、redis安装与启动
查看>>
C++中常用特殊符号简介(& , * , : , :: , ->)
查看>>
mysql分析工具
查看>>
7,数据类型转换,set 集合,和深浅copy
查看>>
任务、进程、线程
查看>>
git 学习
查看>>
GUI自动测试化工具 Ranorex Studio 使用介绍
查看>>
Myeclipse8.6搭建jbpm4.4开发环境
查看>>
Django - 一对多创建
查看>>
TLS1.3&TLS1.2形式化分析(二)
查看>>
学习maven
查看>>
GoF的23种设计模式之行为型模式的特点和分类(1)
查看>>