1. 程式人生 > >mybatis百科-結果集對映類ResultMap

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;
    }