Mybatis框架基础支持层——反射工具箱之MetaClass(7)
简介:MetaClass是Mybatis对类级别的元信息的封装和处理,通过与属性工具类的结合, 实现了对复杂表达式的解析,实现了获取指定描述信息的功能
public class MetaClass {
private ReflectorFactory reflectorFactory;
private Reflector reflector;
/**
* 构造函数私有
*/
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
/**
* 调用构造方法创建MetaClass
*/
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
return new MetaClass(type, reflectorFactory);
}
/**
* 通过属性名称, 获取属性的MetaClass(解决成员变量是类的情况)
*/
public MetaClass metaClassForProperty(String name) {
Class<?> propType = reflector.getGetterType(name);
return MetaClass.forClass(propType, reflectorFactory);
}
public String findProperty(String name) {
StringBuilder prop = buildProperty(name, new StringBuilder());
return prop.length() > ? prop.toString() : null;
}
public String findProperty(String name, boolean useCamelCaseMapping) {
if (useCamelCaseMapping) {
name = name.replace("_", "");
}
return findProperty(name);
}
public String[] getGetterNames() {
return reflector.getGetablePropertyNames();
}
public String[] getSetterNames() {
return reflector.getSetablePropertyNames();
}
public Class<?> getSetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaClass metaProp = metaClassForProperty(prop.getName());
return metaProp.getSetterType(prop.getChildren());
} else {
return reflector.getSetterType(prop.getName());
}
}
public Class<?> getGetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaClass metaProp = metaClassForProperty(prop);
return metaProp.getGetterType(prop.getChildren());
}
// issue #506. Resolve the type inside a Collection Object
return getGetterType(prop);
}
private MetaClass metaClassForProperty(PropertyTokenizer prop) {
Class<?> propType = getGetterType(prop);
return MetaClass.forClass(propType, reflectorFactory);
}
private Class<?> getGetterType(PropertyTokenizer prop) {
Class<?> type = reflector.getGetterType(prop.getName());
if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
Type returnType = getGenericGetterType(prop.getName());
if (returnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
if (actualTypeArguments != null && actualTypeArguments.length == ) {
returnType = actualTypeArguments[];
if (returnType instanceof Class) {
type = (Class<?>) returnType;
} else if (returnType instanceof ParameterizedType) {
type = (Class<?>) ((ParameterizedType) returnType).getRawType();
}
}
}
}
return type;
}
private Type getGenericGetterType(String propertyName) {
try {
Invoker invoker = reflector.getGetInvoker(propertyName);
if (invoker instanceof MethodInvoker) {
Field _method = MethodInvoker.class.getDeclaredField("method");
_method.setAccessible(true);
Method method = (Method) _method.get(invoker);
return TypeParameterResolver.resolveReturnType(method, reflector.getType());
} else if (invoker instanceof GetFieldInvoker) {
Field _field = GetFieldInvoker.class.getDeclaredField("field");
_field.setAccessible(true);
Field field = (Field) _field.get(invoker);
return TypeParameterResolver.resolveFieldType(field, reflector.getType());
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
return null;
}
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (reflector.hasSetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop.getName());
return metaProp.hasSetter(prop.getChildren());
} else {
return false;
}
} else {
return reflector.hasSetter(prop.getName());
}
}
public boolean hasGetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (reflector.hasGetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop);
return metaProp.hasGetter(prop.getChildren());
} else {
return false;
}
} else {
return reflector.hasGetter(prop.getName());
}
}
public Invoker getGetInvoker(String name) {
return reflector.getGetInvoker(name);
}
public Invoker getSetInvoker(String name) {
return reflector.getSetInvoker(name);
}
/**
* 解析属性表达式 会去寻找reflector中是否有对应的的属性
*/
private StringBuilder buildProperty(String name, StringBuilder builder) {
// 解析属性表达式
PropertyTokenizer prop = new PropertyTokenizer(name);
// 是否有子表达式
if (prop.hasNext()) {
// 查找对应的属性
String propertyName = reflector.findPropertyName(prop.getName());
if (propertyName != null) {
// 追加属性名
builder.append(propertyName);
builder.append(".");
// 创建对应的 MetaClass 对象
MetaClass metaProp = metaClassForProperty(propertyName);
// 解析子表达式, 递归
metaProp.buildProperty(prop.getChildren(), builder);
}
} else {
// 根据名称查找属性
String propertyName = reflector.findPropertyName(name);
if (propertyName != null) {
builder.append(propertyName);
}
}
return builder;
}
public boolean hasDefaultConstructor() {
return reflector.hasDefaultConstructor();
}
}
理解了这个方法(递归, 该类中有很多类似的), 就可以很好的对这个类进行理解, 以查找(richType.richProperty)为例:
- 通过 PropertyTokenizer 对表达式进行解析, 得到当前的 name = richType, children = richProperty
- 从 reflector 中查找该 richType 属性
- 将 richType 添加到 builder 中
- 使用 metaClassForProperty 创建 richType 的 MetaClass。
- 递归调用自身来处理子表达式
退出的条件就是没有子表达式。 这个就是为了, 我们类中有成员变量是类, 我们可以通过其找到他们的所有类及其属性。
注意, 在此过程中, ReflectorFactory 一直是同一个, 而其内部缓存了多个 Reflector 对象。
Mybatis框架基础支持层——反射工具箱之MetaClass(7)的更多相关文章
- Mybatis框架基础支持层——反射工具箱之Reflector&ReflectorFactory(3)
说明:Reflector是Mybatis反射工具的基础,每个Reflector对应一个类,在Reflector中封装有该类的元信息, 以及基于类信息的一系列反射应用封装API public class ...
- Mybatis框架基础支持层——反射工具箱之实体属性Property工具集(6)
本篇主要介绍mybatis反射工具中用到的三个属性工具类:PropertyTokenizer.PropertyNamer.PropertyCopier. PropertyTokenizer: 主要用来 ...
- Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)
ObjectFactory官方简介:MyBatis每次创建结果集对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成. 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认 ...
- Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)
简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...
- Mybatis框架基础支持层——日志模块(8)
前言: java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同.为了统一这些工具的接 ...
- Mybatis框架基础支持层——解析器模块(2)
解析器模块,核心类XPathParser /** * 封装了用于xml解析的类XPath.Document和EntityResolver */ public class XPathParser { / ...
- MyBatis源码分析-基础支持层反射模块Reflector/ReflectorFactory
本文主要介绍MyBatis的反射模块是如何实现的. MyBatis 反射的核心类Reflector,下面我先说明它的构造函数和成员变量.具体方法下面详解. org.apache.ibatis.refl ...
- 精尽 MyBatis 源码分析 - 基础支持层
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis 框架 基础应用
1.ORM的概念和优势 概念: 对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据 ...
随机推荐
- PostgreSQL+PostGIS 的使用
一.PostGIS中的几何类型 PostGIS支持所有OGC规范的“Simple Features”类型,同时在此基础上扩展了对3DZ.3DM.4D坐标的支持. 1. OGC的WKB和WKT格式 OG ...
- jenkins:一键回滚站点集群
最近在学习jenkins过程中整理了大量资料,都收录在<jenkins自动化工具使用教程>,但依然缺少一些具体实现细节. 这篇文章,介绍jenkins做集群回滚时的两个设计方案,让一键回滚 ...
- 为wordpress博客网站替换鼠标样式
第一种方法是使用插件来实现这个功能,Unique Cursor 插件.可以在后台直接安装启用,然后就可以设置喜欢鼠标样式,点击保存就可以了.切记在选择的同时有二个选项一个是disable意思是关闭还 ...
- [Swift]LeetCode493. 翻转对 | Reverse Pairs
Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j] ...
- [Swift]LeetCode561. 数组拆分 I | Array Partition I
Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1 ...
- Vue入门手册整理
目录 第一章.环境搭建 第二章.目录结构 第三章.Vue调试 第四章.定义页面 附录资料 第一章.环境搭建 1.1.准备: npm: 6.9.0 (npm > 3.0) node: v10.15 ...
- Java8 LocalDateTime获取时间戳(毫秒/秒)、LocalDateTime与String互转、Date与LocalDateTime互转
本文目前提供:LocalDateTime获取时间戳(毫秒/秒).LocalDateTime与String互转.Date与LocalDateTime互转 文中都使用的时区都是东8区,也就是北京时间.这是 ...
- [Abp 源码分析]九、事件总线
0.简介 事件总线就是订阅/发布模式的一种实现,本质上事件总线的存在是为了降低耦合而存在的. 从上图可以看到事件由发布者发布到事件总线处理器当中,然后经由事件总线处理器调用订阅者的处理方法,而发布者和 ...
- 【从零开始自制CPU之学习篇03】锁存器与触发器
本篇学习了两种锁存器:SR Latch和D Latch,一种触发器:D flip flop SR Latch:SR—锁存器 初始状态下,S和R都为0,Q和Q‘随机有一个为1另一个 为0(取决于电流速度 ...
- jquery lazy load
LazyLoad是一个Js编写的Jq插件,它可以延迟加载页面中的图片,在浏览器可视范围中的图片会被加载.如何使用:LazyLoad依赖于Jquery,在html的结尾处 ,就是在</body&g ...