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
)?
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.