记一次Jackson引发的血案
一
昨天修改项目,想用Jackson
逐渐替换项目中使用的Fastjson
,项目较旧,已经配置了FastJsonHttpMessageConverter
用于springmvc
的返回值序列化,这是前提。
二
既然是用了Jackson解析json,有几个接口返回值里里有JsonNode
类型,这是jackson
的类,FastJson
无法序列化,所以配置文件里添加了MappingJackson2HttpMessageConverter
替代FastJsonHttpMessageConverter
。
替换过后能序列化JsonNode
了,但ios设备闪退…
到公司检查逻辑,默认情况下的MappingJackson2HttpMessageConverter
会将值为null的数据序列化成null,而FastJson
的会删除null值。
1
2
3
4
5
6
7
8
9
10
//fastJson的返回值,b被删除了
{
"a":"a"
}
//Jackson的返回值
{
"a":"a"
"b":null
}
看上面的对比,若b为null
的情况下,均在默认情况下,FastJson
会删除该键值对,Jackson
会序列化成"b":null
。
估计是iso
用的反序列化工具不支持值为null的情况导致的闪退。安卓的不会有问题。
三
在配置文件里定制MappingJackson2HttpMessageConverter
,让其忽略值为null的数据,解决问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean id="jacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<!--值为null时不返回-->
<property name="serializationInclusion">
<util:constant static-field="com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL"/>
</property>
<!--返回时间格式-->
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
</bean>
</property>
</bean>
四
代码可以这么写
1
2
3
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
五
JsonNode
里面的NullNode
因为不属于null,所以仍然会序列化成null,简单点的办法就是序列化之前遍历移出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static void removeNullNode(JsonNode nodes) {
if (nodes.isArray()) {
Iterator<JsonNode> iterator = nodes.iterator();
while (iterator.hasNext()) {
JsonNode next = iterator.next();
if (next.isNull()) {
iterator.remove();
} else {
removeNullNode(next);
}
}
} else if (nodes.isObject()) {
ObjectNode os = (ObjectNode) nodes;
Iterator<Map.Entry<String, JsonNode>> fields = os.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> next = fields.next();
if (next.getValue().isNull()) {
fields.remove();
} else {
removeNullNode(next.getValue());
}
}
}
}
六
2020-05-08更新:
有一个小坑,如果发现返回值对象中的字段为null能屏蔽,返回map内value为null不能屏蔽,请考虑下升级jackson
版本,高版本能解决这个问题。
我用的2.10.1
可以屏蔽map中的null值。