FasterXML / jackson-databind

General data-binding package for Jackson (2.x): works on streaming API (core) implementation(s)
Apache License 2.0
3.51k stars 1.37k forks source link

If deduction-based polymorphism is used, Jackson will deserialize all decimal values as BigDecimal if they are mapped to `java.lang.Object` #3524

Open v1somaki opened 2 years ago

v1somaki commented 2 years ago

Describe the bug If deduction-based polymorphism is used, Jackson will deserialize all decimal values as BigDecimal if they are mapped to java.lang.Object.

Version information 2.13.3

To Reproduce

This can be reproduced by running the following tests:

class DeductionTest {
    @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
    @JsonSubTypes({ @JsonSubTypes.Type(Sub.class)})
    private static class Super { }

    private static class Sub extends Super {
        private Object value;
        public Object getValue() {
            return value;
        }
        public void setValue(Object value) {
            this.value = value;
        }
    }

    @Test
    void deserializeDecimal() throws IOException {
        String json = "{\"value\": 1.0}";
        ObjectMapper mapper = new ObjectMapper();
        Sub sub = (Sub)mapper.readValue(json, Super.class);
        System.out.println("deserializeDecimal: " + sub.getValue().getClass());
    }

    @Test
    void deserializeInteger() throws IOException {
        String json = "{\"value\": 1}";
        ObjectMapper mapper = new ObjectMapper();
        Sub sub = (Sub)mapper.readValue(json, Super.class);
        System.out.println("deserializeInteger: " + sub.getValue().getClass());
    }
}

Prints out:

deserializeDecimal: class java.math.BigDecimal
deserializeInteger: class java.lang.Integer

I believe the first one should be deserialized as java.lang.Double instead of java.math.BigDecimal?

cowtowncoder commented 2 years ago

Hmmh. You are probably right, wrt expected default mapping. Not sure if this is related to deduction-based polymorphic handling (could be same for other polymorphic methods).

As a work-around it probably makes sense to cast value as Number (if known it should be), call Number.asDouble().

cowtowncoder commented 1 year ago

NOTE: almost certainly related to buffering of tokens, needed often with polymorphic deserialization. Interesting that result is BigDecimal, nonetheless; should produce Double unless ObjectMapper configured with DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS