Java JSON 与序列化
JSON 与对象映射的边界:DTO、空值、类型与安全反序列化意识。
#concept
#growing
#dev
#java
[!info] related notes
Java JSON 与序列化
这个概念为什么出现
HTTP API 与消息系统普遍使用 JSON。对象 ↔ JSON 涉及字段命名、空值、日期、未知属性与不可信输入安全。
[!abstract] 一句话理解 用 DTO/record 承载 JSON 形状;选择成熟库做映射;永远校验不可信输入,并谨慎对待 Java 原生二进制序列化。
最小可运行示例
场景:固定字段与受限 ID 的零依赖演示
这里只接受 ASCII 字母、数字、下划线、连字符组成的非空 ID。这个人为限制使示例无需处理字符串转义;它不是通用 JSON 序列化器,也不是实际业务 ID 必须遵守的规则。
public class OrderJsonMini {
// 真实项目用 JSON 库;这里只输出下述白名单域内的 ID。
static String toJson(String id, int cents) {
if (id == null || !id.matches("[A-Za-z0-9_-]+")) {
throw new IllegalArgumentException("id must match [A-Za-z0-9_-]+");
}
return "{\"id\":\"" + id + "\",\"amountCents\":" + cents + "}";
}
public static void main(String[] args) {
System.out.println(toJson("ORD-1", 99));
}
}
javac OrderJsonMini.java && java OrderJsonMini
期望:
{"id":"ORD-1","amountCents":99}
若 ID 需要中文、引号、反斜线或控制字符,应改用库处理,不能仅移除白名单校验继续拼接。库负责 JSON 编码,不会自动替业务校验金额、权限或字段含义。
结合场景再看三个关注点
- 契约字段稳定。
- 字符串转义不能手滑。
- 反序列化是攻击面(类型多态配置等)。
核心概念与准确模型
1. 库选择
Jackson、Gson 是库;JSON-B 是 Jakarta JSON Binding 规范,需要对应实现。它们不是 JDK 自带的 JSON API。
2. DTO 边界
不要直接把复杂实体图裸露给外部。DTO/record 只提供类型和形状;缺失字段、显式 null、未知字段和数值越界的处理取决于映射配置与业务校验,record 不会自动让输入有效。
3. Java Serializable
历史二进制序列化安全风险高,默认不要用于不可信数据。
边界情况与反直觉行为
- 大整数可能超出接收方的精确范围(例如 JavaScript Number 的安全整数范围);金额宜约定整数最小单位或十进制表示,不能默认 double 精确。
- 时间格式时区。
- unknown property 严格/宽松策略。
常见误区
[!warning] 常见误区:开启任意多态类型反序列化 易导致远程代码执行类漏洞;跟进库安全公告。
工程实践
- 契约测试/OpenAPI。
- 限制字段与深度。
- record + 明确命名策略。
- 版本化 API。
本节总结
- JSON 映射是边界工程
- 用库与 DTO
- 安全默认
自测题
- 为什么不推荐手写复杂 JSON?
- Serializable 的主要风险?
参考答案
- 转义/嵌套/性能/正确性难。
- 反序列化攻击面与兼容性脆弱。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Jackson | 库 | 常见映射 |
| OWASP Deserialization | 安全 | 风险 |