如何实现带最小小数位数配置的BigDecimal JSON序列化注解?
基于自定义注解实现可配置的BigDecimal金额序列化方案
1. 自定义带参数的序列化配置注解
创建@MoneySerialize注解,用于传递字段序列化时的最小保留小数位数参数:
import com.fasterxml.jackson.annotation.JacksonAnnotation; import java.lang.annotation.*; @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface MoneySerialize { // 最小保留小数位数,默认值为0 int minimumScale() default 0; }
2. 实现可读取注解参数的MoneySerializer
修改原有序列化器,使其能读取字段上的注解参数,并按规则处理BigDecimal格式化:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; public class MoneySerializer extends StdSerializer<BigDecimal> { public MoneySerializer() { super(BigDecimal.class); } @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (value == null) { gen.writeNull(); return; } // 读取字段上的@MoneySerialize注解参数 int minimumScale = 0; var activeProperty = provider.getActiveProperty(); if (activeProperty != null) { MoneySerialize annotation = activeProperty.getAnnotation(MoneySerialize.class); if (annotation != null) { minimumScale = annotation.minimumScale(); } } // 去除末尾多余零 BigDecimal strippedValue = value.stripTrailingZeros(); int currentScale = strippedValue.scale(); // 保证保留至少指定的最小小数位数 if (currentScale < minimumScale) { strippedValue = strippedValue.setScale(minimumScale, RoundingMode.UNNECESSARY); } // 输出为普通字符串(避免科学计数法) gen.writeString(strippedValue.toPlainString()); } }
3. 在POJO字段上配置注解
在MoneyBean的字段上同时指定序列化器和自定义配置注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.math.BigDecimal; public class MoneyBean { // 保留至少2位小数,去除多余尾零:100.0000 → 100.00 @JsonSerialize(using = MoneySerializer.class) @MoneySerialize(minimumScale = 2) private BigDecimal amount1; // 去除所有尾零:100.0000 → 100;100.1000 → 100.1 @JsonSerialize(using = MoneySerializer.class) @MoneySerialize(minimumScale = 0) private BigDecimal amount2; // 构造方法、Getter、Setter省略 }
核心逻辑说明
- 去除尾零:通过
stripTrailingZeros()移除BigDecimal末尾的无效零,得到最精简的数值表示 - 最小小数位保证:对比去除尾零后的小数位数与注解指定的
minimumScale,若前者更小则补零到指定位数(使用RoundingMode.UNNECESSARY避免四舍五入,保证精度) - 字符串输出:使用
toPlainString()避免BigDecimal自动转为科学计数法的情况
内容的提问来源于stack exchange,提问作者luke
相关产品推荐
相关产品推荐

