Mybatis框架源码笔记(九)之反射工具类解析

1 反射工具类

Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错。Mybatis框架提供了专门的反射包,对常用的反射操作进行了简化封装,提供了更简单方便的API给调用者进行使用,主要的反射包代码结果如下:
在这里插入图片描述

2 核心接口

2.1 ObjectFactory接口

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。
在这里插入图片描述

2.2 ReflectorFactory接口

Mybatis使用一个 ReflectorFactory对象工厂去创建Reflector对象, 每一个Reflector对应一个java的Class类,其中包含了这个java的Class类的元信息,而 ReflectorFactory对象工厂就是用来创建并缓存Reflector对象的。
在这里插入图片描述

2.3 Invoker接口

Mybatis使用一个 Invoker接口来扩展java的Class类中的方法的调用执行,包含getter/setter以及其他方法和未明确方法的调用执行。
在这里插入图片描述

2.4 ObjectWrapper接口

ObjectWrapper 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型,它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。
在这里插入图片描述

3 核心类

3.1 Reflector类

Reflector中存储了反射需要使用的类的元信息(字节码的类型、属性、getter/setter、数据类型、构造器等等)
在这里插入图片描述
在这里插入图片描述
然后我们可以看看Reflector中提供的公共的API方法

方法名称作用
getType获取Reflector表示的Class
getDefaultConstructor获取默认的构造器
hasDefaultConstructor判断是否有默认的构造器
getSetInvoker根据属性名称获取对应的Invoker 对象
getGetInvoker根据属性名称获取对应的Invoker对象
getSetterType获取属性对应的类型 比如:
String name; // getSetterType(“name”) --> java.lang.String
getGetterType与上面是对应的
getGetablePropertyNames获取所有的可读属性名称的集合
getSetablePropertyNames获取所有的可写属性名称的集合
hasSetter判断是否具有某个可写的属性
hasGetter判断是否具有某个可读的属性
findPropertyName根据名称查找属性

3.2 DefaultReflectorFactory类

Mybatis框架内置的默认的创建Reflector对象的工厂类
在这里插入图片描述

3.3 MetaClass类

MetaClass 则用于获取类相关的信息。
在这里插入图片描述

方法说明
静态方法 forClass(type, reflectorFactory)创建 MetaClass 对象
hasDefaultConstructor()判断是否有默认构造方法
hasGetter(name)判断是否有属性 name 或 name 的 getter 方法。与 MetaObject 判断类似。
getGetterNames()获取含有 getter 相关的属性名称。与 MetaObject 判断类似。
getGetInvoker(name)name 的 getter 方法的 Invoker。
hasSetter(name)判断是否有属性 name 或 name 的 setter 方法。与 MetaObject 判断类似。
getSetterNames()获取含有 setter 相关的属性名称。与 MetaObject 判断类似。
getSetterType(name)获取 setter 方法的参数类型。与 MetaObject 判断类似。
getSetInvoker(name)name 的 setter 方法的 Invoker。

3.4 MetaObject类

MetaObject 用于获取和设置对象的属性值

方法说明
hasGetter(name)判断是否有属性 name 或 name 的 getter 方法。
1. 若定义 userId,没定义 getUserId() 方法,hasGetter(“userId”) 则返回 true;
2. 若定义方法 getUserId1(),没定义属性 userId1,hasGetter(“userId1”) 则返回 true。
getGetterNames()获取含有 getter 相关的属性名称。
1. 若定义 userId,没定义 getUserId() 方法,则 userId 会被返回;
2. 若定义方法 getUserId1(),没定义属性 userId1, 则 userId1 会被返回。
getGetterType(name)获取 getter 方法的返回类型。
getValue(name)获取属性值。
hasSetter(name)判断是否有属性 name 或 name 的 setter 方法。
1. 若定义 userId,没定义 setUserId(userId) 方法,hasSetter(“userId”) 则返回 true;
2. 若定义方法 setUserId1(userId1),没定义属性 userId1,hasSetter(“userId1”) 则返回 true。
getSetterNames()获取含有 setter 相关的属性名称。
1. 若定义 userId,没定义 setUserId(userId) 方法,则 userId 会被返回;
2. 若定义方法 setUserId1(userId1),没定义属性 userId1, 则 userId1 会被返回。
getSetterType(name)获取 setter 方法的参数类型。
setValue(name,value)设置属性值。

3.5 SystemMetaObject类

/**
 * @author Clinton Begin
 * 系统元对象
 */
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(new NullObject(), 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());
  }

}

