美文网首页MyBatis源码剖析
[MyBatis源码分析 - 反射器模块 - 组件八] Meta

[MyBatis源码分析 - 反射器模块 - 组件八] Meta

作者: 小胡_鸭 | 来源:发表于2020-10-26 19:57 被阅读0次

一、简介

  在对 ObjectWrapper 类的介绍中,除了 #hasGetter#hasSetter#getGetterType#getSetterType 这几个方法,其余带 PropertyTokenizer 类型参数的方法中,参数代表的表达式已经是经过解析没有子表达式的形式了如 order[0],最终在 ObjectWrapper 中完成功能实现的最后一环,而表达式带多层子表达式的初始状态的解析过程正是在 MetaObject 类中进行的,对 MetaObject 的分析,聚焦于这个属性表达式的解析过程。

二、数据结构

  private Object originalObject;                      // 原始JavaBean对象
  private ObjectWrapper objectWrapper;                // 封装了originalObject对象的包装对象
  private ObjectFactory objectFactory;                // 负责实例化originalObject对象的工厂对象
  private ObjectWrapperFactory objectWrapperFactory;  // 负责创建ObjectWrapper的工厂对象
  private ReflectorFactory reflectorFactory;          // 用于创建并缓存Reflcetor对象的工厂对象
  • originalObject:原始JavaBean对象。
  • objectWrapper:原始JavaBean对象对应的包装对象,根据JavaBean的类型,可能为 BeanWrapperMapWrapperCollectionWrapper
  • objectFactory:负责实例化originalObject对象的工厂对象,通常发生在使用表达式指定属性值时,最末尾的属性所在的对象为空的时候用到,这时候需要先实例化对象,如表达式 user.order.amount ,如果想给该表达式对应的属性赋值,如果中间的 order 对象是空的,则需要先实例化 order,否则无法赋值。
  • objectWrapperFactory:负责创建ObjectWrapper的工厂对象,默认实现抛出异常,主要方便用户自定义 ObjectWrapperFactory 的实现。
  • reflectorFactory:用于创建并缓存Reflcetor对象的工厂对象。

三、构造方法

  // 构造方法声明为私有,只允许通过 MetaObject.forObject() 静态方法创建 MetaObject 对象
  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;

    // 若原始对象已经是ObjectWrapper对象,则直接使用
    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    // 若objectWrapperFactory能够为该原始对象创建对应的ObjectWrapper对象,则优先使用
    // objectWrapperFactory,而DefaultObjectWrapperFactory.hasWrapperFor()始终返回false
    // 用户可以自定义ObjectWrapperFactory实现进行扩展。
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    // 若原始对象为Map类型,则创建MapWrapper对象
    } else if (object instanceof Map) {
      this.objectWrapper = new MapWrapper(this, (Map) object);
    // 若原始对象是Collection类型,则创建CollectionWrapper对象
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    // 若原始对象是普通的JavaBean对象,则创建BeanWrapper对象
    } else {
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

【解析】
  如果传入的对象是一个 ObjectWrapper 则直接使用,否则尝试用 ObjectWrapperFactory 创建 ObjectWrapper(假如用户自定义实现可用),如果以上情况都不满足,则先后尝试创建与对象类型相匹配的 ObjectWrapper,可选类型为 MapWrapperCollectionWrapperBeanWrapper

四、方法功能

1、MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory)

【功能】创建 MetaObject 对象的静态方法,也是唯一调用途径,因为构造方法为 private。
【源码与注解】

  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
      // 若Object为空,则统一返回 SystemMetaObject.NULL_META_OBJECT
      // 反过来,若判断到一个 JavaBean 对象对应的 MetaObject 为 SystemMetaObject.NULL_META_OBJECT,可以判断对象为空
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

【解析】
  如果原始Java对象不为空,则调用构造方法创建对象,否则,使用特殊的用来表达原始对象为空的 SystemMetaObject.NULL_META_OBJECTSystemMetaObject 类的定义如下:

public final class SystemMetaObject {

  public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
  public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
  public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(NullObject.class, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());

  private SystemMetaObject() {
    // Prevent Instantiation of Static Class
  }

  private static class NullObject {
  }

  public static MetaObject forObject(Object object) {
    return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
  }

}

2、Object getValue(String name)

