自定义Moshi BigDecimal JsonAdapter.Factory适配器工厂

背景

所在公司项目中,涉及金额数字,所以在反序列化数字金额时,选择了BigDecimal作为金额相关JSON字段的对象类型。在项目中使用Kotlin语言,搭配Retrofit框架和Moshi作为序列化工具,但Moshi在使用当中发现,是不支持string、number类型的JSON字段转换成BigDecimal类型的参数的。于是需要自定义一个JsonAdapter.Factory来解决这一问题。

先来介绍为什么选BigDecimal

1. 精确的十进制表示

BigDecimal内部,通过整数+小数位存储数据,无精度损失,例如 321.45 存储为 32145 X 10^-2。

2. 完全控制舍入行为

提供多种舍入模式,如RoundingModel.HALF_UP 四舍五入,符合财务规范。

3. 支持任意精度

不受固定自己安长度限制,可处理超大金额或超高精度

4. 避免隐式转换风险

强制使用显示计算方式 如,add()mulitply() ,避免意外错误。

代码如下

kotlin 复制代码
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import java.lang.reflect.Type
import java.math.BigDecimal

class BigDecimalAdapterFactory : JsonAdapter.Factory {
    override fun create(type: Type, annotations: Set<Annotation?>, moshi: Moshi): JsonAdapter<*>? {
        if (type != BigDecimal::class.java) return null

        return object : JsonAdapter<BigDecimal>() {
            override fun fromJson(reader: JsonReader): BigDecimal? {
                return when (reader.peek()) {
                    JsonReader.Token.NUMBER -> {
                        val number = reader.nextDouble()
                        BigDecimal.valueOf(number)
                    }
                    
                    JsonReader.Token.STRING -> {
                        val string = reader.nextString()
                        BigDecimal(string)
                    }

                    JsonReader.Token.NULL -> {
                        null
                    }

                    else -> {
                        val intValue = reader.nextInt()
                        BigDecimal(intValue)
                    }
                }
            }

            override fun toJson(wirtter: JsonWriter, value: BigDecimal?) {
                if (value != null) {
                    wirtter.value(value)
                } else {
                    wirtter.nullValue()
                }
            }
        }.nullSafe()
    }
}
相关推荐
daols884 分钟前
vue 甘特图 vxe-gantt 紧前紧后依赖关系连接线配置详解
前端·vue.js·甘特图
恋猫de小郭5 分钟前
Flutter iOS 的深度优化 PR,搞笑的是贡献者被 Gemini 评审折磨
android·前端·flutter
必须会一定会8 分钟前
Agent Handoff M5 发布验收:`CHANGES.md`、`npm pack`、`release:check` 与干净环境安装验证
前端·人工智能·npm·node.js·ai编程
有脚就行26 分钟前
第07篇-ReAct模式详解-推理与行动的交替循环
前端·react.js·前端框架
未来之窗软件服务43 分钟前
Web 技能的自主测试系统开好处发架构思维-东方仙盟
大数据·前端·架构·仙盟创梦ide·东方仙盟
吠品1 小时前
OkHttp 多文件上传的一个实现
java·服务器·前端
lilian2331 小时前
Harmony os 技术实战|拼豆制图46:图片解码失败为何不能悄悄返回示例图
前端·javascript·华为·harmonyos
zzzzzz3102 小时前
react-bits:从 36K Stars 的组件库,看动画交互组件该如何被评估
前端·react.js·动效
Setsuna_F_Seiei9 小时前
前端的 AI 学习之路 01 之 Agent API 调用 - 和 Agent 的基础对话
前端·人工智能·ai编程
threerocks10 小时前
AI 原生软件开发生命周期手册 - 如何借助 AI,逐阶段改造软件开发生命周期
前端·javascript·后端