Redission 使用Jackson处理LocalDateTime的一些坑

@(redis)

文章目录

  • Redission 使用Jackson处理LocalDateTime的一些坑
    • 不支持`jsr310`的问题(浅坑)
      • 准备
      • 问题
      • 解决
    • 读取 `LocalDateTime`类型的值的问题(深坑)
      • 准备
      • 问题
      • 解决
    • 总结

Redission 使用Jackson处理LocalDateTime的一些坑

当我们想要Redission 存取 LocalDateTime类型的值时,会碰上一些坑,有些坑很浅,有些坑很深。

不支持jsr310的问题(浅坑)

准备

不做任何处理,只是要求使用Jackson 来做序列号和反序列化的处理,代码如下:

配置RedissonClient 的代码:

    private RedissonClient getRedissonClient(){Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(30);JsonJacksonCodec jacksonCodec = new JsonJacksonCodec();jacksonCodec.getObjectMapper().configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);config.setCodec(jacksonCodec);return Redisson.create(config);}

测试代码:

    @Testpublic void testRedissonLocalDateTime(){LocalDateTime now = LocalDateTime.now();RedissonClient redissonClient = getRedissonClient();//默认编码器(Java序列化和反序列化)BucketRBucket<LocalDateTime> voRBucket = redissonClient.getBucket("testLocalDateTime");voRBucket.set(now);System.out.println(voRBucket.get());}

测试结果:

java.lang.IllegalArgumentException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling

问题

发现这个问题了之后,搜索一下关键词很容易找到解决方案。Jackson缺少了jsr310的注册,所以补充这个就可以。

解决

修改配置RedissonClient 的代码,增加支持支持jsr310,如果没有引入对应依赖的,需要增加对应依赖的引入。

    private RedissonClient getRedissonClient(){Config config = new Config();config.useSingleServer().setAddress("redis://47.96.74.163:6379").setDatabase(30);JsonJacksonCodec jacksonCodec = new JsonJacksonCodec();jacksonCodec.getObjectMapper()//补充支持jsr310.registerModule(new JavaTimeModule()).configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);config.setCodec(jacksonCodec);return Redisson.create(config);}

调整代码后,测试非常顺利,正确的存储了数据,Redis上的数据也正确,控制台上的数据也正确。代码可以生产使用了。

读取 LocalDateTime类型的值的问题(深坑)

准备

在上面的代码中,我们通过System.out.println(voRBucket.get()); 代码读取了存储在LocalDateTime的值,结果输出和我们预想的一样,看Redis上的数据保存的值也是符合预期的。但当我们将读取的代码调整下的时候,就会出现一个神奇的问题。

调整后测试代码如下:

	@Testpublic void testRedissonLocalDateTime2(){LocalDateTime now = LocalDateTime.now();RedissonClient redissonClient = getRedissonClient();//默认编码器(Java序列化和反序列化)BucketRBucket<LocalDateTime> voRBucket = redissonClient.getBucket("testLocalDateTime");voRBucket.set(now);System.out.println(voRBucket.get());//取出LocalDateTime 对象,再输出LocalDateTime localDateTime = voRBucket.get();System.out.println(localDateTime);}

测试结果如下:

java.lang.ClassCastException: java.lang.String cannot be cast to java.time.LocalDateTime

问题

新增加的LocalDateTime localDateTime = voRBucket.get(); 这行代码抛出异常了,异常的内容很直白,但处理却有点麻烦。因为我们肯定是支持了jsr310,肯定是支持StringLocalDateTime的,而且我们也通过泛型告诉了它,这里要转换成LocalDateTime,但这里好像很傻,它并不知道应该要做转换,而只是用了Java的强转,所以抛异常了。

但是为什么System.out.println(voRBucket.get()); 这里获取的时候没有抛异常呢?都是get方法,难道还能不一样?

实际情况确实是不一样的,之System.out.println(voRBucket.get()); 这个方法不会抛异常,因为它压根就没做LocalDateTime转换,因为System.out.println 调用的是Object 类型的参数方法,String直接向上转型为Object 是不用调转换方法的,因此不需要转换。

解决

因此我们需要明确告知Redisson ,将返回的结果帮我转换成LocalDateTime对象,因此我们获取Bucket的时候,就得告知它,我们Bucket的值得用什么Codec来转换。于是我们找到了TypedJsonJacksonCodec 这个Jackson 专用的Codec, 通过它构建一个Codec,改进后代码如下:

    @Testpublic void testRedissonLocalDateTime3(){LocalDateTime now = LocalDateTime.now();RedissonClient redissonClient = getRedissonClient();//使用指定的编码器BucketTypedJsonJacksonCodec localDateTimeCodec = new TypedJsonJacksonCodec(new TypeReference<LocalDateTime>() {});RBucket<LocalDateTime> voRBucket = redissonClient.getBucket("testLocalDateTime",localDateTimeCodec);voRBucket.set(now);System.out.println(voRBucket.get());}

运行结果:

java.lang.IllegalArgumentException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling

这个问题又出现了,这个时候可能会想配置RedissonClient 的时候,不是已经加了jsr310的支持么?为什么这里还有问题?一切的问题很其实很清晰,看下TypedJsonJacksonCodec 的构造方法就知道。

    public TypedJsonJacksonCodec(TypeReference<?> valueTypeReference) {this(valueTypeReference, new ObjectMapper());}

很明显,这个构造方法,默认new了一个新的ObjectMapper,而不是用我们之前配置的ObjectMapper。因此我们在构建TypedJsonJacksonCodec 时,需要将配置的ObjectMapper也传入。最终解决问题的代码:

    @Testpublic void testRedissonLocalDateTime4(){LocalDateTime now = LocalDateTime.now();RedissonClient redissonClient = getRedissonClient();//使用指定的编码器BucketJsonJacksonCodec jacksonCodec = (JsonJacksonCodec)redissonClient.getConfig().getCodec();TypedJsonJacksonCodec localDateTimeCodec = new TypedJsonJacksonCodec(new TypeReference<LocalDateTime>() {},jacksonCodec.getObjectMapper());RBucket<LocalDateTime> voRBucket = redissonClient.getBucket("testLocalDateTime",localDateTimeCodec);voRBucket.set(now);System.out.println(voRBucket.get());}

当然更好的写法是,将TypedJsonJacksonCodec localDateTimeCodec的定义成静态的

    private static final JsonJacksonCodec jacksonCodec = new JsonJacksonCodec(JsonUtils.getRedisOm());private static final TypedJsonJacksonCodec localDateTimeValueCodeC = new TypedJsonJacksonCodec(new TypeReference<LocalDateTime>() {},jacksonCodec.getObjectMapper());

总结

其实这里最大坑就是我们平时会用System.out.println来验证我们预期,但没有很容易忽视这个方法是被重载了多次的,并且Jackson做序列化时,对于泛型是不是指定一个接受的泛型类型就可以的,必须得明确指定泛型的类型,这个通常用TypeReference 这个接口的匿名类来处理。当没有指定泛型的类型时,Jackson默认是转换成Object类型来处理的,而对于System.out.println来说,Object类型它会默认调用toString方法来输出,而如果这个Object类型本身就是String强转过来的,那么输出的就是String本身了。在这个问题里,LocalDateTime 保存的字符串和我们取出来的字符串并输出的是一样的,因此只看控制台输出,它们是一样的。但如果我们用对象去接就会发现,默认返回不是LocalDateTime类型的对象,而是一个String对象。

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

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

相关文章

TypeScript 类型兼容性

TypeScript 类型兼容性 在前端开发中&#xff0c;使用 TypeScript 可以提供更强大的类型检查和类型安全。然而&#xff0c;了解 TypeScript 中的类型兼容性是至关重要的&#xff0c;因为它涉及如何处理不同类型之间的关系&#xff0c;以及在这些类型之间进行无缝的交互。本文将…

Leetcode刷题笔记--Hot61-70

1--课程表&#xff08;207&#xff09; 主要思路&#xff1a; 用 in 记录每一门课程剩余的先修课程个数&#xff0c;当剩余先修课程个数为0时&#xff0c;将该课程加入到队列q中。 每修队列q中的课程&#xff0c;以该课程作为先修课程的所有课程&#xff0c;其剩余先修课程个数…

Kubernetes实战(三)-k8s节点设置cpu高于多少就不调度

1 k8s节点设置的概念和原理 k8s是Google开源的容器集群管理系统&#xff0c;用于自动化部署、扩展和管理容器化应用程序。在k8s中&#xff0c;Node是指容器运行的物理或虚拟机器。Node可以是一个物理机或一个虚拟机器&#xff0c;k8s通过其调度器将Pod调度到每个Node上。对于一…

人机环境系统中的“人”、“机”、“环境”

人机环境系统中的“人”、“机”、“环境”是指在一个系统中&#xff0c;人、机和环境三者的相互作用和影响&#xff0c;三者之间的相互作用和影响非常复杂&#xff0c;需要进行有效的协调和管理才能实现系统的高效运转或预期的目标。因此&#xff0c;人机环境系统的设计和优化…

vue elementui的select组件实现滑到底部分页请求后端接口

vue elementui的select组件实现滑到底部分页请求后端接口 1.实现效果2.实现原理 1.实现效果 老规矩&#xff0c;直接上最后的实现效果 2.实现原理 直接上代码 <el-form-item class"diagmosisItem" label"诊断" v-scroll"handleScroll">…

✔ ★【备战实习(面经+项目+算法)】 10.15学习时间表

✔ ★【备战实习&#xff08;面经项目算法&#xff09;】 坚持完成每天必做如何找到好工作1. 科学的学习方法&#xff08;专注&#xff01;效率&#xff01;记忆&#xff01;心流&#xff01;&#xff09;2. 每天认真完成必做项&#xff0c;踏实学习技术 认真完成每天必做&…

【微信小程序开发】基础语法篇

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于小程序的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.视图层 1.数据绑定 wxml js 2 .列…

Python学习六

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

前端工程化知识系列(4)

目录 31. 你是否了解前端性能优化的指标&#xff0c;例如首次内容绘制&#xff08;FCP&#xff09;、最大内容绘制&#xff08;LCP&#xff09;和累计布局位移&#xff08;CLS&#xff09;&#xff1f;如何针对这些指标进行优化&#xff1f;32. 你有没有经验使用服务端渲染&…

Yum安装JDK11

一、安装命令 &#xff1a; yum install java-11-openjdk二、执行以下命令来查看 JDK 11 的安装信息&#xff1a; yum list installed | grep java-11-openjdk三、找到 JDK 11 的软件包名称&#xff08;使用以下命令来查询软件包的安装位置&#xff09;&#xff1a; rpm -ql…

AnolisOS升级SSH,不升级SSL

由于ssh有漏洞需要升级&#xff0c;但是为了最小化升级不影响ssl&#xff0c;因为ssl里面带了加密库&#xff0c;系统中很多核心服务的加密都是用ssl进行加密的&#xff08;像网络服务&#xff0c;系统用户登录等&#xff09;&#xff0c;如果ssl升级出现不兼容&#xff0c;就可…

Java实现B树

1.介绍 B树是一种自平衡的搜索树数据结构&#xff0c;常用于数据库和文件系统中的索引结构。它具有以下好处和功能&#xff1a; 高效的查找操作&#xff1a;B树的特点是每个节点可以存储多个关键字&#xff0c;并且保持有序。通过在节点上进行二分查找&#xff0c;可以快速定位…

260. 只出现一次的数字 III

给你一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。 你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。 示例 1&#xff1a; 输入&…

计算机基础知识32

Socket抽象层(socket编程) # Socket是在应用层和传输层之间的一个抽象层&#xff0c;它把TCP/IP层复杂的操作抽象为几个简单 的接口供应用层调用已实现进程在网络中通信 socket () 对象 bind () 函数来绑定 listen () 监听&#xff0c;等别人电话 accept&#xff08;&#…

canal rocketmq

上篇文章canal 消费进度说到直接使用ClusterCanalConnector并发消费是有问题的&#xff0c;可以先用单点将canal事件发送到mq中&#xff0c;再由mq并发处理&#xff0c;另外mq还可以做到削峰的作用&#xff0c;让canal数据不至于阻塞。 使用队列&#xff0c;可以自己起一个单实…

AI电销机器人好不好用关键是什么?

影响AI电销机器人是否好用的两个因素分别是&#xff0c;识别系统以及线路。 有很多电销企业都想找一个好用的AI电销机器人&#xff0c;可是什么样的机器人才是好用的机器人呢?有哪些因素会影响AI电销机器人好不好用呢? 添加图片注释&#xff0c;不超过 140 字&#xff08;可选…

groupnorm_backward反向公式推导

前向 均值 μ n g ∑ i 1 M ( X i ) M (1) {\large \mathit{\color{Blue} \mu_{ng} \frac{\sum_{i1}^M(X^{i})}{M}} } \tag{1} μng​M∑i1M​(Xi)​(1) 方差 σ n g 2 ∑ i 1 M ( X i − μ n g ) M (2) {\large \mathit{\color{Blue} \sigma_{ng}^2 \frac{\sum_{i …

在 Linux 上保护 SSH 服务器连接的 8 种方法

SSH 是一种广泛使用的协议&#xff0c;用于安全地访问 Linux 服务器。大多数用户使用默认设置的 SSH 连接来连接到远程服务器。但是&#xff0c;不安全的默认配置也会带来各种安全风险。 具有开放 SSH 访问权限的服务器的 root 帐户可能存在风险。尤其是如果使用的是公共 IP 地…

qt中json类

目录 QJsonValue QJsonObject QJsonArray QJsonDocument 案例&#xff1a; Qt 5.0开始提供了对Json的支持&#xff0c;我们可以直接使用Qt提供的Json类进行数据的组织和解析&#xff0c;下面介绍4个常用的类。 QJsonValue 该类封装了JSON支持的数据类型。 布尔类型&#xf…

【Power BI】Power BI 入门指南:版本、下载和报表创建的步骤

文章目录 一、前言二、了解 Power BI 版本三、下载 Power BI Desktop四、如何开始使用 Power BI Desktop五、在 Power BI Desktop 中创建报表六、文末总结 一、前言 Power BI 是微软于 2013 年推出的产品&#xff0c;为一款商业智能与数据可视化工具。它通过引人注目的视觉效果…