With om.setSerializationInclusion(Include.NON_NULL), in 2.8, null values in dynamic data were kept. in 2.9, however, only top-level values are kept (a in the example code, whereasc2` is missing).
Tried several configuration switches of ObjectMapper, but I don't think there's a way to keep the same behaviour as before.
public class Jackson29DynamicDataNullTest {
@Test
public void testNull() throws IOException {
String json = "{'a': null, 'b': 2, 'c': { 'c1': 3, 'c2': null } }".replace('\'', '"');
Map<String, Object> data = om().readValue(json, Map.class);
assertTrue(data.containsKey("a"));
assertNull(data.get("a"));
assertTrue(((Map) data.get("c")).containsKey("c2"));
assertNull(((Map) data.get("c")).get("c2"));
Person p = new Person();
p.data = data;
p.name = "Pep";
p.age = null;
String json2 = om().writeValueAsString(p);
System.err.println(json2);
ObjectNode on = om().readValue(json2, ObjectNode.class);
assertTrue(on.has("a"));
assertTrue(on.get("a").isNull());
assertTrue(on.get("c").has("c2"));
assertTrue(on.get("c").get("c2").isNull());
}
ObjectMapper om() {
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(Include.NON_NULL);
// NONE OF THESE SWITCHES WORKED
// om.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, true);
// om.configOverride(Map.class)
// .setInclude(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS,
// JsonInclude.Include.USE_DEFAULTS));
return om;
}
static class Person {
Map<String, Object> data;
String name;
Integer age;
@JsonAnyGetter
public Map<String, Object> getData() {
return data;
}
@JsonAnySetter
public void setData(Map<String, Object> data) {
this.data = data;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
Have you tried method setDefaultPropertyInclusion() of ObjectMapper?
Discrepancy is probably due to setSerializationInclusion now being a shortcut for:
public ObjectMapper setSerializationInclusion(JsonInclude.Include incl) {
return setDefaultPropertyInclusion(JsonInclude.Value.construct(incl, incl));
}
that is, using same value for both "value" (container) and contents (element(s) within).
I think earlier definition is more likely to be along lines of:
return setDefaultPropertyInclusion(JsonInclude.Value.construct(incl, JsonInclude.ALWAYS));
which in retrospect would have likely been better implementation.
But unfortunately none of unit tests were testing for particular behavioral difference for this usage.
Note that Include.USE_DEFAULTS would have no effect for contents; you probably want ALWAYS instead. It can be set either as global defaults, or as override for Map.
Yes,
om.setDefaultPropertyInclusion(JsonInclude.Value.construct(Include.NON_NULL, Include.ALWAYS));
works as expected, thanks!聽
Most helpful comment
Have you tried method
setDefaultPropertyInclusion()ofObjectMapper?Discrepancy is probably due to
setSerializationInclusionnow being a shortcut for:that is, using same value for both "value" (container) and contents (element(s) within).
I think earlier definition is more likely to be along lines of:
which in retrospect would have likely been better implementation.
But unfortunately none of unit tests were testing for particular behavioral difference for this usage.
Note that
Include.USE_DEFAULTSwould have no effect for contents; you probably wantALWAYSinstead. It can be set either as global defaults, or as override forMap.