@

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

其组成大致如下:

mybatis百科-结果集映射类ResultMap-LMLPHP

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

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最新源码和注释

mybatis百科-结果集映射类ResultMap-LMLPHP

05-11 13:02