1. 程式人生 > >fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 下:來到 fasjson 內部,消除疑惑

fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 下:來到 fasjson 內部,消除疑惑

接上篇:fastjson 始終將 null 物件以 "null " 的形式返回到前端引發的原始碼解析 - 上:從 DispatcherServlet 出發

終於來到了 fastjson 內部。

FastJsonHttpMessageConverter

內部又呼叫了一系列的方法,最終定位到了 JavaBeanSerializer#write 的 216 行。
image.png

在這裡 fastjson 與 spring web 的連線主要是通過 GenericHttpMessageConverter 介面,FastJsonHttpMessageConverter 類實現了該介面,該介面繼承於 HttpMessageConverter

介面,特定只對 HTTP 請求和響應資料進行轉換處理。
再回過頭看下 RequestResponseBodyMethodProcessor#writeWithMessageConverters 方法是怎麼關聯上 FastJsonHttpMessageConverter的:
image.png

JavaBeanSerializer

該類的 write 方法是最終輸出 json 格式資料的地方,其中對 null 型別物件判斷是否要以 "obj": null" 形式輸出的關鍵程式碼如下:


                if (propertyValue == null && !writeAsArray) {
                    if ((!fieldSerializer.writeNull) && (!out.isEnabled(SerializerFeature.WRITE_MAP_NULL_FEATURES))) {
                        continue;
                    }
                }

continue 執行時當前成員就會跳過,不進行處理,也就不會輸出。

SerializeWriter#isEnable 方法原始碼如下

    public boolean isEnabled(int feature) {
        return (this.features & feature) != 0;
    }

該判斷置於一個迴圈中,迴圈用於遍歷目標類的成員,進行處理並輸出。propertyValue 即為當前遍歷到成員的值。fieldSerializer 則是專門序列化當前成員的處理者。

  1. 首先值為 null 並且 SerializerFeature.BeanToArray
    特性未啟用
  2. fieldSerializer 的 writeNull 為 false:writeNull 在其建構函式中賦值,建構函式中會藉助 @JSONField註解初始化 FieldSerializer 的成員,其中如果 SerializerFeature.WRITE_MAP_NULL_FEATURES 特性(實體類成員上類似這樣使用 @JSONField(serialzeFeatures = {SerializerFeature.WRITE_MAP_NULL_FEATURES} ) 註解)啟用的話,writeNull 才為 true,否則 false
  3. 如果 fieldSerializer.writeNull 為 false,則需要進一步判斷,out 是一個 SerializeWriter 物件,繼承自 java.io.Writer,用於輸出 json 字串,out 中攜帶了我們最初的配置

image.png

out.isEnable() 會通過 FastJsonConfig 判斷是否配置了某一特性,如上所示,並沒有配置 SerializerFeature.WRITE_MAP_NULL_FEATURES 特性,那麼為什麼 “obj”: null 還是會輸出呢 ?答案在 WRITE_MAP_NULL_FEATURES 內部

撥雲見日

image.png

可見 SerializerFeature.WRITE_MAP_NULL_FEATURES 是以下幾個特性的組合:

WriteMapNullValue
WriteNullBooleanAsFalse
WriteNullListAsEmpty
WriteNullNumberAsZero
WriteNullStringAsEmpty

fastjson 特性的處理採用的是 二進位制狀態疊加 的方式,這裡的意思是 WRITE_MAP_NULL_FEATURES 特性是其它這幾個特性的集合,
舉個栗子:

如果
0001 -> WriteNullListAsEmpty
0010 -> WriteNullBooleanAsFalse
WRITE_MAP_NULL_FEATURES = WriteNullBooleanAsFalse.getMask() | WriteNullListAsEmpty.getMask()
則
0011 -> WRITE_MAP_NULL_FEATURES

假設配置了 WriteNullListAsEmpty
0001 -> features
呼叫 out.isEnabled(SerializerFeature.WRITE_MAP_NULL_FEATURES) 
   0001
&  0011
   0001 != 0 
結果為 true  

即這幾個特性任意一個配置了,那麼相當於 WRITE_MAP_NULL_FEATURES 也就配置了,這種情況下 會把 null 以 "obj": null 的形式輸出。