zoukankan      html  css  js  c++  java
  • 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项目

  • 相关阅读:
    日期格式化
    堆栈
    编写自己的C头文件
    线性表(gcc实现)
    排序的稳定性
    git创建和合并分支
    当单选input框改变时触发
    css样式定义
    div块显示在一行
    redis数据结构(一)
  • 原文地址:https://www.cnblogs.com/homejim/p/9840373.html
Copyright © 2011-2022 走看看