Search code examples
javajacksondeserializationbigdecimaljson-deserialization

Jackson annotation to convert BigDecimal value and set scale to 2


I have POJO like where I have a BigDecimal field:

public class Foo implements Serializable {

   private BigDecimal amount;
}

I want to have the BigDecimal value up to 2 decimal place only. Is there any annotation exist using which I can directly change it's value at the field level itself? I cannot change it's type as well.

Though it can be done with getter and ObjectMapper within the application.


Solution

  • When you want to set scale you need to take care about rounding. You have some options such as ROUND_HALF_EVEN and you need to decide which rounding mode to use.

    To intercept BigDecimal deserialisation you can write custom deserialiser. Below example shows how to do that, we can extend default one and set scale after deserialzation:

    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 +
                    '}';
        }
    }
    

    For below JSON payload:

    {
      "amount": 16.127
    }
    

    above app prints:

    Foo{amount=16.13}