Mybatis枚举类型转换

news2024/11/19 18:36:36

Mybatis枚举类型转换

类型转换器源码分析

在Mybatis的TypeHandlerRegistry中,添加了常用的类转换器,其中默认的枚举类型转换器是EnumTypeHandler。

public final class TypeHandlerRegistry {
  ....
  
  public TypeHandlerRegistry(Configuration configuration) {
    this.unknownTypeHandler = new UnknownTypeHandler(configuration);

    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());
    ...

EnumTypeHandler.java,默认使用的是枚举的名称设置参数和转换枚举类型。

public EnumTypeHandler(Class<E> type) {
    if (type == null) {
      throw new IllegalArgumentException("Type argument cannot be null");
    }
    this.type = type;
  }

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (jdbcType == null) {
      ps.setString(i, parameter.name());
    } else {
      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
    }
  }

  @Override
  public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
    String s = rs.getString(columnName);
    return s == null ? null : Enum.valueOf(type, s);
    ...

以下代码展示了如何为确定枚举类型的类型转换器。
在这里插入图片描述

  1. 首先直接获取对应类型的类型型转换器,包括原始类型,包括raw type(原始类型,对应Class),parameterized types(参数化类型), array types(数组类型),这是最精确的匹配。
  2. 如果是Class类型且枚举类型是其接口或父类,如果是匿名类,寻找其父类的类型转换器,否则再不断递归寻找该枚举类的接口类型转换器,如果没有找到,直接利用反射获defaultEnumHandler的的对象,专门用于处理该枚举类型,在图中是GroupStatusEnum。
  3. 如果不是枚举类型,则再尝试其父类。

getInstance方法如下

public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    if (javaTypeClass != null) {
      try {
        Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
        return (TypeHandler<T>) c.newInstance(javaTypeClass);
      } catch (NoSuchMethodException ignored) {
        // ignored
      } catch (Exception e) {
        throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
      }
    }
    try {
      Constructor<?> c = typeHandlerClass.getConstructor();
      return (TypeHandler<T>) c.newInstance();
    } catch (Exception e) {
      throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
    }
  }

自定义通用枚举类型

  1. 为项目中所有枚举类型定一个接口

    public interface BaseEnum {
        Integer getValue();
    }
    
  2. 枚举类实现该接口

    @AllArgsConstructor
    @Getter
    public enum GroupStatusEnum implements BaseEnum {
        DISBANDED("已解散", 0),
        NORMAL("正常", 1);
        private final String desc;
        private final Integer value;
    }
    
  3. 定义通用枚举类型转换器

    public class GenericEnumHandler<E extends BaseEnum> implements TypeHandler<E> {
    
        private final Map<Integer, E> map = new HashMap<>();
    
        public GenericEnumHandler(Class<E> clazz) {
            E[] constants = clazz.getEnumConstants();
            for (E constant : constants) {
                map.put(constant.getValue(), constant);
            }
        }
    
        @Override
        public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
            ps.setInt(i, parameter.getValue());
        }
    
        @Override
        public E getResult(ResultSet rs, String columnName) throws SQLException {
            return map.get(rs.getInt(columnName));
        }
    
        @Override
        public E getResult(ResultSet rs, int columnIndex) throws SQLException {
            return map.get(rs.getInt(columnIndex));
        }
    
        @Override
        public E getResult(CallableStatement cs, int columnIndex) throws SQLException {
            return map.get(cs.getInt(columnIndex));
        }
    }
    

按照上述源码分析流程,当GroupStatusEnum第一次需要转化数据库的int时,mybatis去寻找类型转换器。

  • 我们没有为这种类型定义专门的类型转换器(TypeHandler<GroupStatusEnum>)。
  • 该类不是内部类。
  • 该类实现了BaseEnum接口,但是我们没有为BaseEnum定义类型转换器。
  • 使用该类和默认的枚举类利用反射构造一个对象处理该枚举,即new GenericEnumTypeHandler(GroupStatusEnum.class)。

使用方法

mybatis:
  configuration:
    local-cache-scope: statement
    jdbc-type-for-null: null
    use-generated-keys: true
    cache-enabled: false
    map-underscore-to-camel-case: true
    default-enum-type-handler: com.windcf.easychatjava.typehandler.GenericEnumHandler
  mapper-locations: classpath:/mappers/**/*.xml
#  type-handlers-package: com.windcf.easychatjava.typehandler

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1707569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第 8 章 机器人平台设计之传感器(自学二刷笔记)

重要参考&#xff1a; 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 8.6.1 传感器_激光雷达简介 激光雷达是现今机器人尤其是无人车领域及最重要、最关键也是最常见的传感器之一&…

opencv c++编程基础

1、图片的本质 图像在 OpenCV 中的本质 在 OpenCV 中&#xff0c;图像被表示为一个多维数组&#xff0c;其中每个元素对应于图像中的单个像素。图像的维度取决于其通道数和像素数。 **通道数&#xff1a;**图像可以有多个通道&#xff0c;每个通道存储图像的不同信息。例如&…

RabbitMQ 发布订阅

RabbitMQ 发布订阅视频学习地址&#xff1a; 简单模式下RabbitMQ 发布者发布消息 消费者消费消息 Publist/Subscribe 发布订阅 在 RabbitMQ 中&#xff0c;发布订阅模式是一种消息传递方式&#xff0c;其中发送者&#xff08;发布者&#xff09;不会将消息直接发送到特 定的…

8.微信小程序之自定义组件

