本文介绍一些高级技巧,用来处理一些特殊的序列化和反序列化需求。所选场景全部来自于 Github 上面的真实需求,绝对值得借鉴。
控制 Double 序列化输出的精度
开发同学,估计都曾为 Double 精度问题苦恼过。这不,有小伙伴在 Github 上面提交 ISSUE,想要自定义 Double 输出,控制小数点在两位数。
这个问题相对比较简单,只需定义一个 ValueFilter 即可。
ValueFilter filter = new ValueFilter() {
@Override
public Object apply(Object object, String name, Object value) {
if (value instanceof Double) {
BigDecimal bd = new BigDecimal(Double.toString((Double) value));
// 保留两位小数并选择舍入模式
BigDecimal result = bd.setScale(2, RoundingMode.HALF_UP);
return result.toString();
}
return value;
}
};
然后在序列化的时候,调用 JSON.toJSONString(Object object, Filter filter, JSONWriter.Feature... features) 这个接口即可。
上面这个接口,会把 ValueFilter 应用到所有的字段,如果发现是 Double 类型,就调用 BigDecimal 控制精度。
于是,这里有一个问题,如果只需给特定类的特定Double字段控制精度呢?这时需要用到 SerializeConfig,然后调用JSON.toJSONString(Object object, SerializeConfig config, SerializerFeature... features) 这个接口。
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.addFilter(A.class, new DoubleFilter());
输出 Integer NULL 值为 N/A
有小伙伴在 Github 上说,在很多报表型应用中,如果某个数据没有值,在界面上打印出 null 是非常不友好的事情,更加优雅的做法是输出 N/A,那么这个应该如何实现呢?
序列化时,同样定义一个 ValueFilter 即可,这一步比较简单。
ValueFilter filter = new ValueFilter() {
@Override
public Object apply(Object object, String name, Object value) {
if (value == null) {
return "N/A"; // 如果字段值为 null,改为 "N/A"
}
return value;
}
};
然而,反序列化过程中会遇到一些挑战。Fastjson 默认情况下无法识别 "N/A" 这样的特殊值,也没有为其提供内置的处理机制。这就意味着我们需要自定义一个专门的反序列化器来应对这种情况。这个自定义反序列化器不仅要能够正确解析正常的整数值,还要能够识别并适当处理 "N/A" 这样的特殊字符串,将其转换为 null 或其他适当的表示形式。
public class MyObjectReaderInt implements ObjectReader<Integer> {
@Override
public Integer readObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
char curr = jsonReader.current();
if (curr == '"' || curr == '\'') {
String text = jsonReader.readString();
if (text.equals("N/A")) {
return null;
} else {
throw new RuntimeException("unknown text " + text);
}
} else {
return jsonReader.readInt32();
}
}
}
需要注意的是,这个反序列化器不支持全局配置,有BUG,详情参考 github.com/alibaba/fas… 。解决办法是,针对每个类的每个字段用JSONField。
总结与最佳实践
本文探讨了 FastJson 处理特殊字段的高级技巧,旨在提高 JSON 数据的可读性和实用性。这些场景源自 Github 上的真实需求,我也有幸直接参与了解决方案的贡献。
主要涵盖以下方面:
- 精度控制:使用 ValueFilter 精确控制 Double 类型输出的小数位数
- NULL 值处理:通过 ValueFilter 将 NULL 转换为更友好的显示(如"N/A")
- 自定义反序列化:利用 ObjectReader 处理特殊值(如"N/A")
这些技巧能帮助开发者构建更灵活、更健壮的应用。在实际使用时,请根据具体需求选择合适的方法,并注意测试各种边界情况。
编写 ObjectReader 时需参考 Fastjson 的源码。建议使用阅读源码的神器 XCodeMap 插件 分析默认实现,然后进行针对性调整。
如果你对学习如何阅读开源项目源码、解决开源 ISSUE 或贡献开源代码感兴趣,欢迎关注我。我将持续分享我的开源经历和心得。