mybatis底层组件介绍-ObjectWrapper

本文详细介绍了ObjectWrapper及其子类在处理Bean、Map和集合属性读写中的作用,以及MetaObject如何扩展对属性链的访问。通过示例展示了MetaObject如何递归解析属性字符串以获取深层属性值。内容涵盖了BeanWrapper、MapWrapper、CollectionWrapper的常用方法,以及MetaObject的构造和getValue方法的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ObjectWrapper

ObjectWrapper的主要作用就是对一个对象进行了包裹,方便通过这个类来对对象进行属性的设置以及读取属性
然后根据被包裹对象的类型,分别使用不同的子类来进行包裹
在这里插入图片描述
可以看到,主要有三种类型:

  1. BeanWrapper,主要处理Bean的属性读写
  2. MapWrapper,主要处理Map的属性读写
  3. CollectionWrapper,主要处理集合的属性读写

常用的方法如下

public interface ObjectWrapper {

  Object get(PropertyTokenizer prop);

  void set(PropertyTokenizer prop, Object value);

  String findProperty(String name, boolean useCamelCaseMapping);

  String[] getGetterNames();

  String[] getSetterNames();

  Class<?> getSetterType(String name);

  Class<?> getGetterType(String name);

  boolean hasSetter(String name);

  boolean hasGetter(String name);

  MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

  boolean isCollection();

  void add(Object element);

  <E> void addAll(List<E> element);

}

BeanWrapper

构造函数

构造函数主要是赋值MetaObject,object以及根据Object的类型来获取MetaClass

public BeanWrapper(MetaObject metaObject, Object object) {
 super(metaObject);
 this.object = object;
 this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
}
get
public Object get(PropertyTokenizer prop) {
	// 当前遍历的属性包括下标,也就是是一个集合类的属性
  if (prop.getIndex() != null) {
    Object collection = resolveCollection(prop, object);
    return getCollectionValue(prop, collection);
  } else {
    return getBeanProperty(prop, object);
  }
}

这里首先看下如何处理集合类属性
比如我们当前需要解析的属性字符串是richList[0]
那么会将richList交给metaObject来解析,metaObject底层会通过objectWrapper来获取当前对象的richList属性,然后返回

protected Object resolveCollection(PropertyTokenizer prop, Object object) {
  if ("".equals(prop.getName())) {
    return object;
  } else {
    return metaObject.getValue(prop.getName());
  }
}

接下来就是简单地case by case的处理,根据对象类型的不同,进行转换,然后获取指定下标的值

protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
  if (collection instanceof Map) {
    return ((Map) collection).get(prop.getIndex());
  } else {
    int i = Integer.parseInt(prop.getIndex());
    if (collection instanceof List) {
      return ((List) collection).get(i);
    } else if (collection instanceof Object[]) {
      return ((Object[]) collection)[i];
    } else if (collection instanceof char[]) {
      return ((char[]) collection)[i];
    } else if (collection instanceof boolean[]) {
      return ((boolean[]) collection)[i];
    } else if (collection instanceof byte[]) {
      return ((byte[]) collection)[i];
    } else if (collection instanceof double[]) {
      return ((double[]) collection)[i];
    } else if (collection instanceof float[]) {
      return ((float[]) collection)[i];
    } else if (collection instanceof int[]) {
      return ((int[]) collection)[i];
    } else if (collection instanceof long[]) {
      return ((long[]) collection)[i];
    } else if (collection instanceof short[]) {
      return ((short[]) collection)[i];
    } else {
      throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
    }
  }
}

接下来看下当前遍历的属性不是集合类的情况,可以看到就是简单地通过MetaClass来获取对应属性的getter,然后执行,返回

private Object getBeanProperty(PropertyTokenizer prop, Object object) {
  try {
    Invoker method = metaClass.getGetInvoker(prop.getName());
    try {
      return method.invoke(object, NO_ARGUMENTS);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  } catch (RuntimeException e) {
    throw e;
  } catch (Throwable t) {
    throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ".  Cause: " + t.toString(), t);
  }
}

MetaObject

MetaObject中会使用到ObjectWrapper,因此接下来继续介绍下MetaObject
从之前的介绍可以看出,ObjectWrapper只是对一个对象的包括,并且可以对该对象的直接属性的读写,但是无法处理由.连接的属性链的读写
而MetaObject底层基于ObjectWrapper,提供了对使用.连接的属性链的读写
MetaObject主要完成的是对属性字符串的解析,负责顺着属性字符串进行遍历,但是最终返回值仍然是通过ObjectWrapper来获取的

构造函数