目录 1. 创建-注册-使用组件 1.1 创建自定义组件 1.2 使用自定义组件 2. 自定义组件-数据和方法 3. 自定义组件-属性 4. 组件 wxml 的 slot 5. 组件样式以及注意事项 6. 组件样式隔离 7. 数据监听器 8. 组件间通信与事件 8.1 父往子传值 8.2 子往父传值 8.3 获取…

十四天学会Vue——Vue核心(理论+实战)上篇(第一天)

一、Vue核心&#xff08;上篇&#xff09; 热身tops&#xff1a;选取开发模式 ①用于开发模式 我们只需要知道 我们是开发模式&#xff0c;开发模式他会跟你提示代码出现错误的地方以及出错原因&#xff0c;而生产模式比较简洁。 ②用于生产模式 1.1 new Vue()实例 了解Vue&a…

shell脚本的基础应用

规范脚本的构成 #&#xff01;/bin/bash # 注释信息 可执行的语句 执行脚本的方法 有1.添加x权限 ,绝对路经&#xff0c;或者相对路径2. 使用解释器 不需加x,root...bash...bash..echo 3,用source&#xff0c; 开机root ...bash ...echo bash -x /opt/test01.sh &#xff…

Linux网络-Socket套接字_Windows与Linux端双平台基于Udp传输协议进行多线程跨平台的服务器与客户端网络通信的简易聊天室实现

文章目录 一、Socket套接字二、socket 常见API1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length…

话术巧妙分隔沟通效果更佳看看这个小技巧

客服回复客户咨询&#xff0c;如果遇到比较复杂的问题&#xff0c;经常会有大段的文字回复&#xff0c;用聊天宝的分段符功能&#xff0c;在需要分段的地方点击右上角的“插入分隔符”&#xff0c;就可以在指定位置分段&#xff0c;实现多段发送的目的。 前言 客服回复客户咨询…

Python-3.12.0文档解读-内置函数map()详细说明+记忆策略+常用场景+巧妙用法+综合技巧

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 详细说明 map(function, iterable, *iterables) 参数 返回值 示例 注意事项 参考…

CHI Read传输——CHI(3)

目录 一、Read操作概览 二、DMT(Direct Memory Transfer) 三、DCT (Direct Cache Transfer) 四、without Direct Data Transfer 五、ReadNoSnp and ReadOnce* structure with DMT 本篇我们来介绍一下CHI传输类型中的Read 一、Read操作概览 read操作有以下几种&#xff1…

自适应星空背景个人导航单页(附带源码)

自适应星空背景个人导航单页 效果图部分源码领取源码下期更新预报 效果图 部分源码 function Star(id, x, y) {this.id id;this.x x;this.y y;this.r Math.floor(Math.random() * 2) 1;var alpha (Math.floor(Math.random() * 10) 1) / 10 / 2;this.color "rgba(…

QColor官网文档简介

颜色可以用不同的模型来进行表示,常见的有RGB,HSV或者CMYK.QColor基于RGB值创建颜色,如果要转接到HSV或者CMYK需要使用转接函数toHsv() toCmyk() 返回期望格式的副本 get...和set...函数具体参见文档用isValid()检查RGB颜色是否合法颜色组成部分可以单独检索QRgb是一种无符号整…

第98天:权限提升-WIN 全平台MSF 自动化CS 插件化EXP 筛选溢出漏洞

目录 思维导图 前置知识 案例一&#xff1a; Web&Win2008-人工手动&全自动msf-筛选&下载&利用 手动 全自动msf 案例二: Web&Win2019-CS 半自动-反弹&插件&利用 思维导图 前置知识 提权方式&#xff0c;这里讲的是溢出漏洞 windows权限 常…

⌈ 传知代码 ⌋ 高速公路车辆速度检测软件

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

C++学习/复习8--STL简介/六大组件/缺陷

一、STL简介 二、六大组件 三、面试题 四、STL缺陷

实现按块复制元素的进阶技巧

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、按块复制元素的重要性 二、使用LED模块创建数组并复制 三、实现按块复制的具体步骤 四…

粤嵌—2024/5/28—最大正方形(✔)

代码实现&#xff1a; 方法一&#xff1a;模拟——超时 int maximalSquare(char **matrix, int matrixSize, int *matrixColSize) {int maxSide 0;if (matrix NULL || matrixColSize NULL || matrixSize < 0 || matrixColSize[0] < 0) {return 0;}for (int i 0; i &l…

Cesium For Unity 在Unity中无法下载的问题

Unity 下载失败&#xff0c;提供百度网盘“com.cesium.unity-1.10.0.tgz”下载链接 链接&#xff1a;https://pan.baidu.com/s/1PybXQ8EvkRofOKD6rSN66g?pwd1234 提取码&#xff1a;1234 导入方法&#xff1a; 1.打开PackageManager;Window-PackageManager 2.在PackageMan…

Golang | Leetcode Golang题解之第104题二叉树的最大深度

题目&#xff1a; 题解&#xff1a; func maxDepth(root *TreeNode) int {if root nil {return 0}queue : []*TreeNode{}queue append(queue, root)ans : 0for len(queue) > 0 {sz : len(queue)for sz > 0 {node : queue[0]queue queue[1:]if node.Left ! nil {queue…

酒店报修进入智能时代:无纸化系统的全面革新

在这个信息爆炸的时代&#xff0c;面对酒店的设备故障你还在用纸质工单来报修吗&#xff1f;那简直像是石器时代的遗风&#xff01;一场酒店服务的革命性变革正在悄然兴起&#xff0c;它将彻底颠覆你对传统报修方式的认知。想象一下&#xff0c;当客人在房间遇到水龙头漏水&…