欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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迭代解析的过程

mybatis源码学习-----property工具包

上一篇: 1.流水灯

下一篇: MyBatis学习笔记