mybatis源码学习-----property工具包
程序员文章站
2022-07-12 22:37:11
...
property工具包简介
org.apache.ibatis.reflection.property包下共有三个工具类,PropertyCopier、PropertyNamer和PropertyTokenizer。
- PropertyCopier:主要用于两个对象之间进行属性复制
- PropertyNamer:主要用于完成属性名和方法名之间的转换
- PropertyTokenizer:主要用于解析属性表达式,比如在mapper.xml中经常写的
<if test="order.orderName != null && order.orderName != ''">
......
</if>
这里的order.orderName就是属性表达式而PropertyTokenizer工具类的作用就是解析属性表达式
PropertyCopier
属性复制器只有一个方法copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean),该方法的功能是通过递归的方法将sourceBean对象中的属性复制到destinationBean对象中,包括sourceBean和destinationBean的父对象中的属性
//final修饰,不允许进行扩展或修改。
public final class PropertyCopier {
private PropertyCopier() {
}
public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
Class<?> parent = type;
while (parent != null) {//递归退出条件
final Field[] fields = parent.getDeclaredFields();//获取当前类声明的所有字段
for (Field field : fields) {
try {
try {
//将sourceBean中的该字段的值赋给destinationBean中对应的字段
field.set(destinationBean, field.get(sourceBean));
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
field.setAccessible(true);
field.set(destinationBean, field.get(sourceBean));
} else {
throw e;
}
}
} catch (Exception e) {
//进入这里表示当前字段可能是final修饰的或者是其他异常,直接忽略
}
}
parent = parent.getSuperclass();
}
}
}
PropertyNamer
名称解析器,用于属性名和方法名之间的转换
public final class PropertyNamer {
private PropertyNamer() {
// Prevent Instantiation of Static Class
}
/**
* 该方法用于将方法名转换成属性名,逻辑非常简单
* 1、将方法开头的is、get或set去掉
* 2、将剩余字符串的首字母变成小写
* @param name
* @return
*/
public static String methodToProperty(String name) {
if (name.startsWith("is")) {
name = name.substring(2);
} else if (name.startsWith("get") || name.startsWith("set")) {
name = name.substring(3);
} else {
throw new ReflectionException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get' or 'set'.");
}
if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
}
return name;
}
/**
* 判断传入的name是不是属性
* @param name
* @return
*/
public static boolean isProperty(String name) {
return isGetter(name) || isSetter(name);
}
/**
* 判断name是不是getter方法名
* @param name
* @return
*/
public static boolean isGetter(String name) {
return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
}
/**
* 判断name是不是setter方法名
*
* @param name
* @return
*/
public static boolean isSetter(String name) {
return name.startsWith("set") && name.length() > 3;
}
}
PropertyTokenizer
PropertyTokenizer用于解析属性表达式,PropertyTokenizer定义了4个属性
private String name;
private final String indexedName;
private String index;
private final String children;
- name表示当前属性名
- indexedName表示带索引的属性名,如果当前无索引,则该值与name相同
- index表示索引下标
- children除去name外的子表达式
以表达式 obj1.list[0].obj2为例,此时name为obj1,indexedName为obj1,index为null,children为list[0].obj2
PropertyTokenizer的代码如下
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
private String name;
private final String indexedName;
private String index;
private final String children;
//构造函数,用于对上面定义的四个属性进行赋值
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
public String getName() {
return name;
}
public String getIndex() {
return index;
}
public String getIndexedName() {
return indexedName;
}
public String getChildren() {
return children;
}
/**
* 实现自Iterator接口中的方法
* @return
*/
@Override
public boolean hasNext() {
return children != null;
}
/**
* 实现自Iterator接口中的方法
* @return
*/
@Override
public PropertyTokenizer next() {
//创建下一个PropertyTokenizer对象
return new PropertyTokenizer(children);
}
/**
* 实现自Iterator接口中的方法
* @return
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
}
}
由PropertyTokenizer类的定义可知,该类实现了Iterator接口,于是他变可以处理多层嵌套的表达式。
举例
以表达式obj1.list[0].obj2的解析过程为例,讲解PropertyTokenizer迭代解析的过程
上一篇: 1.流水灯
下一篇: MyBatis学习笔记
推荐阅读
-
Mybatis源码学习(15)-binding模块之MapperMethod类
-
mybatis源码学习------resultMap和sql片段的解析
-
mybatis源码学习------动态sql的解析(SqlSource)
-
mybatis源码学习------binding模块(上)
-
mybatis源码学习------缓存模块
-
mybatis源码学习------StatementHandler
-
Mybatis 源码学习(二) Mapper 接口和sql的映射
-
mybatis源码学习-----property工具包
-
MyBatis源码学习之SqlSession创建
-
MyBatis源码学习之SqlSession创建