1. 程式人生 > >排坑:kotlin物件序列化過程引數丟失

排坑:kotlin物件序列化過程引數丟失

問題現象與背景:

這個bug出現在引入kotlin程式碼的過程中。我們的專案採用的是spring boot框架,為前端提供業務介面。通過周密調研,我們計劃在一個子模組中應用kotlin來進行業務開發。springbootkotlin的結合方式不再本文累述。

開發過程中發現了一個bug:系統提供的介面有部分引數丟失。如圖所示,輸出的介面資料中沒有is_try_readis_onlineis_free3個數據。


進一步進行debug,發現記憶體中該物件確實包含對應屬性。

 


方法已經執行到了return這一步,那麼為什麼在輸出環節丟失了資料呢?

排查與定位:

首先分析該輸出物件的類的設計是否有異常。該物件的類採用

kotlin的資料類實現。


Kotlin 可以建立一個只包含資料的類,關鍵字為data。編譯器會自動的從主建構函式中根據所有宣告的屬性生產equals()、hashCode()、toString() 、componentN()、和copy() 函式。kotlin的資料類簡化了這種用於表示特定實體的類,不用再麻煩地設定settergetter方法。根據kotlin程式碼設計原則,屬性預設為public級別可見性,編譯器會為其生成settergetter方法。如圖所示的資料類設計應該沒有問題。

接著我反編譯資料類class檔案,發現了一些端倪。如圖所示,"is"開頭的變數,編譯器自動加上

setget方法時,命名規則和其他在變數首部新增"set""get"字母的駝峰方式有所不同,例如is_online變數自動生成的方法為set_online()is_online()isOnline變數自動生成方法為setOnline()isOnline()。這本身無可厚非,但是和某些java框架、工具結合起來就顯現出了問題。


綜上,我覺得可能spring boot預設的序列化工具在把物件轉換成json字串時可能找不到上述"is"開頭的變數的get方法才導致該變數丟失。於是我寫了一個簡單的測試方法來測試fastJsonGsonJackson3個序列化工具。如圖所示。


其中Book

是一個kotlin資料類,從輸出結果發現:只有Gson保留了完整資料。


解決方案:

至此,定位到了問題原因是kotlin"is"開頭變數編譯生成的setget方法命名方式有所不同導致某些java序列化工具不能識別。因為專案用的序列化工具是jackson,所以我升級了jackson的版本,發現變數仍然丟失。

解決方案一:

資料類不用"is"開頭來命名變數。但是這個始終留下了隱患,開發人員稍不注意可能就掉坑裡了,治標不治本。

解決方案二:

Gson替換框架的序列化工具。在典型的Spring場景中,一旦請求退出後,那麼@Controller註解就會去渲染一個檢視。我們可以通過@RequestBody或者@RestController這種註解來請求Spring,並且可以直接將Model中的java物件注入到Response中,而這個過程中應用了序列化。我採用HttpMessageConverters來自定義gson為定首選序列化工具。配置如下:

@Configuration

publicclass CustomConfiguration {

    @Bean

    public HttpMessageConverterscustomConverters() {

       Collection<HttpMessageConverter<?>> messageConverters = newArrayList<>();

        GsonHttpMessageConvertergsonHttpMessageConverter = new GsonHttpMessageConverter();

       messageConverters.add(gsonHttpMessageConverter);

        return new HttpMessageConverters(true,messageConverters);

    }

}

通過這個配置,springframework框架預設使用的HttpMessageConverter中追加了GsonHttpMessageConverter來進行序列化工作。

最終我採用了方案二的方式來處理這個問題。

其他:

定位問題過程中其實還有一些曲折,例如is_try_readis_onlineis_free3個變數都是kotlinInt型別,而kotlinIntjavaintInteger相對應,懷疑可能是這個型別出現的序列化問題。但是在控制變數多次嘗試後,發現與型別無關,String型別的is_online變數依然會丟失。

Gson提供了流式序列化的方法,核心是各種adapterwrite方法。


通過getAdapter(TypeToken<T> type)方法來繫結物件的變數到其AdapterboundFields來進行後續轉換。


參考資料:

相關推薦

kotlin物件序列過程引數丟失

問題現象與背景: 這個bug出現在引入kotlin程式碼的過程中。我們的專案採用的是spring boot框架,為前端提供業務介面。通過周密調研,我們計劃在一個子模組中應用kotlin來進行業務開發。springboot與kotlin的結合方式不再本文累述。 開發過程中發

(二)遠端服務Java 物件序列和反序列

在遠端方法呼叫 RMI 學習的過程中,涉及到一個概念,序列化,本文進行詳述。 Java 物件的序列化和反序列化 的兩種應用場景 有時候需要將 Java 物件儲存永久儲存,比如儲存到檔

面向物件【day07】類的例項過程剖析(三)

本節內容 1、概述 2、類的語法 3、總結 一、概述    之前我們說關於python中的類,都一臉懵逼,都想說,類這麼牛逼到底是什麼,什麼才是類?下面我們就來講講,什麼是類?它具有哪些特性。 二、類的語法 2.1 語法

記一次使用Jackson對Java物件序列和反序列的踩經歷

背景大概是這樣,專案中的兩個服務A和B依賴了同一個common包的Java類,A對該類json序列化,而B對其反序列化。在一次common包升級過程中,這個Java類中增加了一個屬性,由於B其實用不到這個屬性,就只把A給升級打包了,這就導致B在反序列化時出現了一個異常:com.fasterxml.j

