Force spring boot jackson deserializer to use BigDecimal
Asked Answered
W

3

9

I'm having a problem in which jackson is deserializing numeric values into arbitrary types which I cannot predict. For example, if someone passes the value "14", jackson will instantiate it as an Integer. However, if someone passes the value "14.01" then jackson will instantiate it as a Double. This is a problem because I have a custom deserializer (@JsonCreator) which is throwing exceptions since I cannot predictable cast the field into a BigDecimal. Ideally jackson would just turn everything into a BigDecimal.

I found a post which suggests that Jackson might be capable of doing something like this. Deserialize JSON into a generic map, forcing all JSON floats into Decimal or String, in Jackson

However, I can't figure out how to access the mapper object hidden inside Spring Boot in order to run the appropriate method mapper.enable().

Here is a snippet of the deserializer:

@JsonCreator
public OptionTransaction(Map<String,Object> jsonObj){  
    Map<String,Object> jsonOption = (Map<String, Object>) jsonObj.get("option");

    Map<String,Object> optionPriceObj = (Map<String, Object>) jsonOption.get("price");
    BigDecimal optionValue = new BigDecimal((Double) optionPriceObj.get("value"));

As you can see above, that Double cast is a problem because jackson is sometimes not feeding in doubles. Does anyone know an easy way to get jackson to either always output BigDecimals, or even just strings?

UPDATE:

As far as getting doubles converted to BigDecimal, I accomplished this by modifying application.properties in the following way:

# ===============================
# = DESERIALIZATION CUSTOMIZATION
# ===============================
spring.jackson.deserialization.USE_BIG_DECIMAL_FOR_FLOATS=true
Walburga answered 24/10, 2016 at 8:41 Comment(2)
Why do you need access to the Spring mapper, why don't you just create your own?Hypsography
The answer to my question could include that, but that wouldn't fully answer the question. If I were to create my own mapper, how would I get spring boot to start using it?Walburga
T
6
@JsonCreator
public OptionTransaction(Map<String,Object> jsonObj){  
    Map<String,Object> jsonOption = (Map<String, Object>) jsonObj.get("option");

    Map<String,Object> optionPriceObj = (Map<String, Object>) jsonOption.get("price");
    BigDecimal optionValue = new BigDecimal((Double) optionPriceObj.get("value"));
}

..

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);

OptionTransaction transaction = mapper.readValue(jsonString, OptionTransaction.class);

https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features

Telegu answered 24/10, 2016 at 9:16 Comment(3)
I think to mark the question as answered this should also describe how to get sping boot to start using this mapper for future deserialization attempts. Is that even possible? For example, any endpoint using @RequestBody Object obj should be deserialized with this mapper.Walburga
How can we set custom scale and precision in this deserializer ?Saracen
is there a way to set this with class level annotations?Herzegovina
F
1

Very simple setup in Spring Boot configuration:

spring:
  jackson:
    deserialization:
      use-big-decimal-for-floats: true

In OpenAPI specification use (for generate MyClass { BigDecimal id; }:

MyClass:
  type: object
  properties:
    id:
      type: number
      example: 666.66
Ferula answered 16/6 at 23:15 Comment(1)
Dies this use a new BigDecimal("666.66")? Defining a precision of 2?Narvik
C
0
@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        return builder
                .modules(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES), new JavaTimeModule())
                .deserializers( new NumberDeserializers.BigDecimalDeserializer())
                .featuresToEnable(MapperFeature.AUTO_DETECT_CREATORS)
                .build();
    }
}
Customhouse answered 3/1, 2023 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.