MapperMethod、 BaseExecutor、 CachingExecutor、 DefaultResultSetHandler、 DefaultParameterHandler、Configuration中都是用MetaObject类

4 使用演示

Mybatis框架的源码中提供了丰富的测试案例演示反射工具中核心的工具类的使用方式, 下面我们简单演示几个,更多测试案例可以到源码中自行查看。
在这里插入图片描述

4.1 Reflector使用示例

class ReflectorTest {

  @Test
  void testGetSetterType() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
  }

  @Test
  void testGetGetterType() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertEquals(Long.class, reflector.getGetterType("id"));
  }

  @Test
  void shouldNotGetClass() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertFalse(reflector.hasGetter("class"));
  }

  interface Entity<T> {
    T getId();

    void setId(T id);
  }

  static abstract class AbstractEntity implements Entity<Long> {

    private Long id;

    @Override
    public Long getId() {
      return id;
    }

    @Override
    public void setId(Long id) {
      this.id = id;
    }
  }

  static class Section extends AbstractEntity implements Entity<Long> {
  }
 }

4.2 MetaClass使用示例

/*
 *    Copyright 2009-2022 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.domain.misc.RichType;
import org.apache.ibatis.domain.misc.generics.GenericConcrete;
import org.junit.jupiter.api.Test;

class MetaClassTest {

  @Test
  void shouldTestDataTypeOfGenericMethod() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(GenericConcrete.class, reflectorFactory);
    assertEquals(Long.class, meta.getGetterType("id"));
    assertEquals(Long.class, meta.getSetterType("id"));
  }

  @Test
  void shouldThrowReflectionExceptionGetGetterType() {
    try {
      ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
      MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
      meta.getGetterType("aString");
      org.junit.jupiter.api.Assertions.fail("should have thrown ReflectionException");
    } catch (ReflectionException expected) {
      assertEquals("There is no getter for property named \'aString\' in \'class org.apache.ibatis.domain.misc.RichType\'", expected.getMessage());
    }
  }

  @Test
  void shouldCheckGetterExistance() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertTrue(meta.hasGetter("richField"));
    assertTrue(meta.hasGetter("richProperty"));
    assertTrue(meta.hasGetter("richList"));
    assertTrue(meta.hasGetter("richMap"));
    assertTrue(meta.hasGetter("richList[0]"));

    assertTrue(meta.hasGetter("richType"));
    assertTrue(meta.hasGetter("richType.richField"));
    assertTrue(meta.hasGetter("richType.richProperty"));
    assertTrue(meta.hasGetter("richType.richList"));
    assertTrue(meta.hasGetter("richType.richMap"));
    assertTrue(meta.hasGetter("richType.richList[0]"));

    assertEquals("richType.richProperty", meta.findProperty("richType.richProperty", false));

    assertFalse(meta.hasGetter("[0]"));
  }

  @Test
  void shouldCheckSetterExistance() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertTrue(meta.hasSetter("richField"));
    assertTrue(meta.hasSetter("richProperty"));
    assertTrue(meta.hasSetter("richList"));
    assertTrue(meta.hasSetter("richMap"));
    assertTrue(meta.hasSetter("richList[0]"));

    assertTrue(meta.hasSetter("richType"));
    assertTrue(meta.hasSetter("richType.richField"));
    assertTrue(meta.hasSetter("richType.richProperty"));
    assertTrue(meta.hasSetter("richType.richList"));
    assertTrue(meta.hasSetter("richType.richMap"));
    assertTrue(meta.hasSetter("richType.richList[0]"));

    assertFalse(meta.hasSetter("[0]"));
  }

  @Test
  void shouldCheckTypeForEachGetter() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(String.class, meta.getGetterType("richField"));
    assertEquals(String.class, meta.getGetterType("richProperty"));
    assertEquals(List.class, meta.getGetterType("richList"));
    assertEquals(Map.class, meta.getGetterType("richMap"));
    assertEquals(List.class, meta.getGetterType("richList[0]"));

    assertEquals(RichType.class, meta.getGetterType("richType"));
    assertEquals(String.class, meta.getGetterType("richType.richField"));
    assertEquals(String.class, meta.getGetterType("richType.richProperty"));
    assertEquals(List.class, meta.getGetterType("richType.richList"));
    assertEquals(Map.class, meta.getGetterType("richType.richMap"));
    assertEquals(List.class, meta.getGetterType("richType.richList[0]"));
  }

  @Test
  void shouldCheckTypeForEachSetter() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(String.class, meta.getSetterType("richField"));
    assertEquals(String.class, meta.getSetterType("richProperty"));
    assertEquals(List.class, meta.getSetterType("richList"));
    assertEquals(Map.class, meta.getSetterType("richMap"));
    assertEquals(List.class, meta.getSetterType("richList[0]"));

    assertEquals(RichType.class, meta.getSetterType("richType"));
    assertEquals(String.class, meta.getSetterType("richType.richField"));
    assertEquals(String.class, meta.getSetterType("richType.richProperty"));
    assertEquals(List.class, meta.getSetterType("richType.richList"));
    assertEquals(Map.class, meta.getSetterType("richType.richMap"));
    assertEquals(List.class, meta.getSetterType("richType.richList[0]"));
  }

  @Test
  void shouldCheckGetterAndSetterNames() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(5, meta.getGetterNames().length);
    assertEquals(5, meta.getSetterNames().length);
  }

  @Test
  void shouldFindPropertyName() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals("richField", meta.findProperty("RICHfield"));
  }

}

4.3 MetaObject使用示例

/*
 *    Copyright 2009-2022 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import static org.junit.jupiter.api.Assertions.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.domain.blog.Author;
import org.apache.ibatis.domain.blog.Section;
import org.apache.ibatis.domain.misc.CustomBeanWrapper;
import org.apache.ibatis.domain.misc.CustomBeanWrapperFactory;
import org.apache.ibatis.domain.misc.RichType;
import org.junit.jupiter.api.Test;

class MetaObjectTest {

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

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

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

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

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

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

  @Test
  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
  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
  void shouldGetAndSetListItem() {
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richList[0]", "foo");
    assertEquals("foo", meta.getValue("richList[0]"));
  }

  @Test
  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
  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
  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
  void shouldSetPropertyOfNullNestedProperty() {
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    richWithNull.setValue("richType.richProperty", "foo");
    assertEquals("foo", richWithNull.getValue("richType.richProperty"));
  }

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

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

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

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

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

  }

  @Test
  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
  void shouldDemonstrateDeeplyNestedMapProperties() {
    HashMap<String, String> map = new HashMap<>();
    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);

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

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

  @Test
  void shouldDemonstrateNullValueInMap() {
    HashMap<String, String> map = new HashMap<>();
    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
  void shouldNotUseObjectWrapperFactoryByDefault() {
    MetaObject meta = SystemMetaObject.forObject(new Author());
    assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
  }

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

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

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

    Map<String, Object> parametersEmulation = new HashMap<>();
    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]"));
  }

}

5、反射工具类在Mybatis框架中的应用

5.1 DefaultResultSetHandler

查询结果集的核心处理方法createResultObject()中有很多地方都使用了到了反射工具类

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.2 DefaultParameterHandler

  /**
   * 替换SQL语句中的占位符为实际传入的参数值的方法
   */
  @Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    // 从BoundSql对象中获取到参数映射对象集合
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        // 依次取出parameterMapping对象
        ParameterMapping parameterMapping = parameterMappings.get(i);
        // 保证当前处理的parameterMapping对象都是输入参数
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          // 获取当前处理的parameterMapping对象的属性名称
          String propertyName = parameterMapping.getProperty();
          // 如果BoundSql对象的附加参数对象中包含该属性名称, 直接从BoundSql对象的附加参数对象中获取到该属性KEY对应的值
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
            // 如果ParameterObject为空,说明没有传值,值直接就为null
          } else if (parameterObject == null) {
            value = null;
            // 如果类型注册器中有该参数对象对应的类型处理器,则该参数取值就是parameterObject
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
            // 以上都不满足,就创建一个元数据对象,然后从元数据对象汇总通过属性获取到对应的取值
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          // 获取当前parameterMapping对象的类型处理器
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          // 获取当前parameterMapping对象的JDBC数据类型
          JdbcType jdbcType = parameterMapping.getJdbcType();
          // 如果参数输入值为null并且数据库数据类型为null,就将jdbcType类型设置为OTHER类型
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            // 为什么这里是使用i + 1?
            // insert into t_user(name, age, gender, email) value(?, ?, ?, ?)
            // 因为解析出来的带占位的sql语法中的?参数的计数是从1开始的, 不是从0开始的
            // 调用typeHandler的替换参数的方法替换到SQL语句中目标位置上占位符上为输入的参数值
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

5.3 Configuration

在这里插入图片描述

反射在java项目的实践应用中是非常重要的,必须熟练掌握,很多成熟的开源框架中都已经封装了很多非常好的反射工具,我们在进行源码阅读时,可以将这些精华的部分进行搜集整理应用到自己的项目中,只看是学不会的,编程这个东西还是更注重实践,实践的多了,自然你就会自主的去学习和思考了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7561.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React 组件的 children 数据使用

children 属性表示该组件的子节点&#xff0c;只要组件内部有子节点&#xff0c;props 就有该属性&#xff0c;是自动带上的&#xff0c;不需要开发者添加。 children 可以是 普通文本、普通标签元素、函数、JSX … 案例一&#xff1a;普通文本 import React from "rea…

奇异值分解(SVD)和图像压缩

在本文中&#xff0c;我将尝试解释 SVD 背后的数学及其几何意义&#xff0c;还有它在数据科学中的最常见的用法&#xff0c;图像压缩。 奇异值分解是一种常见的线性代数技术&#xff0c;可以将任意形状的矩阵分解成三个部分的乘积&#xff1a;U、S、V。原矩阵A可以表示为&#…

数据结构与算法基础(王卓)(21):哈夫曼编码(1):过程

逻辑雏形 根据老师讲解的思路&#xff0c;梳理出程序运行的逻辑雏形如下&#xff1a; 搞一个多维数组HC&#xff0c;用来存储我们这里 n(每) 个节点的哈夫曼编码搞一个数组cd&#xff0c;用来存储我们这里每个节点是前面一位的左子树&#xff08;0&#xff09;还是右子树&…

Spark 基本知识介绍

文章目录1. Spark是什么2. Spark与Hadoop区别3. Spark四大特点3.1 速度快3.2 易于使用3.3 通用性强3.4 运行方式4. Spark整体框架5. Spark运行模式6. Spark架构角色6.1 YARN角色6.2 Spark 角色1. Spark是什么 Spark是用于大规模数据处理的统一分析引擎。 Spark 最早源于一篇论…

Qt5.15.2 for WebAssembly 环境搭建 - Windows篇

Qt系列文章目录 文章目录Qt系列文章目录前言一、准备工作二、操作步骤1.使用cmd工具2.安装Qt for WebAssembly3.创建工程WebAssembly3.创建Qt Assembly工程参考前言 由于前端Canvas绘制图像效率问题&#xff0c;而且实现三维特效也有性能瓶颈&#xff0c;虽然Web 技术突飞猛进…

基于Arm Cortex-M4核心MK60DN256VMD10、MK60DX256VMD10嵌入式微控制器芯片介绍

MK60DN256VMD10&#xff08;MK60DX256VMD10&#xff09;是Kinetis K6x系列32位微控制器&#xff0c;基于ArmCortex-M4核心&#xff0c;是与Kinetis Kx MCU家族兼容的引脚&#xff0c;外设和软件。K6x mcu还集成了10/100Mbps以太网与IEEE1588精确时间协议(PTP)收发器和USB 2.0 (…

【Linux-计算机网络】-TCP协议通信流程

1.TCP协议通信流程图 1.1TCP协议的通讯流程可以分为以下步骤&#xff1a; 应用层&#xff1a;应用程序通过系统调用API&#xff08;如socket&#xff09;创建一个TCP套接字&#xff08;socket&#xff09;&#xff0c;并设置好相关的选项。 传输层&#xff1a;当应用程序调用c…

再学C语言49:C库中的字符串函数

C库提供了很多处理字符串的函数&#xff1b;ANSI C用头文件 string.h 给出这些函数的原型 一、strlen()函数 功能&#xff1a;计算并返回字符串长度 示例代码&#xff1a; /* test strlen() function */ #include <stdio.h> #include <string.h>int main(void)…

数据的存储--->【大小端字节序】(Big Endian)(Little Endian)

⛩️博主主页&#xff1a;威化小餅干&#x1f4dd;系列专栏&#xff1a;【C语言】藏宝图&#x1f38f; ✨绳锯⽊断&#xff0c;⽔滴⽯穿&#xff01;一个编程爱好者的学习记录!✨前言计算机硬件有两种存储数据的方式&#xff1a;大端字节序——Big Endian小端字节序——Little …

【Python】【进阶篇】十、Python爬虫的Requests库

目录十、Python爬虫的Requests库10.1 常用请求方法10.1.1 requests.get()10.1.2 requests.post()10.2 对象属性10.3 Requests库应用十、Python爬虫的Requests库 Python 提供了多个用来编写爬虫程序的库&#xff0c;除了前面已经介绍的 urllib 库之外&#xff0c;还有一个很重的…

vue尚品汇商城项目-day07【44.个人中心二级路由搭建+45.我的订单+46.优化登录跳转+47.独享守卫】

文章目录44.个人中心二级路由搭建45.我的订单46.优化登录跳转47.独享守卫本人其他相关文章链接44.个人中心二级路由搭建 修改代码&#xff1a; 将Center拆分为2个组件MyOrderGroupOrder src/router/routes.js import Center from /pages/Center import GroupOrder from /pages…

QT 常见控件使用

1. QLineEdit 添加控件后&#xff0c;可以编辑控件的名称&#xff0c;然后使用名称获取和设置值 QString qstrValue ui->strName->text(); QMessageBox::information(this, "提示", qstrValue); 2.窗体导航切换 添加新的对话框&#xff0c;然后引入头文件…

游戏安全漏洞一些分享

安全界对漏洞的定义为&#xff1a;在硬件、软件、系统等具体实现或者系统安全策略上存在的缺陷&#xff0c;从而使攻击者能够达到于某种破坏效果。游戏安全漏洞属于常规漏洞的子类&#xff0c;常规漏洞的分类如下图所示&#xff1a; 通过以上的漏洞分类图可知游戏漏洞属于常规…

MATLAB | 如何绘制github同款日历热力图

应粉丝要求&#xff0c;出一个类似于github热图的日历热力图&#xff0c;大概长这样&#xff1a; 依旧工具函数放在文末&#xff0c;如有bug请反馈并去gitee下载更新版。 使用教程 使用方式有以下几种会慢慢讲到&#xff1a; heatmapDT(Year,T,V)heatmapDT(Year,T,V,MonLim)h…

被称为“眼黄金”的叶黄素究竟是什么?叶黄素则能过滤蓝光

人眼视觉依赖于黄斑的中心凹陷。黄斑中含有大量的叶黄素&#xff0c;因此被称为“黄斑”。叶黄素&#xff0c;也被称为“眼黄金”&#xff0c;是人类视网膜中最重要的营养物质。它含有黄斑&#xff08;视觉中心&#xff09;和晶状体&#xff0c;特别是黄斑中含有高浓度的叶黄素…

外部中断实验

基础知识及实验目标 目标&#xff1a;通过中断来实现按键对小灯的控制。 WK_UP 翻转小灯&#xff1b; KEY 1控制 DS1按一次亮&#xff0c;再按一次灭&#xff1b;KEY 0控制DS0&#xff0c;按一次亮&#xff0c;再按一次灭。 触发中断的意思就是&#xff1a;当这个IO口达到触发…

MathType公式使用技巧汇总——Mathtype怎么在word中编辑公式?论文中公式有哪技巧?有哪些注意事项?论文中的公式怎么写?

文章目录1 Mathtype安装2 word 段落间插入公式3 文字间嵌入&#xff08;内联&#xff09;公式4 公式修改5 不要使用键盘上的括号等符号5.1 键盘上符号引发的问题5.2 正确的符号使用方法6 常用设置6. 1公式字体大小设置6.2 公式样式设置7 公式标号设置8 MathType怎么设置下一章公…

ESP-C3入门18. 低功耗蓝牙SPP Server端功能测试

ESP-C3入门18. 低功耗蓝牙SPP Server端功能测试一、功能简介1. GATT2. SPP3. SPP Server和 SPP Client二、 SPP Server开发步骤1. 启动 GATT Server2. SPP 任务初始化3. 注册 SPP应用程序4. UART 初始化5. UART 事件处理程序二、完整程序1. 代码和注释2. 运行方法一、功能简介 …

【SQL 必知必会】- 第八课 使用函数处理数据

目录 函数 函数带来的问题 可移植&#xff08;portable&#xff09; 是否应该使用函数&#xff1f; 使用函数 文本处理函数 SOUNDEX 支持 日期和时间处理函数 数值处理函数 函数 函数带来的问题 与几乎所有DBMS 都等同地支持SQL 语句&#xff08;如SELECT&#xff09;不同&am…

Selenium Web UI 自动化分布式运行:SeleniumGrid

简介&#xff1a;Selenium Grid是selenium的三大组件之一&#xff0c;它允许Selenium-RC针对规模庞大的测试案例集或者需要在不同环境中运行的测试案例集进行扩展。通过将客户端命令发送到远程浏览器的实例, Selenium Grid 允许在远程计算机 (虚拟或真实) 上执行WebDriver脚本.…