📋 目录
一、工具类功能
把对象转成字节或 Base64 文本再还原,或者复制出一份引用完全独立的副本,嵌套集合与数组一起断开、改副本不影响原对象,读外部来路的字节必须给类白名单。
二、所需环境
JDK 17或以上
三、方法与调用示例(按需调用)
🔢 方法序号:1
🎯 方法用途:
- 序列化再读出,得到引用完全独立的副本,嵌套对象、集合与数组一起复制
- 不想手写拷贝构造、又要改掉副本不影响原对象时用
🧩 方法定义:public static <T extends Serializable> T deepCopy(T source)
🗣️ 入参解释:public static <T extends Serializable> T deepCopy(待拷贝对象)
📤 返回值解释:T,与原对象同类型的新副本
💡 边界口径:
transient字段不会被带走,副本里是 null- 拷贝后
==不再成立,但equals语义保持;单例与枚举要用各自的克隆策略 - 原对象的
writeObject副作用会被执行,持有连接或文件的对象不适合走这条路 - 对象图里有任何一个类没实现
Serializable就整体失败,抛IllegalStateException - 副本走的是免白名单的内部读取,外部来路的数据绝不能用这个入口
🧪 方法示例:
deepCopy(origin).tags.size()拿到2 个,原对象仍是1 个,集合互不影响- 副本的地址城市改成上海后,原对象读到的是
杭州 - 刚拷出来的副本
sessionToken是null,transient 字段没带过来 deepCopy(null)抛IllegalArgumentException
🔢 方法序号:2
🎯 方法用途:
- 把对象转成 Java 原生序列化的字节数组
- 进程内缓存、同版本服务之间的临时传递用这一版
🧩 方法定义:public static byte[] serializeToBytes(Object object)
🗣️ 入参解释:public static byte[] serializeToBytes(可序列化对象)
📤 返回值解释:byte[],Java 序列化协议的字节流
💡 边界口径:
- 字节流前两个字节固定是 magic
0xaced,一眼能认出是 Java 序列化数据 - 对象没实现
Serializable时抛IllegalStateException,消息里带上类名 - 参数为 null 抛
IllegalArgumentException - 原生序列化格式对类版本变更极敏感,改字段或改
serialVersionUID就解不出来,也不具备跨语言能力
🧪 方法示例:
serializeToBytes(origin).length拿到367- 头两个字节拿到
magic 0xaced serializeToBytes(new Object())抛对象序列化为字节数组失败,class=java.lang.Object, java.lang.Object
🔢 方法序号:3
🎯 方法用途:
- 把对象转成一串 Base64,能放进字符串字段、日志行或文本消息
- 只能传文本的通道(表单字段、MQ 文本消息)用它承载对象
🧩 方法定义:public static String toBase64(Object object)
🗣️ 入参解释:public static String toBase64(可序列化对象)
📤 返回值解释:String,标准 Base64(含 padding)
💡 边界口径:
- 前缀
rO0AB就是 Java 序列化流的特征头,看到它应知道这是原生序列化数据 - 长度约为字节数的 4 分之 3,比字节更占空间
- 编码规则沿用
Base64.getEncoder(),是标准字母表,不是 URL 安全形态 - 还原必须走带白名单的
fromBase64,别拿它当可信任字符串处理
🧪 方法示例:
toBase64(origin).length()拿到492- 前 20 位拿到
rO0ABXNyAC5jb20uZXhh,一看就是序列化流 - 对一段文本
toBase64("只是一段文本")也能出串,拿它按Order.class还原会抛反序列化结果类型不匹配,期望 com.example.order.api.SerializeUtilsDemo$Order,实际 java.lang.String
🔢 方法序号:4
🎯 方法用途:
- 读外部来路的字节,白名单之外的类在读任何对象之前就被拒绝
- 网络、上传、缓存、MQ 来的序列化数据必须走这个带白名单的入口
🧩 方法定义:public static Object deserialize(byte[] bytes, String allowedClassPattern)
🗣️ 入参解释:public static Object deserialize(字节数组, 类白名单表达式)
📤 返回值解释:Object,还原出的对象,由调用方自己判类型
💡 边界口径:
- 用的是 JDK 的
ObjectInputFilter,在读取任何对象之前就拒绝非法类 - 表达式末尾会自动补一条
!*兜底拒绝,没匹配到的类不会被放过 - 同时限制深度 64 层、引用数 100 万、字节量 256 MiB、数组长度 1000 万
- 对象图里的嵌套类也要显式放行,只放外层类会在内层被拒
- 「被过滤器拒绝」与「字节流损坏」是两回事,前者翻译成
IllegalArgumentException,不会混成一句流损坏
🧪 方法示例:
- 白名单里没有
java.awt.Point时deserialize(foreign, pattern)抛反序列化被安全过滤器拒绝(类不在白名单内,或超出深度/引用数/数组长度上限): InvalidClassException: filter status: REJECTED - 同一份字节把
java.awt.**写进白名单后拿到java.awt.Point[x=1,y=2] - 漏写兜底拒绝规则时会被自动补齐,非法类依然抛
IllegalArgumentException - 对象图深度超过 64 层时抛
IllegalArgumentException deserialize(new byte[0], MY_PACKAGE)抛bytes 不能为null或空数组deserialize(bytes, " ")抛allowedClassPattern 不能为null或空白
🔢 方法序号:5
🎯 方法用途:
- 还原自己刚序列化出来的字节,不做类白名单校验
- 数据源百分百可信、且就是本进程
serializeToBytes产出的场合用它
🧩 方法定义:public static Object deserializeTrusted(byte[] bytes)
🗣️ 入参解释:public static Object deserializeTrusted(本类刚产出的字节)
📤 返回值解释:Object,还原出的对象
💡 边界口径:
- 名字里的 Trusted 就是提醒:换数据源必须改成带白名单的
deserialize - 仍然带深度、引用数、字节量与数组长度限制,防爆与深链
- 字节流损坏、类不存在或版本不一致抛
IllegalStateException并保留原因 - 参数为 null 或空数组抛
IllegalArgumentException
🧪 方法示例:
deserializeTrusted(bytes)拿到单号 ORD20261005001- 还原结果与原对象的
equals判断是true - 与原对象是否同一个引用,答案是
false deserializeTrusted(new byte[0])抛bytes 不能为null或空数组
🔢 方法序号:6
🎯 方法用途:
- 从 Base64 还原并校验类型,直接拿到目标类的对象,不用自己强转
- 前端或外部系统回传的 Base64 对象串,按约定类型解回来时用
🧩 方法定义:public static <T> T fromBase64(String base64, Class<T> type, String... extraAllowed)
🗣️ 入参解释:public static <T> T fromBase64(Base64串, 目标类, 额外白名单)
📤 返回值解释:T,类型校验通过后的对象
💡 边界口径:
- 白名单除目标类外,还放行
java.lang.*、java.util.**、java.time.**、java.math.**这些基础包 - 业务对象所在的包要靠
extraAllowed追加,漏了就在过滤器处被拒 - 解出来的对象类型与
type不符时抛IllegalArgumentException,消息带上期望与实际类型 - Base64 串非法或空白抛
IllegalArgumentException - 要更紧的口径就自己写表达式走
deserialize
🧪 方法示例:
fromBase64(base64, Order.class, MY_PACKAGE)拿到ORD20261005001,金额 4999,地址 杭州- 对象图里的嵌套类没放行时抛
反序列化被安全过滤器拒绝(类不在白名单内,或超出深度/引用数/数组长度上限): InvalidClassException: filter status: REJECTED - 把一段文本的 Base64 按
Order.class解,抛反序列化结果类型不匹配,期望 com.example.order.api.SerializeUtilsDemo$Order,实际 java.lang.String
🔢 方法序号:7
🎯 方法用途:
- 不指定目标类,完全按调用方给的白名单表达式从 Base64 还原
- 类型要运行时才知道、或者要一次放开多个包时用这一版
🧩 方法定义:public static Object fromBase64(String base64, String allowedClassPattern)
🗣️ 入参解释:public static Object fromBase64(Base64串, 类白名单表达式)
📤 返回值解释:Object,还原出的对象,类型由调用方判断
💡 边界口径:
- 表达式口径与
deserialize(byte[], String)完全一致,同样自动补!* - 不做类型校验,需要类型安全就用三参版
- 表达式为 null 或空白抛
IllegalArgumentException
🧪 方法示例:
fromBase64(base64, MY_PACKAGE + ";" + JDK_ONLY)拿到还原对象的类名Order- 表达式里没有目标类所在的包时抛
IllegalArgumentException,消息是过滤器拒绝那句
四、工具类源码(可直接复制)
📦 源码文件