Jackson自定义BigDecimal序列化时的精度

需求:接口中返回数字时需要对数字进行保留小数的处理。
解决方法:实现一个BigDecimalSerializer,以及一个@BigDecimalScale注解,可实现自定义的数字精度。

代码:

BigDecimalWithAccuracySer类:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.math.BigDecimal;

/**
 * bigDecimal转成字符串,可识别精度
 */
public class BigDecimalWithAccuracySer extends StdSerializer<BigDecimal> implements ContextualSerializer {

    private final BigDecimalScale annotation;



    public BigDecimalWithAccuracySer(Class<BigDecimal> t, BigDecimalScale annotation) {
        super(t);
        this.annotation = annotation;
    }

    public BigDecimalWithAccuracySer(Class<BigDecimal> t) {
        super(t);
        this.annotation = null;
    }

    public BigDecimalWithAccuracySer(JavaType type) {
        super(type);
        this.annotation = null;
    }

    public BigDecimalWithAccuracySer(Class<?> t, boolean dummy) {
        super(t, dummy);
        this.annotation = null;
    }

    public BigDecimalWithAccuracySer(StdSerializer<?> src) {
        super(src);
        this.annotation = null;
    }

    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (annotation == null) {
            gen.writeNumber(value.toPlainString());
        } else {
            BigDecimal decimal = value
                    .movePointLeft(annotation.moveLeft())
                    .movePointRight(annotation.moveRight())
                    .setScale(annotation.setScale(), annotation.setRoundingMode());
            gen.writeNumber(decimal.toPlainString());
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        BigDecimalScale annotation = property.getAnnotation(BigDecimalScale.class);
        return new BigDecimalWithAccuracySer(BigDecimal.class, annotation);
    }
}

ContextualSerializer接口的作用是创建一个可感知当前处理字段相关信息的Serializer。其createContextual可自定义创建的Serializer。

BigDecimalScale注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.RoundingMode;

/**
 * 配合BigDecimalWithAccuracySer,处理bigDecimal的精度
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BigDecimalScale {

    /**
     * 设置小数点精度
     */
    int setScale() default 0;

    /**
     * 设置保留方式
     */
    RoundingMode setRoundingMode() default RoundingMode.HALF_UP;

    /**
     * 左移位数
     */
    int moveLeft() default 0;

    /**
     * 右移位数
     */
    int moveRight() default 0;

}

配置ObjectMapper:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.math.BigDecimal;
import java.util.TimeZone;

@Configuration
public class ObjectMapperConfigure {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(BigDecimal.class, new BigDecimalWithAccuracySer(BigDecimal.class));
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

posted @ 2025-06-26 15:24  Hekk丶  阅读(160)  评论(0)    收藏  举报