Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS doesn't preserve scale

When I deserialize a JSON number to a BigDecimal using readTree, the results don't preserve the scale, i.e. it treats 0.10 as 0.1. On the other hand, if I deserialize using readValue, it does preserve scale, returning a BigDecimal with the correct scale of 2:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
    JsonNode jsonNode = objectMapper.readTree("0.10");
    BigDecimal numberFromReadTree = ((DecimalNode)jsonNode).decimalValue();
    BigDecimal numberFromReadValue = objectMapper.readValue("0.10", BigDecimal.class);

    System.out.println(numberFromReadTree); // Prints 0.1, i.e. scale = 1
    System.out.println(numberFromReadValue); // Prints 0.10, i.e. scale = 2

Is there a reason for this apparent inconsistency, and is there an option I can set to keep the scale the same as the input (i.e. to be consistent with readValue)?

like image 827
Klitos Kyriacou Avatar asked Nov 30 '25 10:11

Klitos Kyriacou


1 Answers

Is there a reason for this apparent inconsistency, and is there an option I can set to keep the scale the same as the input (i.e. to be consistent with readValue)?

As you pointed the reason for this inconsistency stands in an option that can be set for JSonNode nodes that will be created:

JsonNodeFactory factory = new JsonNodeFactory(true);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setNodeFactory(factory);
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
JsonNode jsonNode = objectMapper.readTree("0.10");
System.out.println(jsonNode); // Prints 0.10, i.e. scale = 2

Basically the ObjectMapper mapper has to set its JSonNodeFactory attribute passing a new JsonNodeFactory object created by the JsonNodeFactory#JsonNodeFactory-boolean constructor using the true value indicating that DecimalNode instances must be built with exact representations of BigDecimal instances, while the std ObjectMapper constructor owns a JsonNodeFactory object created by the no-arg constructor (and the default instance) with a default false value as an argument.

In the second case that uses a ObjectMapper mapper without touching the JSonNodeFactory attribute:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
BigDecimal numberFromReadValue = objectMapper.readValue("0.10", BigDecimal.class);
System.out.println(numberFromReadValue); // Prints 0.10, i.e. scale = 2

It works because in the BigDecimal class the BigDecimal.html#BigDecimal-java.lang.String constructor is present and directly used by the ObjectMapper mapper giving the expected result.

like image 86
dariosicily Avatar answered Dec 03 '25 00:12

dariosicily



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!