在 MongoDB
中 ObjectId
是一个 12
字节的 BSON
类型数据(我们在可视化数据库工具中看到的是 24
位的 16
进制形式),其具体数据结构如下:
4
个字节为时间戳(timestamp
);3
个字节机器标识码(randomValue1
);2
个字节为进程 id
(randomValue2
);3
个字节是随机计数器值 (counter
)。讲完 ObjectId
的存储格式后,再来说下如何解决序列化问题,本文使用了基于 Gson
的 Java
序列化工具包,本文使用的完整代码也已上传到 GitHub,下面就介绍具体的解决办法。
由于接下来的解决办法需要自定义 ObjectId
的序列化类,因此需要从底层的具体存储格式开始:
Gson gson = new Gson();
TestEntity id = new TestEntity(new ObjectId("600a47a0076abd67f0d588f6"));
System.out.println(gson.fromJson(gson.toJson(id), Document.class));
// TestEntity 的类结构如下
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestEntity {
private ObjectId _id;
}
/**
* output:
* Document{{_id=
* {
* timestamp=1.611286432E9,
* counter=1.399423E7,
* randomValue1=486077.0,
* randomValue2=26608.0
* }
* }}
*/
从上面的代码和输出结果可以看出,如果为了插入数据在序列化实体时转换为 Document
类型,就会出现不和预期的结果,下面就结合前言中介绍的 ObjectId
底层存储结构来介绍 600a47a0 076abd 67f0 d588f6
这个十六进制字符串和 {timestamp=1.611286432E9, counter=1.399423E7, randomValue1=486077.0, randomValue2=26608.0}
的对应关系:
可以看到 24
位的 16
进制字符串正好和对象里面的对应字段的值相等,下面就正式开始序列化的解决办法。
在前面介绍了本文使用了基于 Gson
的 Java
序列化工具包,下面的解决方法也需要使用里面的 @JsonAdapter
这个注解,这个注解需要传入一个自定义的序列化解析类,这个自定义的类需要继承 TypeAdapter<T>
类,下面是具体的代码展示:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestEntity {
// 自定义一个名为 MongoObjectId 的类进行 ObjectId 的自定义序列化处理
@JsonAdapter(MongoObjectId.class)
private ObjectId _id;
}
下面是这个自定义序列化解析类的代码:
public class MongoObjectId extends TypeAdapter<ObjectId> {
@Override
public void write(JsonWriter out, ObjectId value) throws IOException {
// 对于需要被序列化的 value
// 如果为空就在 out 中写入空值
// 否则写入 ObjectId 的 16 进制字符串形式
// tips: ObjectId 类的 toString 方法被重写实现了返回 ObjectId 的 16 进制字符串形式
if (value == null) {
out.nullValue();
return;
}
out.value(value.toString());
}
@Override
public ObjectId read(JsonReader in) throws IOException {
// in.beginObject() 代表读取的是一个对象
// 即 {timestamp=1.611286432E9, counter=1.399423E7, randomValue1=486077.0, randomValue2=26608.0}
in.beginObject();
int i = 0;
// 将接下来要读取的四个数据先保存在数组中
long[] nums = new long[4];
while (in.hasNext()) {
// 先读取对象名
in.nextName();
// 然后将值存储到数组中
nums[i++] = in.nextLong();
}
// in.endObject() 表示对象读取完毕
in.endObject();
if (i == 0) {
return null;
}
// 将获取的数据转换为 16 进制的字符串形式用于获取 ObjectId 对象
return new ObjectId(String.format("%08x%06x%04x%06x", nums[0], nums[2], nums[3], nums[1]));
}
}
然后再使用上述的测试代码:
Gson gson = new Gson();
TestEntity id = new TestEntity(new ObjectId("600a47a0076abd67f0d588f6"));
System.out.println(gson.fromJson(gson.toJson(id), Document.class));
/**
* 输出结果如下:
* Document{{_id=600a47a0076abd67f0d588f6}}
*/
可以发现解决了 ObjectId
的序列化问题,之后只要是 ObjectId
类型的变量,加上 @JsonAdapter(MongoObjectId.class)
注解即可。
本文简单介绍了 MongoDB
的 ObjectId
数据类型的底层存储格式,以及如何通过 Gson
中的一个注解解决序列化问题,希望能够对你有所帮助。
原网址: 访问
创建于: 2024-06-21 09:58:00
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论