手写Java序列化工具
一、思考
假设给一个java bean,让你按照 json 的格式打印出来,你会怎么做?
比如这个java bean 长这样,并且创建了一个叫宝儿姐的朋友
package com.test;public class User {private String name;private Integer age;private BigDecimal mony;private List<User> childs;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public BigDecimal getMony() {return mony;}public void setMony(BigDecimal mony) {this.mony = mony;}public List<User> getChilds() {return childs;}public void setChilds(List<User> childs) {this.childs = childs;}
}public class JsonTest {public static void main(String[] args) throws Exception {User user = new User();user.setAge(18);user.setName("宝儿姐");user.setMony(new BigDecimal("-4000000.5"));List<User> userList = new ArrayList<>();User son = new User();son.setAge(1);son.setName("大壮");userList.add(son);User daughter = new User();daughter.setAge(10);daughter.setName("小美");userList.add(daughter);user.setChilds(userList);// 打印java beanprintToJson(user);// 打印集合printToJson(userList);// 打印数值printToJson(new BigDecimal("1.235"));printToJson((byte)2);printToJson((short)3);printToJson(4);printToJson(5.1F);printToJson(5.2D);printToJson(233L);// 打印字符串printToJson("小美");}private static void printToJson(User user) {// .....}
}
我们调用 printToJson 之后,期望的输出是长这样的:
{"name":"宝儿姐","childs":[{"name":"大壮","age":1},{"name":"小美","age":10}],"age":18,"mony":-4000000.5}
[{"name":"大壮","age":1},{"name":"小美","age":10}]
1.235
2
3
4
5.1
5.2
233
"小美"
那么一个简单而又没啥设计的实现方式如下:
public class JsonTest {public static void main(String[] args) throws Exception {User user = new User();user.setAge(18);user.setName("宝儿姐");user.setMony(new BigDecimal("-4000000.5"));List<User> userList = new ArrayList<>();User son = new User();son.setAge(1);son.setName("大壮");userList.add(son);User daughter = new User();daughter.setAge(10);daughter.setName("小美");userList.add(daughter);user.setChilds(userList);// 打印java beanprintToJson(user);// 打印集合printToJson(userList);// 打印数值printToJson(new BigDecimal("1.235"));printToJson((byte)2);printToJson((short)3);printToJson(4);printToJson(5.1F);printToJson(5.2D);printToJson(233L);// 打印字符串printToJson("小美");}private static <T> void printToJson(T obj) throws Exception {if (Objects.isNull(obj)) {System.out.println("");return;}Class<?> tClass = obj.getClass();StringWriter stringWriter = new StringWriter();if (tClass == String.class) {stringPrint(stringWriter, (String) obj);} else if (Number.class.isAssignableFrom(tClass)) {numberPrint(stringWriter, (Number) obj);} else if (Collection.class.isAssignableFrom(tClass)) {collectionPrint(stringWriter, (Collection) obj, null);// 省略数组,map等各种类型的打印} else {javaBeanPrint(stringWriter, obj, tClass);}System.out.println(stringWriter.toString());}private static void javaBeanPrint(StringWriter stringWriter, Object javaBean, Class<?> tClass) throws Exception {// 不考虑继承Method[] methods = tClass.getDeclaredMethods();if (Objects.isNull(methods) || methods.length == 0) {stringWriter.append("{}");return;}stringWriter.append("{");boolean hasPrev = false;for (Method method : methods) {String methodName = method.getName();if (methodName.startsWith("get") && methodName.length() > 3) {Object val = method.invoke(javaBean);if (Objects.isNull(val)) {continue;}if (hasPrev) {stringWriter.append(",");}String propertyName = methodName.substring(3);String newPropertyName;if (propertyName.length() > 1) {newPropertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);} else {newPropertyName = propertyName.substring(0, 1).toLowerCase();}stringWriter.append("\"").append(newPropertyName).append("\"").append(":");Class<?> returnType = method.getReturnType();if (returnType == String.class) {stringPrint(stringWriter, (String) val);} else if (Number.class.isAssignableFrom(returnType)) {numberPrint(stringWriter, (Number) val);} else if (Collection.class.isAssignableFrom(returnType)) {Type type = method.getGenericReturnType();collectionPrint(stringWriter, (Collection) val, type);// 省略数组,map等各种类型的打印} else {javaBeanPrint(stringWriter, val, val.getClass());}hasPrev = true;}}stringWriter.append("}");}private static void stringPrint(StringWriter stringWriter, String val) {stringWriter.append("\"").append(val).append("\"");}private static void numberPrint(StringWriter stringWriter, Number val) {if (val instanceof BigDecimal) {stringWriter.append(((BigDecimal) val).toPlainString());} else {stringWriter.append(val.toString());}}private static void collectionPrint(StringWriter stringWriter, Collection val, Type type) throws Exception {if(Objects.isNull(val) || val.size() == 0) {stringWriter.append("[]");return;}stringWriter.append("[");boolean havPrev = false;for (Object v : val) {if(Objects.isNull(v)) {continue;}if(havPrev) {stringWriter.append(",");}Class<?> vClass = v.getClass();if (vClass == String.class) {stringPrint(stringWriter, (String) v);} else if (Number.class.isAssignableFrom(vClass)) {numberPrint(stringWriter, (Number) v);} else if (Collection.class.isAssignableFrom(vClass)) {collectionPrint(stringWriter, (Collection) v, type);// 省略数组,map等各种类型的打印} else {javaBeanPrint(stringWriter, v, vClass);}havPrev = true;}stringWriter.append("]");}
}
以上是一个非常简单的实现,我们可以看到针对每种数据类型,它的序列化方式是不一样的,所以其实
我们可以使用策略模式加以改造,比如定义一个接口,加一个参数上下文,根据不同的数据类型实现
不同的序列化器。
相关文章:
手写Java序列化工具
一、思考 假设给一个java bean,让你按照 json 的格式打印出来,你会怎么做? 比如这个java bean 长这样,并且创建了一个叫宝儿姐的朋友 package com.test;public class User {private String name;private Integer age;private Bi…...
mysql面试题26:MySQL中什么是MVCC,它的底层原理是什么
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:什么是MVCC,它的底层原理是什么? MVCC(Multi-Version Concurrency Control)是一种并发控制机制,用于在数据库中实现并发事务的隔离性和一致性…...
SQL进阶 - SQL的编程规范
性能优化是一个很有趣的探索方向,将耗时耗资源的查询优化下来也是一件很有成就感的事情,但既然编程是一种沟通手段,那每一个数据开发者就都有义务保证写出的代码逻辑清晰,具有很好的可读性。 目录 引子 小试牛刀 答案 引言 …...
[NISACTF 2022]babyserialize - 反序列化+waf绕过【*】
[NISACTF 2022]babyserialize 一、解题过程二、思考总结(一)、关于题目的小细节(二)、关于弱类型比较技巧 一、解题过程 题目代码: <?php include "waf.php"; class NISA{public $fun"show_me_fl…...
docker部署Vaultwarden密码共享管理系统
Vaultwarden是一个开源的密码管理器,它是Bitwarden密码管理器的自托管版本。它提供了类似于Bitwarden的功能,允许用户安全地存储和管理密码、敏感数据和身份信息。 Vaultwarden的主要特点包括: 1. 安全的数据存储:Vaultwarden使…...
低代码开发技术选型
低代码的技术路径 低代码开发低代码开发优势低代码的技术路径1.表格驱动2.表单驱动3.数据模型4.领域模型 低代码的核心能力企业级低代码开发平台的11项关键能力低代码平台的流程引擎选型低代码平台的流程设计器选型低代码平台的表单设计器选型低代码平台的Vue.js 框架选型 低代…...
在vue2中,v-model和.sync的区别
最近在封装一个弹窗组件时,用了比较复杂的逻辑去做显示和隐藏的逻辑,在查看同事的代码之后,才知道还有更简单的方法,自己已经忘了一些API. popup组件里统一的template: <div v-ifisShowPopup> // 弹窗内容 <…...
nginx 配置
一、nginx安装 下载地址:http://nginx.org/en/download.html,和Keepalived搭配使用,防止nginx挂掉 二、nginx配置 ########### 每个指令必须有分号结束。################# #user administrator administrators; #配置用户或者组…...
【计算机视觉|人脸建模】学习从图像中回归3D面部形状和表情而无需3D监督
本系列博文为深度学习/计算机视觉论文笔记,转载请注明出处 标题:Learning to Regress 3D Face Shape and Expression from an Image without 3D Supervision 链接:[1905.06817] Learning to Regress 3D Face Shape and Expression from an I…...
Linux系统之部署h5ai目录列表程序
Linux系统之部署h5ai目录列表程序 一、h5ai介绍1.1 h5ai简介1.2 h5ai特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、安装httpd软件4.1 检查yum仓库4.2 安装httpd软件4.3 启动httpd服务4.4 查看htt…...
Java-Exception
目录 异常概念ErrorException 体系图常见运行时异常NullPointerExceptionArithmeticExceptionArrayIndexOutOfBoundExceptionClassCastExceptionNumberFormatException 常见的编译异常异常处理机制自定义异常throw和throws对比 异常是Java编程中的常见问题,了解如何…...
C++并发与多线程(2) | 线程运行开始和结束的基本方式
当程序运行起来,生成一个进程,该进程所属的主线程开始自动运行。当主线程从main()函数返回,则整个进程执行完毕。 主线程从main()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,就代表着我们这个线程运行结束。 整个进…...
vue3前端开发-flex布局篇
文章目录 1.传统布局与flex布局优缺点传统布局flex布局建议 2. flex布局原理2.1 布局原理 3. flex常见属性3.1 父项常见属性3.2 子项常见属性 4.案例实战(携程网首页) 1.传统布局与flex布局优缺点 传统布局 兼容性好布局繁琐局限性,不能再移动端很好的布局 flex布…...
网络是什么?(网络零基础入门篇)
1.如何理解局域网和广域网? 2.路由器和交换机是怎么样工作的? 3.三层交换机能不能代替路由器? -- 局域网 广域网 -- 企业网架构,运营商架构,数据中心架构 -- 局域网 通过 交换机连接的 转发 相同的ip地址…...
【JavaEE】线程安全的集合类
文章目录 前言多线程环境使用 ArrayList多线程环境使用队列多线程环境使用哈希表1. HashTable2. ConcurrentHashMap 前言 前面我们学习了很多的Java集合类,像什么ArrayList、Queue、HashTable、HashMap等等一些常用的集合类,之前使用这些都是在单线程中…...
【C++算法】is_partitioned、partition_copy和partition_point
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、is_partitioned函数:1.1 is_partitioned是什么?1.2 函数原型1.3 示例代码1.4 更多示例代码 二、partition_copy函数2.1 概念2.2 函数…...
MyBatis(JavaEE进阶系列4)
目录 前言: 1.MyBatis是什么 2.为什么要学习MyBatis框架 3.MyBatis框架的搭建 3.1添加MyBatis框架 3.2设置MyBatis配置 4.根据MyBatis写法完成数据库的操作 5.MyBatis里面的增删改查操作 5.1插入语句 5.2修改语句 5.3delete语句 5.4查询语句 5.5like查…...
『力扣每日一题15』:买卖股票的最佳时机
一、题目 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…...
Java中栈实现怎么选?Stack、Deque、ArrayDeque、LinkedList(含常用Api积累)
目录 Java中的Stack类 不用Stack有以下两点原因 1、从性能上来说应该使用Deque代替Stack。 2、Stack从Vector继承是个历史遗留问题,JDK官方已建议优先使用Deque的实现类来代替Stack。 该用ArrayDeque还是LinkedList? ArrayDeque与LinkList区别࿱…...
雷达分辨率单元、单向/双向雷达方程、天气雷达方程简介
一、点状目标 如果两个点状目标在一个分辨率单元中,经典脉冲雷达只能看到一个目标。 点状目标 二、雷达距离分辨率 对于简单的键控开/关脉冲调制: 对于使用脉冲内调制的雷达,距离分辨率取决于压缩脉冲的脉冲持续时间。脉冲压缩比(PCR)取决于传输带宽BWtx,即距离分辨率取…...
RabbitMQ之Fanout(扇形) Exchange解读
目录 基本介绍 适用场景 springboot代码演示 演示架构 工程概述 RabbitConfig配置类:创建队列及交换机并进行绑定 MessageService业务类:发送消息及接收消息 主启动类RabbitMq01Application:实现ApplicationRunner接口 基本介绍 Fa…...
Redisson—分布式集合详述
7.1. 映射(Map) 基于Redis的Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。与HashMap不同的是,RMap保持了元素的插入顺序。该对象的最大容量受Redis限制,最大元素数…...
开发做前端好还是后端好?这是个问题!
前言 随着互联网的快速发展,越来越多的人选择从事Web开发行业,而Web开发涉及到前端和后端两个方面,相信许多人都曾经对这两个方面进行过探究。而且编程世界就像一座大城市,前端开发和后端开发就像城市的两个不同街区。作为初学者&…...
运行huggingface Kosmos2报错 nameerror: name ‘kosmos2tokenizer‘ is not defined
尝试运行huggingface上的Kosmos,https://huggingface.co/ydshieh/kosmos-2-patch14-224失败,报错: nameerror: name kosmos2tokenizer is not defined查看报错代码: vi /root/.cache/huggingface/modules/transformers_modules/ydshieh/kosmos-2-patch14-224/48e3edebaeb…...
吃鸡玩家必备神器!一站式提升战斗力、分享干货!
大家好,我是吃鸡玩家。在这个视频中,我要分享一个让你瞬间提高战斗力的神器,同时让你享受到顶级游戏作战干货的盛宴!让我们一起来了解吧! 首先,我们推荐绝地求生作图工具。通过这款工具,你可以轻…...
【maven】idea中基于maven-webapp骨架创建的web.xml问题
IDEA中基于maven-webapp骨架创建的web工程,默认的web.xml是这样的。 <!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name…...
【算法题】2034. 股票价格波动
插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 题目: 给你一支股票价格的数据流。数据流…...
APSIM模型】作物模型应用案例
APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生长模拟模型之一。APSIM模型有Classic和Next Generation两个系列模型,能模拟几十种农作物、牧草和树木的土壤-植物-大气过程,被广泛应用于精细农业、水肥管理、气候变化、粮食安…...
io_uring之liburing库安装
手动编译和安装 liburing: 1.首先,从 liburing 的 GitHub 仓库中获取源代码。您可以使用以下命令克隆仓库: git clone https://github.com/axboe/liburing.git2.进入 liburing 目录: cd liburing3.运行configure ./configure …...
Python WebSocket自动化测试:构建高效接口测试框架!
为了更高效地进行WebSocket接口的自动化测试,我们可以搭建一个专门的测试框架。本文将介绍如何使用Python构建一个高效的WebSocket接口测试框架,并重点关注以下四个方面的内容:运行测试文件封装、报告和日志的封装、数据驱动测试以及测试用例…...
申请免费网站域名/合肥网络公司排名
1、每条记录包含三个数据项: 0-201-70353-x 4 24.99 第一次项是书的ISBN号,第二项是售出的册数,最后一项是书的单价。书店老板需要查询此档案,计算每本书的销售量、销售额及平均售价。 划分子问题 1.定义变量 2.进行…...
培训公司网站建设/企业网站优化软件
Kettle8.2与HBase集成一、HBase安装1.1 zookeeper单机安装1.2 HBase安装1.3 创建weblogs表,列族为pageviews二、Kettle配置三、案例演示3.1 功能描述3.2 测试数据3.3 组件实现3.4 运行验证说明:环境:Centos7 Kettle8.2 hbase-1.3.1 zookee…...
网站手机端排名怎么做/个人网站制作
文章目录前言一、依赖关系是什么?二、支持的功能总结前言 终于更新一个小的python项目来一起动手学习了,今天想看看Redis源码,可惜太慢太多,思维太乱,于是想到看是否用Python可以分析出这个源码直接的依赖关系。 一、…...
免费微网站模板/大型营销型网站制作
自己写过的程序,统计一下你写过多少行代码。包括空行和注释,但是要分别列出来1.打开文件方法1.1 以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符1.2 Python引入了with语句来自动帮我们调用close(…...
做网站开发的电话销售话术/海城seo网站排名优化推广
测试用例是进行测试的最小单元粒度。在编写测试用例之前需要很多准备工作去分析需求,提取测试点,然后根据提取的测试点选择相应分析方法,来设计测试用例。但测试用例如果要自己在excl手动填写,制作用例模板时,需要注意…...
找别人做网站注意事项/如何做好网络营销推广
返回:贺老师课程教学链接 【项目1-程序的多文件组织】请将下面的程序中的代码分别保存在两个文件中,利用多文件的方式组织。 * main.c(也可以是别的名字) #include <stdio.h> int max(int x,int y); int min(int x,int y…...