private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
	// 原始的对象
  this.originalObject = object;
  // 负责根据参数来构建对象的工厂
  this.objectFactory = objectFactory;
  // 负责创建objectWraper的工厂,objectWraper可以通过传入PropertyTokenizer来对指定的属性进行读写
  this.objectWrapperFactory = objectWrapperFactory;
  // 负责创建reflector的工厂,reflector中封装了类的setter,getter和属性
  this.reflectorFactory = reflectorFactory;

	// 根据入参object的类型的不同,分别执行不同的操作,来对objectWrapper进行赋值
	// 根据类型的不同,返回相应类型的objectWrapper
  if (object instanceof ObjectWrapper) {
    this.objectWrapper = (ObjectWrapper) object;
  } else if (objectWrapperFactory.hasWrapperFor(object)) {
    this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
  } else if (object instanceof Map) {
    this.objectWrapper = new MapWrapper(this, (Map) object);
  } else if (object instanceof Collection) {
    this.objectWrapper = new CollectionWrapper(this, (Collection) object);
  } else {
    this.objectWrapper = new BeanWrapper(this, object);
  }
}

getValue

getValue用来根据字符串来获取对应的属性
主要原理就是递归地获取当前变量的属性的MetaClass,如果是表达式的最后一级,那么直接通过ObjectWrapper来返回结果

public Object getValue(String name) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
  	// 递归入口
  	// 获取当前属性的MetaObject
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return null;
    } else {
      return metaValue.getValue(prop.getChildren());
    }
  } else {
  	// 递归出口
    return objectWrapper.get(prop);
  }
}
public MetaObject metaObjectForProperty(String name) {
  Object value = getValue(name);
  return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
}

这里看个官方例子来增强理解

@Test
void shouldGetPropertyOfNullNestedProperty() {
  MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
  assertNull(richWithNull.getValue("richType.richProperty"));
}
  1. 首先是创建一个MetaObject,因为当前RichType只是一个普通的类,所以最终创建的MetaObject具有的ObjectWrapper是BeanWrapper
  2. 当前需要解析的属性字符串是richType.richProperty,所以在getValue方法中首先会获取当前遍历的属性名称即richType,底层会通过BeanWrapper来获取当前对象的richType属性的值,然后使用这个值创建一个MetaObject,使用这个新创建的MetaObject,继续处理剩余的属性表达式即richProperty,过程和之前的一样,最终就会返回richProperty的值
### 回答1: 语法错误:错误:找不到模块'cache-loader'。 这个错误通常是由于缺少依赖项或安装不正确的模块引起的。您可以尝试重新安装缺少的模块或更新您的依赖项。如果问题仍然存在,请检查您的代码并确保正确导入了所需的模块。 ### 回答2: 发生此错误,说明在 Node.js 应用程序中引用了 'cache-loader' 模块,但 Node.js 无法找到此模块。故此错误出现通常有以下原因: 1. 模块没有正确安装:'cache-loader' 模块可能没有被正确地安装。 解决方法:使用 npm install cache-loader -g 命令全局安装此模块。 2. 模块被误删除:如果曾经安装过 'cache-loader' 模块,但删除了它,可能会导致这个错误。 解决方法:重新安装 'cache-loader' 模块即可。 3. Node.js 环境版本问题:'cache-loader' 模块需要 Node.js 环境支持,如果使用的 Node.js 版本不兼容,则会提示找不到模块。 解决方法:升级或降级 Node.js 环境即可。 4. 项目依赖不一致:项目中的其他依赖可能不兼容 'cache-loader' 模块,导致找不到此模块。 解决方法:尝试升级或降级项目中的其他依赖以解决依赖不一致问题。 总之,如果遇到此错误,最好确定 'cache-loader' 模块是否存在,如果存在,则需要查明问题的具体原因,并采取适当的解决方法。 ### 回答3: 该错误是因为在使用Webpack构建时,无法找到所需的模块“cache-loader”。这个模块通常是用来加速Webpack构建时间的。所以当我们试图使用缓存时,却找不到该模块时,就会出现这种错误。 如果出现这种错误,通常可以通过以下步骤来解决: 第一步是确认是否已经安装了“cache-loader”模块。如果没有安装,则需要使用npm命令来安装该模块。在终端中进入项目根目录,执行以下命令:npm install cache-loader --save-dev。 第二步是检查项目中是否存在依赖该模块的代码。如果没有,则需要在Webpack配置文件中将其删除。如果存在,则需要将其正确地引入到Webpack配置中。在Webpack配置文件中找到与该模块相关的配置项,将其添加到“module.rules”或“module.loaders”中。 第三步是重新启动Webpack构建,并确认是否还出现该错误。如果该错误仍然存在,则需要进一步排除问题。可以尝试升级或回滚该模块的版本,或尝试删除缓存和重新安装依赖项等方法。 总之,要解决这个错误,我们需要了解Webpack的基本概念和配置,掌握一些基本的调试技巧,以及有耐心、仔细地排除问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值