【功能】获取表达式指定的原始对象中属性的值。
【源码与注解】

  public Object getValue(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);   // 解析表达式
    if (prop.hasNext()) {
      // 创建子表达式所属对象
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      // 如果所属对象为空,对象下的属性肯定也为空
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {
        // 不为空,则递归解析子表达式,这里是递归的入口
        return metaValue.getValue(prop.getChildren());
      }
    } else {
      // 没有子表达式或者到了递归出口,直接调用 ObjectWrapper 对象获得属性值
      return objectWrapper.get(prop);
    }
  }

【解析】
  递归处理表达式的处理跟 ObjectWrapper 中的 #hasGetter#hasSetter#getGetterType#getSetterType 类似,MetaClass 类中有个方法 #metaClassForProperty() 用来为对象属性创建对应的 MetaClass 对象,同样的 MetaObject 类中也有方法 #metaObjectForProperty() 用来为对象属性创建对应的 MetaObject 对象,其源码如下:

  public MetaObject metaObjectForProperty(String name) {
    Object value = getValue(name);
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }

3、void setValue(String name, Object value)

【功能】为表达式指定的原始对象中属性设置值。
【源码与注解】

  public void setValue(String name, Object value) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      // 当顶层属性对象值为空时,依然尝试去先创建初始化顶层属性对象
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        // 如果要设定的值为空并且子表达不为空,这时没有设置的必要了
        // 为什么非要并且子表达式为非空?因为有可能就是要给某个属性设空值
        if (value == null && prop.getChildren() != null) {
          // don't instantiate child path if value is null
          return;
        } else {
          // 初始化顶层属性对象
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }
      // 如果值不为空,直接调用;
      // 如果值为空,则先初始化后再调用
      metaValue.setValue(prop.getChildren(), value);
    } else {
      // 没有子表达式或者到了递归出口,直接调用 ObjectWrapper 对象设置属性值
      objectWrapper.set(prop, value);
    }
  }

【解析】
  #setValue()#getValue() 差别在于:如果顶层属性为空,肯定无法获取值,直接返回null;但是设置属性值,即使顶层属性为空,也可以先初始化顶层属性,再赋值。比如 user.order.amount,属性 user 是一个 User 对象,order 是其成员,类型为 Order,如果 order 为空,获取值时 order 的 amount 成员也必为空,但是设置值时,即使 order 为空,也可以先创建对象 order = new Order() 再给 order.amount 赋值。

4、其他方法

  除了上述方法,其他方法只是类中定义属性的一个简单的 getter,或者是对 ObjectWrapper 接口方法的一个代理,方便外部程序直接调用 MetaObject 类中的方法就可以实现相应的功能。

  public ObjectFactory getObjectFactory() {
    return objectFactory;
  }

  public ObjectWrapperFactory getObjectWrapperFactory() {
    return objectWrapperFactory;
  }

  public ReflectorFactory getReflectorFactory() {
    return reflectorFactory;
  }

  public Object getOriginalObject() {
    return originalObject;
  }

  public String findProperty(String propName, boolean useCamelCaseMapping) {
    return objectWrapper.findProperty(propName, useCamelCaseMapping);
  }

  public String[] getGetterNames() {
    return objectWrapper.getGetterNames();
  }

  public String[] getSetterNames() {
    return objectWrapper.getSetterNames();
  }

  public Class<?> getSetterType(String name) {
    return objectWrapper.getSetterType(name);
  }

  public Class<?> getGetterType(String name) {
    return objectWrapper.getGetterType(name);
  }

  public boolean hasSetter(String name) {
    return objectWrapper.hasSetter(name);
  }

  public boolean hasGetter(String name) {
    return objectWrapper.hasGetter(name);
  }

  public ObjectWrapper getObjectWrapper() {
    return objectWrapper;
  }

  public boolean isCollection() {
    return objectWrapper.isCollection();
  }

  public void add(Object element) {
    objectWrapper.add(element);
  }

  public <E> void addAll(List<E> list) {
    objectWrapper.addAll(list);
  }

五、测试案例

1、类定义

public class RichType {

  private RichType richType;

  private String richField;

  private String richProperty;

  private Map richMap = new HashMap();

  private List richList = new ArrayList() {
    {
      add("bar");
    }
  };

  public RichType getRichType() {
    return richType;
  }

  public void setRichType(RichType richType) {
    this.richType = richType;
  }

  public String getRichProperty() {
    return richProperty;
  }

  public void setRichProperty(String richProperty) {
    this.richProperty = richProperty;
  }

  public List getRichList() {
    return richList;
  }

  public void setRichList(List richList) {
    this.richList = richList;
  }

