Confusion with setSerializationInclusion(Include.NON_NULL)
I'm confused with setup in "Usage section":
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.registerModule(new JsonNullableModule());
Please take a look on the following snippet ( val=null is passed in JSON and in Map):
record A (JsonNullable<BigDecimal> val) {}
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JsonNullableModule());
A a1 = objectMapper.readValue("{ \"val\" : null }", A.class);
System.out.println(a1);
HashMap hashMap = new HashMap();
hashMap.put("val", null);
A a2 = objectMapper.convertValue(hashMap, A.class);
System.out.println(a2);
Output is consistent
A[val=JsonNullable[null]] A[val=JsonNullable[null]]
But with setup
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JsonNullableModule())
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Output is not consistent
A[val=JsonNullable[null]] A[val=JsonNullable.undefined]
Well, time for questions:
- I do not understand why you propose in "Usage" section setup
.setSerializationInclusion(JsonInclude.Include.NON_NULL). It looks useless. - I do not understand how serialization setup may affect deserialization (
objectMapper.convertValueis deserialization)
serializationInclusion impacts the conversion from a Java object to a String. It does not impact the conversion from a String into a Java object.
mapper.readValue(someString, A.class) will always produce the same value, regardless of the serializationInclusion property.
mapper.writeValueAsString(someDto) may serialize to a different String based on the value of serializationInclusion.
mapper.convertValue(someDto, A.class)isn't exactly the same, but is similar to calling mapper.readValue(mapper.writeValueAsString(someDto), A.class) and as such it may also be impacted by the different configuration options of serializationInclusion (check the javadoc on convertValue for details on how it works).
If you use JsonInclude.Include.ALWAYS, then new A(null) will be converted to a String with the value of {"val": null}. When you then attempt to convert this String back into A, it will be converted into new A(JsonNullable.of(null). This is typically undesirable.
If you use JsonInclude.Include.NON_NULL (or NON_ABSENT or NON_EMPTY) then new A(null) will be converted to a String with the value of {}. When you attempt to convert this String back into A it will be converted into new A(null). This is the typical desirable behavior.
(I say String above, but I believe the same applies if you're using a byte array, InputStream, etc. String is just the simplest for discussion here.)
This module relies on the below concepts. By using JsonInclude.Include.ALWAYS for serialization, these concepts don't work well on the deserialization side.
- A JSON object without a property is equivalent to
JsonNullable.undefined(). - A JSON object with a property set to
nullis equivalent toJsonNullable.of(null). - A JSON object with a property set to any value is equivalent to
JsonNullable.of(someValue).