Java之路物件序列

一、物件序列化的基本概念 所謂的物件序列化(在某些書籍中也叫序列化),是指在記憶體之中儲存的物件轉化為二進位制資料流的形式的一種操作。通過將物件序列化,可以方便地實現物件的傳輸及儲存。 但是在Java之中並不是所有的類的物件都可以被序列化,如果一個類物件需要被序

C#物件序列

序列化的方法很簡單,如下:         /// <summary>        /// 文字化XML序列化  &nb

面試題Java中物件序列介面(Serializable)的意義

Serializable介面是一個裡面什麼都沒有的介面 它的原始碼是public interface Serializable{},即什麼都沒有。 如果一個接口裡面什麼內容都沒有,那麼這個介面是一個標識介面,比如,一個學生遇到一個問題,排錯排了幾天也沒解決,此時,她舉手了(示意我去幫他解決),然後我過去,幫他

物件序列使用System.Xml.Serialization名稱空間(轉)

        要使用.NET進行物件的序列化,必須在解決方案中新增System.Xml的引用,並且在類檔案中引入System.Xml.Serialization名稱空間。這樣就可以在檔案中使用序列化所需要的各種特性了。 Imports System.Xml.Seriali

rocketMq如何設置rocketMq broker的ip地址

配置文件 clas vip 一個 同事 tex -s https osc 在工作中遇到了一個這個問題,就是我們rocketmq是部署在雲主機上的 但是我們的開發同事在自己的電腦連接rocketmq鏈接不上 報錯顯示Caused by: org.apache.rocketmq

Serializable 指示一個類可以序列;ICloneable支持克隆,即用與現有實例相同的值創建類的新實例(接口);ISerializable允許對象控制其自己的序列和反序列過程(接口)

att 文本 所有 可能 成員 強制 void inter 適用於 Serializable : 序列化是指將對象實例的狀態存儲到存儲媒體的過程。在此過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換為字節流,然後再把字節流寫入數據流。在隨後對對象進

74、CallContext線程數據緩存-調用上下文 System.Runtime.Remoting.Messaging,JOIN序列過程中日期的處理

線程 none tle border img ren call rem 圖片 74、CallContext線程數據緩存-調用上下文 System.Runtime.Remoting.Messaging,JOIN序列化過程中日期的處理

運維常用正則表達式

blog img .com ODB status ext mon shell使用 更新 一、awk提取雙引號之間的字符串方法:如文本:Speed="1000" echo ‘Speed="1000"‘ | awk -F ‘"

FastJson自定義複雜物件序列

總結:  SerializeFilter是通過程式設計擴充套件的方式定製序列化。fastjson支援6種SerializeFilter,用於不同場景的定製序列化。  PropertyPreFilter 根據PropertyName判斷是否序列化  Pr

JVM總括四-類載入過程、雙親委派模型、物件例項過程 JVM思考-init和clinit區別

JVM總括四-類載入過程、雙親委派模型、物件例項化過程 目錄:JVM總括:目錄 一、 類載入過程 類載入過程就是將.class檔案轉化為Class物件,類例項化的過程,(User user = new User(); 這個過程是物件例項化的過程); 一個.class檔案只有一個Class物件(位元

JVM思考-init和clinit區別 JVM總括四-類載入過程、雙親委派模型、物件例項過程

JVM思考-init和clinit區別 目錄:JVM總括:目錄 clinit和init的區別其實也就是Class物件初始化物件初始化的區別,詳情看我上一篇部落格:  JVM總括四-類載入過程、雙親委派模型、物件例項化過程 一、init和clinit方法執行時機不同   init是物件構

JVM總括四-類載入過程、雙親委派模型、物件例項過程

JVM總括四-類載入過程、雙親委派模型、物件例項化過程 目錄:JVM總括:目錄 一、 類載入過程 類載入過程就是將.class檔案轉化為Class物件, 類例項化 的過程 ,(User user = new User(); 這個過程是 物件例項化 的

java物件序列機制

1.定義 java物件序列化機制允許實現了Serializable/Externalizable介面的java物件永久性地儲存到計算機的磁碟中,或則允許java物件直接在網路中傳輸,擺脫平臺的限制。反序列化即使將IO流中的位元組序列轉化為java物件。 2.原理 3.使用 序列化: 1)一個實現了S

java基礎類庫學習(六.6)物件序列

前言 物件序列化:允許把記憶體中的物件轉換成平臺無關的二進位制流,從而把這種二進位制流持久的儲存自磁碟上,通過網路將這種二進位制流傳輸到網路的另一個節點,其他程式一旦獲得了這種二進位制流,都可以將這種二進位制流恢復成原來的java物件 物件的序列化是指將一個java物件寫入io流中,

Gohttp.ServeMux意外重定向的問題分析

何為http.ServeMux? http.ServeMux是什麼?官方定義為http服務的多路複用器。可以讓開發在http伺服器中自定義不同的path路由和對應的處理函式,我們簡單舉個例子: package main import ( "net/http" "fmt" ) func

Python 中將例項物件序列

Python中支援json進行資料封裝的資料型別有str ,list,dict,如果想要對Python中的例項化物件進行json資料封裝時,一般採用將物件轉化為字典型別,方法是呼叫dict(),但是前提必須給類提供倆個方法keys和 --getitem–,程式碼如下: class St