Search code examples
javajsonjacksondeserializationjson-deserialization

Jackson not throwing an exception on deserializing when provided json is different class type than targeted class


I have two classes A and B, both having public getters and constructors marked with @JsonCreator and @JsonProperty on constructor arguments. Both of those classes are deserialized correctly when correct json is provided. However when I provide a json that is a projection of class type A and try to deserialize it into B type object, I expect an exception to be thrown. It turnes out that jackson deserializes json correctly into B type object, but this object is just null. Is this the default behaviour? My ObjectMapper is created simply with new ObjectMapper(). Can I configure it in any way so that it throws an exception in described case?

Class A implementation:

@JsonIgnoreProperties(ignoreUnknown = true)
final class A {

    private final String propertyA;

    @JsonCreator
    A(@JsonProperty("propertyA") String propertyA) {
        this.propertyA = propertyA;
    }

    public String getPropertyA() {
        return propertyA;
    }

    @Override
    public String toString() {
        return "A{" +
            "propertyA='" + propertyA + '\'' +
            '}';
    }

}

Class B implementation:

@JsonIgnoreProperties(ignoreUnknown = true)
final class B {

    private final String propertyB;

    @JsonCreator
    B(@JsonProperty("propertyB") String propertyB) {
        this.propertyB = propertyB;
    }

    public String getPropertyB() {
        return propertyB;
    }

    @Override
    public String toString() {
        return "B{" +
            "propertyB='" + propertyB + '\'' +
            '}';
    }

}

Json with class B projection: {"propertyB":"propertyBValue"}

Deserialization code:

String jsonWithBObject = "{\"propertyB\":\"propertyBValue\"}";

A deserializedAObject = mapFromJsonToObject(jsonWithBObject, A.class);
private <T> T mapFromJsonToObject(String json, Class<T> targetClass) {
    try {
        return objectMapper.readValue(json, targetClass);
    } catch (JsonProcessingException exception) {
        throw new RuntimeException();
    }
}

And after running this code, no exception is thrown, and deserializdAObject contains: A{propertyA='null'}


Solution

  • Use @JsonProperty(required = true) to force Jackson throw exception on missing key

    This property is only partially supported. Excerpt from Jackson javadoc:

     Note that as of 2.6, this property is only used for Creator
     Properties, to ensure existence of property value in JSON:
     for other properties (ones injected using a setter or mutable
     field), no validation is performed. Support for those cases
     may be added in future.