Jackson注解转换BigDecomposition值并将比例设置为2

nqwrtyyt  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(86)

我有POJO,就像我有一个BigDecimal字段:

public class Foo implements Serializable {

   private BigDecimal amount;
}

我想有BigDecimal的值最多2小数位只。是否存在任何注解,我可以直接在字段级别更改它的值?我也不能改变它的类型。
虽然它可以在应用程序中使用getter和ObjectMapper来完成。

mftmpeh8

mftmpeh81#

当你想设置比例时,你需要注意四舍五入。你有一些选项,如ROUND_HALF_EVEN,你需要决定使用哪种舍入模式。
要拦截BigDecimal的解析,您可以编写自定义解析器。下面的例子展示了如何做到这一点,我们可以扩展默认的一个,并设置规模后,缩放:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;

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

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        Foo person = mapper.readValue(jsonFile, Foo.class);
        System.out.println(person);
    }
}

class BigDecimal2JsonDeserializer extends NumberDeserializers.BigDecimalDeserializer {

    @Override
    public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        BigDecimal value = super.deserialize(p, ctxt);

        // set scale
        value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);

        return value;
    }
}

class Foo {

    @JsonDeserialize(using = BigDecimal2JsonDeserializer.class)
    private BigDecimal amount;

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return "Foo{" +
                "amount=" + amount +
                '}';
    }
}

对于以下JSON有效负载:

{
  "amount": 16.127
}

以上app打印:

Foo{amount=16.13}
mqkwyuun

mqkwyuun2#

对于你的Kotlin爱好者,我实现了这个BigDeclarationContextualSerializer,其中小数位数可以使用注解配置。虽然在序列化器中引入舍入是一个奇怪的地方,但对我来说这不是问题。检查自己,如果舍入可能是一个问题。
Serializer类:

class CustomBigDecimalSerializer(private val decimalPlaces: Int = 2) : StdSerializer<BigDecimal>(BigDecimal::class.java),
        ContextualSerializer {

    override fun serialize(value: BigDecimal?, jsonGenerator: JsonGenerator?, serializerProvider: SerializerProvider?) {
        if (value != null) {
            jsonGenerator?.writeNumber(value.setScale(decimalPlaces, RoundingMode.HALF_UP))
        } else {
            jsonGenerator?.writeNull()
        }
    }

    override fun createContextual(provider: SerializerProvider?, property: BeanProperty?): JsonSerializer<*> {
        val decimalPlaces = property?.getAnnotation(DecimalPlaces::class.java)
        return CustomBigDecimalSerializer(decimalPlaces?.numberOfDigits ?: 2)
    }
}

可用于配置小数位数的注解:

@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class DecimalPlaces(val numberOfDigits: Int)

最后是它在这个“单元测试”中的用法:

class CustomBigDecimalSerializerTest {

    @Test
    fun serializeBigDecimals(){
        val objectMapper: ObjectMapper = ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
        val container = BigDecimalContainer(BigDecimal(Math.PI))
        // no assertions, just print the serialized container
        println(objectMapper.writeValueAsString(container))
    }

    data class BigDecimalContainer(val rawValue: BigDecimal){

        @JsonSerialize(using = CustomBigDecimalSerializer::class)
        val defaultDecimalPlaces = rawValue

        @JsonSerialize(using = CustomBigDecimalSerializer::class)
        @DecimalPlaces(numberOfDigits = 1)
        val oneDecimalPlaces = rawValue

        @JsonSerialize(using = CustomBigDecimalSerializer::class)
        @DecimalPlaces(numberOfDigits = 2)
        val twoDecimalPlaces = rawValue

        @JsonSerialize(using = CustomBigDecimalSerializer::class)
        @DecimalPlaces(numberOfDigits = 3)
        val threeDecimalPlaces = rawValue

        @JsonSerialize(using = CustomBigDecimalSerializer::class)
        @DecimalPlaces(numberOfDigits = 10)
        val tenDecimalPlaces = rawValue
    }
}

测试的输出为:

{
  "rawValue" : 3.141592653589793115997963468544185161590576171875,
  "defaultDecimalPlaces" : 3.14,
  "oneDecimalPlaces" : 3.1,
  "twoDecimalPlaces" : 3.14,
  "threeDecimalPlaces" : 3.142,
  "tenDecimalPlaces" : 3.1415926536
}

玩得开心!

相关问题