@

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

mybatis百科-结果集映射类ResultMap的更多相关文章

  1. mybatis百科-列映射类ResultMapping

    目录 1 成员变量 2 构造函数 3 其他函数 3.1 setter 和 getter 函数 3.2 equals 和 hashCode 函数 3.3 toString 函数 4 内部类 Builde ...

  2. MyBatis的getMapper()接口、resultMap标签、Alias别名、 尽量提取sql列、动态操作

    一.getMapper()接口 解析:getMapper()接口 IDept.class定义一个接口, 挂载一个没有实现的方法,特殊之处,借楼任何方法,必须和小配置中id属性是一致的 通过代理:生成接 ...

  3. Mybatis第七篇【resultMap、resultType、延迟加载】

    resultMap 有的时候,我们看别的映射文件,可能看不到以下这么一段代码: <resultMap id="userListResultMap" type="us ...

  4. mybatis自定义枚举转换类

    转载自:http://my.oschina.net/SEyanlei/blog/188919 mybatis提供了EnumTypeHandler和EnumOrdinalTypeHandler完成枚举类 ...

  5. mybatis 一对一 映射实体类、嵌套查询

    一对一 在SysUser 类中增加SysRole字段.1.sql语句将role.role_name映射到role.roleName上. 2.还可以在XML 映射文件中配置结果映射.<result ...

  6. Mybatis笔记四:Mybatis中的resultType和resultMap查询操作实例详解

    resultType和resultMap只能有一个成立,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,resultMap解决复杂查询是的映射问题.比 ...

  7. MyBatis中的resultType和resultMap

    MyBatis的查询在进行映射的时候,返回值类型可以使用resultType同时也可以使用resultMap.前者表示直接的返回值类型,一般是domain名称,当然这里可以写domain的全部路径也可 ...

  8. Mybatis自动生成实体类和实体映射工具

    Mybatis Mysql生成实体类 用到的Lib包: mybatis-generator-core-1.3.2.jarmysql-connector-java-5.1.30.jar 1. 创建一个文 ...

  9. mybatis mapper xml文件配置resultmap时,id行和result行有什么区别?

    mybatis mapper xml文件配置resultmap时,id行和result行有什么区别? <resultMap id = "CashInvoiceMap" typ ...

随机推荐

  1. 计算机网络TCP“三次握手”

    终于有时间写这篇文章了,最近真的比较忙! TCP协议  之 “三次握手” 引言:我们知道,TCP是面向连接的协议(相较于UDP无连接的协议),会在传送数据之前先在 发送端 & 接收端 之间建立 ...

  2. MFC Bresesnham算法

    Bresesnham算法绘制直线段 Bresenham算法的意义:高效的将图形光栅化.其计算过程中均采用加法运算,故大大减少了程序的开销. 绘制直线段(MFC中) //传入参数:起点.终点,颜色 vo ...

  3. 填坑:Windows下使用OpenSSL生成自签证书(很简单,一个晚上搞明白的,让后来者少走弯路)

    最近在学习中发现openssl 中有个坑,所有的教程都是openssl genrsa -des3 -out private.key 1024,但是产生的证书,npm start 之后就报错如下: er ...

  4. Android ListView的item背景色设置以及item点击无响应等相关问题

    Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的ite ...

  5. android build 编译打印详细过程

    我们在make otapackage编译android代码的时候,有时候需要跟踪详细的过程,包括所有的过程,可以修改build/core/Makefile,赋值hide := 为空即可

  6. 关于商米D1S,USB默认权限在关机后丢失的FAQ

    1.机器型号:商米D1S 2.机器系统版本:7.1.2 3.情况描述:双屏的机器不管是银盒子收银还是银盒子智能收银,勾选默认后重启机器还是会提示, 4.解决方案:商米厂商大约会在1月份进行系统更新,到 ...

  7. [20181214]open file using O_DIRECT.txt

    [20181214]open file using O_DIRECT.txt --//因为一个测试需要,需要写一个测试小例子,验证使用O_DIRECT打开文件每次都是从磁盘读取.--//没想到浪费1个 ...

  8. shell编程—变量(三)

    在shell脚本中,变量分两种,系统变量和自定义变量. 系统默认变量是系统自带的一些变量,如path为路径变量 用户自定义变量为在编写吧脚本的时候自己定义的一些变量 变量名命名规则 首个字符必须为字母 ...

  9. raid1 raid2 raid5 raid6 raid10的优缺点和做各自raid需要几块硬盘

    Raid 0:一块硬盘或者以上就可做raid0优势:数据读取写入最快,最大优势提高硬盘容量,比如3快80G的硬盘做raid0 可用总容量为240G.速度是一样.缺点:无冗余能力,一块硬盘损坏,数据全无 ...

  10. 一、Selenium 工作原理

    1.Selenium介绍 Selenium是用于测试Web应用程序用户界面UI的常用框架.端对端的功能测试.并且在一个多个浏览器中操作. 目前Seienium 组件主要包括Selenium IDE   ...