记一次Jackson引发的血案

Posted by hcy on December 25, 2019

记一次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值。


转载请注明出处:https://www.huangchaoyu.com/2019/12/25/记一次Jackson引发的血案/