mybatis百科-结果集映射类ResultMap

@

ResultMap 对应的是结果集 <resultMap>中的一个结果集。 其基本组成部分中, 含有 ResultMapping 对象。

其组成大致如下:

结果集映射类

本文, 主要讲解一下该类的组成。

1 成员变量

  // resultMap 节点的 id
  private String id;
  // resultMap 节点的 type
  private Class<?> type;
  // 用于记录 <discriminayor> 节点之外的其他映射关系
  private List<ResultMapping> resultMappings;
  // 记录映射关系中带有 ID 标记的映射关系。 如 id, constructor 等节点
  private List<ResultMapping> idResultMappings;
  // 记录映射关系中有 Constructor 标记的映射关系
  private List<ResultMapping> constructorResultMappings;
  // 记录映射关系中没有 Constructor 标记的映射关系
  private List<ResultMapping> propertyResultMappings;
  // 记录所有映射关系中涉及 column 属性的集合
  private Set<String> mappedColumns;
  private Set<String> mappedProperties;
  // 鉴别器, 对应 <discriminayor> 节点
  private Discriminator discriminator;
  // 是否含有嵌套的结果映射, 如果某个映射关系中有 resultMap, 没有 resultSet , 则为true
  private boolean hasNestedResultMaps;
  // 是否存在嵌套查询
  private boolean hasNestedQueries;
  // 是否开启自动映射
  private Boolean autoMapping;

2 构造函数

只有默认构造函数

  private ResultMap() {
  }

3 其他函数

3.1 setter 和 getter 函数

对象创建使用的是建造者模式, 因此,只有部分成员变量含有 setter 函数。而除了 Configuration 对象, 其他都含有 getter 函数。

4 静态内部类

4.1 成员变量

  private ResultMap resultMap = new ResultMap();

是要建造的对象。

4.2 构造函数

public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings) {
    this(configuration, id, type, resultMappings, null);
}

public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings, Boolean autoMapping) {
    resultMap.configuration = configuration;
    resultMap.id = id;
    resultMap.type = type;
    resultMap.resultMappings = resultMappings;
    resultMap.autoMapping = autoMapping;
}

没有默认构造函数, 必须要给ResultMap对象的一些成员变量赋值。

4.3 建造者相关的函数

    public Builder discriminator(Discriminator discriminator) {
      resultMap.discriminator = discriminator;
      return this;
    }

discriminator, 赋值后返回对象本身。

负责建造对象一些逻辑的函数。

 public ResultMap build() {
    if (resultMap.id == null) {
      throw new IllegalArgumentException("ResultMaps must have an id");
    }
    resultMap.mappedColumns = new HashSet<>();
    resultMap.mappedProperties = new HashSet<>();
    resultMap.idResultMappings = new ArrayList<>();
    resultMap.constructorResultMappings = new ArrayList<>();
    resultMap.propertyResultMappings = new ArrayList<>();
    final List<String> constructorArgNames = new ArrayList<>();
    
    // 遍历 resultMappings
    for (ResultMapping resultMapping : resultMap.resultMappings) {
      // 是否存在嵌套查询
      resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
      // 是否存在嵌套的结果
      resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null);
      // 获取列名
      final String column = resultMapping.getColumn();
      if (column != null) {
        // 列名转大写添加到 mappedColumns 结果集中
        resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
      } else if (resultMapping.isCompositeResult()) {
        for (ResultMapping compositeResultMapping :   resultMapping.getComposites()) {
          final String compositeColumn = compositeResultMapping.getColumn();
          if (compositeColumn != null) {
            resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));
          }
        }
      }
      // 获取列映射对应的属性
      final String property = resultMapping.getProperty();
      if(property != null) {
        resultMap.mappedProperties.add(property);
      }
      if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
        resultMap.constructorResultMappings.add(resultMapping);
        if (resultMapping.getProperty() != null) {
          constructorArgNames.add(resultMapping.getProperty());
        }
      } else {
        resultMap.propertyResultMappings.add(resultMapping);
      }
      if (resultMapping.getFlags().contains(ResultFlag.ID)) {
        resultMap.idResultMappings.add(resultMapping);
      }
    }
    if (resultMap.idResultMappings.isEmpty()) {
      resultMap.idResultMappings.addAll(resultMap.resultMappings);
    }
    if (!constructorArgNames.isEmpty()) {
      final List<String> actualArgNames = argNamesOfMatchingConstructor(constructorArgNames);
      if (actualArgNames == null) {
        throw new BuilderException("Error in result map '" +   resultMap.id
            + "'. Failed to find a constructor in '"
            + resultMap.getType().getName() + "' by arg names " + constructorArgNames
            + ". There might be more info in debug log.");
      }
      Collections.sort(resultMap.constructorResultMappings, (o1, o2) -> {
        int paramIdx1 = actualArgNames.indexOf(o1.getProperty());
        int paramIdx2 = actualArgNames.indexOf(o2.getProperty());
        return paramIdx1 - paramIdx2;
      });
    }
    // lock down collections
    resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
    resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
    resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
    resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
    resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);
    return resultMap;
}

