您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# JSON序列化导致Long类型被搞成Integer怎么解决
## 引言
在Java开发中,JSON序列化/反序列化是系统间数据交互的常见操作。但当处理数值类型时,开发者常会遇到一个棘手问题:明明定义的`Long`类型字段,经过JSON序列化后却变成了`Integer`,导致数据精度丢失或类型转换异常。本文将深入分析问题根源,并提供5种实用解决方案。
---
## 问题现象与复现
### 典型报错场景
```java
// 定义DTO对象
public class OrderDTO {
private Long orderId; // 数据库主键通常为Long
// getters/setters...
}
// 序列化测试
OrderDTO order = new OrderDTO();
order.setOrderId(123456789012345L); // 15位长整型
String json = JSON.toJSONString(order); // 使用Fastjson等库序列化
OrderDTO parsed = JSON.parseObject(json, OrderDTO.class);
System.out.println(parsed.getOrderId().getClass()); // 输出可能是java.lang.Integer!
Number
库名称 | 默认行为 | 配置方式 |
---|---|---|
Fastjson | 根据数值范围自动转换 | SerializerFeature |
Jackson | 相对保守,但也会类型推断 | JsonGenerator 配置 |
Gson | 完全依赖运行时类型 | 无需特殊配置 |
泛型在运行时被擦除,反序列化时可能丢失原始类型信息:
List<Long> ids = Arrays.asList(100L, 200L);
// 序列化后可能变成[100,200],反序列化时无法确定是Long
适用场景:所有主流JSON库
// 序列化时保留类型
String json = JSON.toJSONString(order,
SerializerFeature.WriteClassName);
// 反序列化时识别类型
OrderDTO parsed = JSON.parseObject(json, OrderDTO.class,
Feature.SupportAutoType);
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL);
public class LongToStringSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator gen,
SerializerProvider provider) throws IOException {
gen.writeString(value.toString()); // 转为字符串传输
}
}
// 注册注解
public class OrderDTO {
@JsonSerialize(using = LongToStringSerializer.class)
private Long orderId;
}
ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(Long.class)
.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
// 使用Hutool工具包
String json = JSONUtil.toJsonStr(order);
OrderDTO parsed = JSONUtil.toBean(json, OrderDTO.class);
public class OrderDTO {
private String orderId; // 前端传输用String
public Long getOrderIdAsLong() {
return Long.parseLong(orderId);
}
}
方案 | 可靠性 | 性能影响 | 侵入性 | 适用场景 |
---|---|---|---|---|
强制声明类型 | ★★★★★ | 较小 | 低 | 通用方案 |
自定义序列化器 | ★★★★ | 中等 | 中 | 需要精确控制 |
全局配置 | ★★★★ | 小 | 低 | 新项目 |
工具类 | ★★★ | 较大 | 无 | 快速解决 |
DTO转换 | ★★ | 大 | 高 | 老旧系统 |
前后端统一规范:
id
字段统一用String传输监控与防御编程:
// 在反序列化后添加校验
if (parsed.getOrderId() instanceof Integer) {
throw new IllegalStateException("Type conversion error!");
}
ObjectMapper
实例并缓存Q:为什么数据库的BIGINT映射到Java的Long还会出问题?
A:问题出在JSON这一传输层,与数据库无关
Q:使用String存储Long有什么缺点?
A:会增加约30%的存储空间,但现代压缩算法可缓解
Q:如何批量处理历史数据?
A:推荐使用jq命令行工具预处理:
cat old.json | jq '.id |= tostring' > new.json
JSON序列化中的Long类型问题本质是类型系统边界问题。通过本文介绍的5种方案,开发者可以根据实际场景选择最适合的解决方式。建议新项目直接采用方案1+方案3的组合,既保证类型安全又不失灵活性。
关键点:在分布式系统中,显式类型声明永远比隐式转换更可靠 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。