FastJSON与Jackson序列化的区别——踩过的一百个坑
问题背景
在与第三方API对接时,涉及到层级嵌套过深,接口提供加密方法可能会出现差异,导致传输后校验sign不正确,因此可能会需要自己这边先对嵌套的List进行Json化,再加密,之后进行传输,但今天遇到的一个问题比较邪门。无论怎么传都得到接口返回,api sign 不正确,仔细检查了方法,发现问题只能在Json时出现问题,由于我使用的是内部封装JsonUtils,所使用Jackson实现。
先说结论:特别是在处理大数字(如雪花算法生成的ID)时,FastJSON和Jackson的默认行为存在显著差异,可能导致接口调用失败。
现象描述
考虑以下示例数据:
class Order {
private Long id = 1912712976293294081L;
// 其他字段...
}
使用不同库序列化的结果:
// FastJSON结果
{"id": 1912712976293294081}
// Jackson结果
{"id": "1912712976293294081"}
原因分析
-
FastJSON:
- 默认保持数字类型
- 对大数字采用原样输出
- 不做特殊处理
-
Jackson:
- 默认将大数字转换为字符串
- 这样做是为了防止JavaScript处理大数字时的精度损失
- JavaScript的Number类型最大安全整数是2^53-1
解决方案
1. 修改Jackson配置
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 禁用将大数字转换为字符串
mapper.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false);
return mapper;
}
}
2. 使用注解方式
public class Order {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
}
3. 全局配置序列化器
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(Long.TYPE, ToStringSerializer.instance);
}
}
最佳实践建议
-
API文档优先
- 仔细阅读第三方API文档
- 确认字段类型要求
- 进行接口测试验证
-
统一序列化策略
- 项目中统一使用一种序列化库
- 保持配置一致性
- 做好文档说明
-
测试验证
- 编写单元测试
- 使用Postman等工具验证
- 记录关键数据日志
示例代码
// 调试代码
@Slf4j
public class JsonTest {
public void compareJsonOutput() {
Order order = new Order();
// FastJSON输出
String fastJsonStr = JSONObject.toJSONString(order);
log.info("FastJSON结果: {}", fastJsonStr);
// Jackson输出
String jacksonStr = objectMapper.writeValueAsString(order);
log.info("Jackson结果: {}", jacksonStr);
}
}
常见陷阱
- 前端JavaScript处理大数字精度问题
- 不同序列化库默认行为差异
- 第三方API对数据格式的严格要求
总结
- FastJSON和Jackson在处理Long类型时有不同的默认行为
- 需要根据具体场景选择合适的序列化策略
- 统一项目中的序列化配置很重要
- 做好测试和日志记录
相关链接
标签
Java JSON FastJSON Jackson 序列化 Long类型 大数字处理
最近有个想法,想把自己踩过的坑全都搬到线上来,专门做一个系列,有时候可能真就是一个小细节,就要排查很久,但是如果但凡有一点印象,或许就能加快排查步骤,大家可以支持点赞下。

1344

被折叠的 条评论
为什么被折叠?