  public Map getRichMap() {
    return richMap;
  }

  public void setRichMap(Map richMap) {
    this.richMap = richMap;
  }
}

2、测试案例

@Test
  public void shouldGetAndSetField() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richField", "foo");
    assertEquals("foo", meta.getValue("richField"));
  }

  @Test
  public void shouldGetAndSetNestedField() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richField", "foo");
    assertEquals("foo", meta.getValue("richType.richField"));
  }

  @Test
  public void shouldGetAndSetProperty() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richProperty", "foo");
    assertEquals("foo", meta.getValue("richProperty"));
  }

  @Test
  public void shouldGetAndSetNestedProperty() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richProperty", "foo");
    assertEquals("foo", meta.getValue("richType.richProperty"));
  }

  @Test
  public void shouldGetAndSetMapPair() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richMap.key", "foo");
    assertEquals("foo", meta.getValue("richMap.key"));
  }

  @Test
  public void shouldGetAndSetMapPairUsingArraySyntax() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richMap[key]", "foo");
    assertEquals("foo", meta.getValue("richMap[key]"));
  }

  @Test
  public void shouldGetAndSetNestedMapPair() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richMap.key", "foo");
    assertEquals("foo", meta.getValue("richType.richMap.key"));
  }

  @Test
  public void shouldGetAndSetNestedMapPairUsingArraySyntax() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richMap[key]", "foo");
    assertEquals("foo", meta.getValue("richType.richMap[key]"));
  }

  @Test
  public void shouldGetAndSetListItem() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richList[0]", "foo");
    assertEquals("foo", meta.getValue("richList[0]"));
  }

  @Test
  public void shouldSetAndGetSelfListItem() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richList[0]", "foo");
    assertEquals("foo", meta.getValue("richList[0]"));
  }

  @Test
  public void shouldGetAndSetNestedListItem() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richList[0]", "foo");
    assertEquals("foo", meta.getValue("richType.richList[0]"));
  }

  @Test
  public void shouldGetReadablePropertyNames() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    String[] readables = meta.getGetterNames();
    assertEquals(5, readables.length);
    for (String readable : readables) {
      assertTrue(meta.hasGetter(readable));
      assertTrue(meta.hasGetter("richType." + readable));
    }
    assertTrue(meta.hasGetter("richType"));
  }

  @Test
  public void shouldGetWriteablePropertyNames() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    String[] writeables = meta.getSetterNames();
    assertEquals(5, writeables.length);
    for (String writeable : writeables) {
      assertTrue(meta.hasSetter(writeable));
      assertTrue(meta.hasSetter("richType." + writeable));
    }
    assertTrue(meta.hasSetter("richType"));
  }

  @Test
  public void shouldSetPropertyOfNullNestedProperty() {
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    richWithNull.setValue("richType.richProperty", "foo");
    assertEquals("foo", richWithNull.getValue("richType.richProperty"));
  }

  @Test
  public void shouldSetPropertyOfNullNestedPropertyWithNull() {
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    richWithNull.setValue("richType.richProperty", null);
    assertEquals(null, richWithNull.getValue("richType.richProperty"));
  }

  @Test
  public void shouldGetPropertyOfNullNestedProperty() {
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    assertNull(richWithNull.getValue("richType.richProperty"));
  }

  @Test
  public void shouldVerifyHasReadablePropertiesReturnedByGetReadablePropertyNames() {
    MetaObject object = SystemMetaObject.forObject(new Author());
    for (String readable : object.getGetterNames()) {
      assertTrue(object.hasGetter(readable));
    }
  }

  @Test
  public void shouldVerifyHasWriteablePropertiesReturnedByGetWriteablePropertyNames() {
    MetaObject object = SystemMetaObject.forObject(new Author());
    for (String writeable : object.getSetterNames()) {
      assertTrue(object.hasSetter(writeable));
    }
  }

  @Test
  public void shouldSetAndGetProperties() {
    MetaObject object = SystemMetaObject.forObject(new Author());
    object.setValue("email", "test");
    assertEquals("test", object.getValue("email"));

  }

  @Test
  public void shouldVerifyPropertyTypes() {
    MetaObject object = SystemMetaObject.forObject(new Author());
    assertEquals(6, object.getSetterNames().length);
    assertEquals(int.class, object.getGetterType("id"));
    assertEquals(String.class, object.getGetterType("username"));
    assertEquals(String.class, object.getGetterType("password"));
    assertEquals(String.class, object.getGetterType("email"));
    assertEquals(String.class, object.getGetterType("bio"));
    assertEquals(Section.class, object.getGetterType("favouriteSection"));
  }

  @Test
  public void shouldDemonstrateDeeplyNestedMapProperties() {
    HashMap<String, String> map = new HashMap<String, String>();
    MetaObject metaMap = SystemMetaObject.forObject(map);

    assertTrue(metaMap.hasSetter("id"));
    assertTrue(metaMap.hasSetter("name.first"));
    assertTrue(metaMap.hasSetter("address.street"));

    assertFalse(metaMap.hasGetter("id"));
    assertFalse(metaMap.hasGetter("name.first"));
    assertFalse(metaMap.hasGetter("address.street"));

    metaMap.setValue("id", "100");
    metaMap.setValue("name.first", "Clinton");
    metaMap.setValue("name.last", "Begin");
    metaMap.setValue("address.street", "1 Some Street");
    metaMap.setValue("address.city", "This City");
    metaMap.setValue("address.province", "A Province");
    metaMap.setValue("address.postal_code", "1A3 4B6");

    assertTrue(metaMap.hasGetter("id"));
    assertTrue(metaMap.hasGetter("name.first"));
    assertTrue(metaMap.hasGetter("address.street"));

    assertEquals(3, metaMap.getGetterNames().length);
    assertEquals(3, metaMap.getSetterNames().length);

    Map<String,String> name = (Map<String,String>) metaMap.getValue("name");
    Map<String,String> address = (Map<String,String>) metaMap.getValue("address");

    assertEquals("Clinton", name.get("first"));
    assertEquals("1 Some Street", address.get("street"));
  }

  @Test
  public void shouldDemonstrateNullValueInMap() {
    HashMap<String, String> map = new HashMap<String, String>();
    MetaObject metaMap = SystemMetaObject.forObject(map);
    assertFalse(metaMap.hasGetter("phone.home"));

    metaMap.setValue("phone", null);
    assertTrue(metaMap.hasGetter("phone"));
    // hasGetter returns true if the parent exists and is null.
    assertTrue(metaMap.hasGetter("phone.home"));
    assertTrue(metaMap.hasGetter("phone.home.ext"));
    assertNull(metaMap.getValue("phone"));
    assertNull(metaMap.getValue("phone.home"));
    assertNull(metaMap.getValue("phone.home.ext"));

    metaMap.setValue("phone.office", "789");
    assertFalse(metaMap.hasGetter("phone.home"));
    assertFalse(metaMap.hasGetter("phone.home.ext"));
    assertEquals("789", metaMap.getValue("phone.office"));
    assertNotNull(metaMap.getValue("phone"));
    assertNull(metaMap.getValue("phone.home"));
  }

  @Test
  public void shouldNotUseObjectWrapperFactoryByDefault() {
    MetaObject meta = SystemMetaObject.forObject(new Author());
    assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
  }

  @Test
  public void shouldUseObjectWrapperFactoryWhenSet() {
    MetaObject meta = MetaObject.forObject(new Author(), SystemMetaObject.DEFAULT_OBJECT_FACTORY, new CustomBeanWrapperFactory(), new DefaultReflectorFactory());
    assertTrue(meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));

    // Make sure the old default factory is in place and still works
    meta = SystemMetaObject.forObject(new Author());
    assertFalse(meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
  }

  @Test
  public void shouldMethodHasGetterReturnTrueWhenListElementSet() {
    List<Object> param1 = new ArrayList<Object>();
    param1.add("firstParam");
    param1.add(222);
    param1.add(new Date());

    Map<String, Object> parametersEmulation = new HashMap<String, Object>();
    parametersEmulation.put("param1", param1);
    parametersEmulation.put("filterParams", param1);

    MetaObject meta = SystemMetaObject.forObject(parametersEmulation);

    assertEquals(param1.get(0), meta.getValue("filterParams[0]"));
    assertEquals(param1.get(1), meta.getValue("filterParams[1]"));
    assertEquals(param1.get(2), meta.getValue("filterParams[2]"));

    assertTrue(meta.hasGetter("filterParams[0]"));
    assertTrue(meta.hasGetter("filterParams[1]"));
    assertTrue(meta.hasGetter("filterParams[2]"));
  }

3、执行结果

相关文章

网友评论

    本文标题:[MyBatis源码分析 - 反射器模块 - 组件八] Meta

    本文链接:https://www.haomeiwen.com/subject/yvuomktx.html