4.4 获取配置的构造方法参数列表

主函数是argNamesOfMatchingConstructor。 其功能主要是获取参数名。

private List<String> argNamesOfMatchingConstructor(List<String> constructorArgNames) {
  // 获取声明的构造方法
  Constructor<?>[] constructors = resultMap.type.getDeclaredConstructors();
  // 遍历每个构造方法
  for (Constructor<?> constructor : constructors) {
    // 获取构造方法的参数类型
    Class<?>[] paramTypes = constructor.getParameterTypes();
    // 参数长度和获取到参数类型数量一致
    if (constructorArgNames.size() == paramTypes.length) {
      // 获取构造函数的参数名称
      List<String> paramNames = getArgNames(constructor);
      if (constructorArgNames.containsAll(paramNames)
          && argTypesMatch(constructorArgNames, paramTypes, paramNames)) {
        return paramNames;
      }
    }
  }
  return null;
}

getArgNames获取构造函数的参数名

private List<String> getArgNames(Constructor<?> constructor) {
  List<String> paramNames = new ArrayList<>();
  List<String> actualParamNames = null;
  // 获取参数的注解
  final Annotation[][] paramAnnotations = constructor.getParameterAnnotations();
  int paramCount = paramAnnotations.length;
  for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
    String name = null;
    for (Annotation annotation : paramAnnotations[paramIndex]) {
      if (annotation instanceof Param) {
        name = ((Param) annotation).value();
        break;
      }
    }
    if (name == null && resultMap.configuration.isUseActualParamName()) {
      if (actualParamNames == null) {
        actualParamNames = ParamNameUtil.getParamNames(constructor);
      }
      if (actualParamNames.size() > paramIndex) {
        name = actualParamNames.get(paramIndex);
      }
    }
    paramNames.add(name != null ? name : "arg" + paramIndex);
  }
  return paramNames;
}
}

argTypesMatch方法用来检查构造方法参数是否匹配

    private boolean argTypesMatch(final List<String> constructorArgNames,
        Class<?>[] paramTypes, List<String> paramNames) {
      for (int i = 0; i < constructorArgNames.size(); i++) {
        Class<?> actualType = paramTypes[paramNames.indexOf(constructorArgNames.get(i))];
        Class<?> specifiedType = resultMap.constructorResultMappings.get(i).getJavaType();
        if (!actualType.equals(specifiedType)) {
          if (log.isDebugEnabled()) {
            log.debug("While building result map '" + resultMap.id
                + "', found a constructor with arg names " + constructorArgNames
                + ", but the type of '" + constructorArgNames.get(i)
                + "' did not match. Specified: [" + specifiedType.getName() + "] Declared: ["
                + actualType.getName() + "]");
          }
          return false;
        }
      }
      return true;
    }

一起学 mybatis

你想不想来学习 mybatis? 学习其使用和源码呢?那么, 在博客园关注我吧!!

我自己打算把这个源码系列更新完毕, 同时会更新相应的注释。快去 star 吧!!

mybatis最新源码和注释

github项目

posted @ 2018-10-23 23:13  阿进的写字台  阅读(1662)  评论(0编辑  收藏  举报