別給我講源碼,告訴我Moshi是如何實(shí)現(xiàn)反序列化的饵沧!

Moshi是什么

一句話描述

Moshi就是一個實(shí)現(xiàn)了對Json序列化和反序列化的開源庫

大名鼎鼎的Gson大家肯定都知道,Moshi本質(zhì)上就是干了和他一樣的事

( 本文是建立在對Moshi使用有一些簡單了解的基礎(chǔ)上赌躺,如果還沒有了解過Moshi狼牺,建議看下這篇文章新一代Json解析庫Moshi使用及原理解析)

為什么使用Moshi

一句話描述

Gson是一個針對Java的Json序列化和反序列化庫

Moshi是一個針對Kotlin的Json序列化和反序列化庫

在各種更高級語言涌現(xiàn)的今天,特別是kotlin的誕生礼患,雖然本質(zhì)上還是java那一套是钥,但各種方便易用的api和語法糖,讓人大呼爽歪歪缅叠。而老牌的Gson在處理Kotlin序列化問題上顯得有些力不從心悄泥,主要有兩個問題:

(1)空安全問題

Kotlin對變量分為可空類型和不可空類型,而Java中基本上所有變量都是可空的(除了@NonNullable標(biāo)簽)肤粱。如果Json中一個變量值是null弹囚,但Kotlin聲明這個變量是非空,Gson仍然會把這個變量賦值為null

(2)默認(rèn)參數(shù)失效

默認(rèn)參數(shù)是Kotlin的一個新語法领曼。是在定義一個data類時鸥鹉,直接在構(gòu)造函數(shù)中賦給參數(shù)默認(rèn)值蛮穿。例如:

class People(val name:String, val age:Int = 18)復(fù)制代碼

當(dāng)Json是:

{? ? "name" : "哈哈哈"}復(fù)制代碼

根據(jù)Kotlin的語法,期望得到的對象是

People(name="哈哈哈"宋舷,age = 18)復(fù)制代碼

但實(shí)際上Gson會解析成

People(name="哈哈哈"绪撵,age = 0)復(fù)制代碼

這樣就造成默認(rèn)參數(shù)age = 18的丟失

為了讓Json解析更加符合kotlin的語法規(guī)范,于是選擇使用Moshi

Moshi是如何實(shí)現(xiàn)反序列化的

這時候好奇的哥哥可能就要問了

為什么Moshi的解析更符合Kotlin的語法規(guī)范呢祝蝠? 你說符合就符合啊幻碱?

別急別急绎狭,想弄清這個問題,需要了解一下Moshi是如何實(shí)現(xiàn)反序列化的

我們先看一下Moshi反序列化的簡單使用:

// 需要反序列化的jsonval json = "{? ? "name": "張三",? ? "age": 18,? ? "email": "helloword@163.com"}"http:// Model類class People(val name:String褥傍,val age:Int ){val email : String = ""}// 反序列化fun parseModel(json: String): People? {? ? val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()? ? val adapter = moshi.adapter(People::class.java)? ? val people = adapter.fromJson(json)? ? return people}復(fù)制代碼

( Model類里藏了一個坑儡嘶,后面揭曉 ^ ^ )

沒有用過Moshi的哥哥可能很反感這種行為,“來不來就給我整幾行代碼恍风?我是看了代碼就能記住的人嗎蹦狂?!”

別急別急朋贬,我這就一點(diǎn)一點(diǎn)給您掰開了揉碎了說凯楔,您就舒舒服服躺好嘞~

這里陌生的東西主要有兩個。KotlinJsonAdapterFactory和adapter锦募。

①KotlinJsonAdapterFactory 是生成JsonAdapter的工廠

② val adapter = moshi.adapter(People::class.java)實(shí)際上就是傳了個class type給KotlinJsonAdapterFactory摆屯,然后工廠創(chuàng)建出adapter

③ adapter調(diào)用自己的fromJson和toJson方法完成序列化和反序列化過程。

把上面的代碼翻譯成流程圖就是:

Moshi反序列化過程就是這么簡單糠亩!

校驗(yàn)對象

了解了Moshi的反序列化流程虐骑,我們來回答一下上面哥哥的問題

為什么說用Moshi更符合kotlin語法規(guī)范呢?

我們先回到Moshi使用的那個例子赎线,這個反序列化的結(jié)果是什么呢廷没?

是People(name="張三", age = 18) email = "helloworld@163.com"

還是People(name="張三", age = 18) email = ""

我們從Kotlin語法分析,email是val不可變的垂寥。序列化實(shí)際上就是創(chuàng)建一個對象然后根據(jù)json進(jìn)行賦值颠黎,那么Moshi會對不可變的email進(jìn)行賦值嗎

答案是不會。

膽大心細(xì)臉皮厚的哥哥可能已經(jīng)看到上面流程圖中KotlinJsonAdapterFactory在生成JsonAdapter過程中矫废,有一個「檢驗(yàn)對象是否合法」的過程盏缤,我偷偷貼這個過程中的一行源碼:

// 位于:KotlinJsonAdapterFactory#create() if (property !is KMutableProperty1 && parameter == null) continue復(fù)制代碼

哎哎哎,我不是標(biāo)題黨蓖扑,這不是源碼唉铜,是英語英語,不信我給你解釋解釋

propery-- 表示數(shù)據(jù)類中所有的成員屬性律杠。用上面的例子來說就是val name:String潭流,val age:Int和var email : String = ""

KMutableProperty1-- 是Kotlin中的類型對象竞惋。表示的是var這個可變類型

parameter-- 表示構(gòu)造函數(shù)中的參數(shù)。用上面的例子就是val name:String灰嫉,val age:Int(這里聯(lián)系上下文知道parameter == null是用來判斷property是不是構(gòu)造函數(shù)中聲明的成員屬性)

continue-- 跳過拆宛。不對這個屬性反序列化了

所以用偉大中華人民共和國56個民族之一的漢族語言來說就是:

如果一個成員屬性,他是不可變的(也就是val)并且不是構(gòu)造函數(shù)中聲明的讼撒,就跳過它

看到了吧浑厚,KotlinAdapterJsonFactory實(shí)際上就是區(qū)別于Gson的關(guān)鍵之一,它對類對象做了一些校驗(yàn)根盒,使Moshi更加符合Kotlin語法

真正實(shí)現(xiàn)

KotlinJsonAdapter是Moshi的另一個核心钳幅,是Model的序列化和反序列化的真正實(shí)現(xiàn)

adapter的核心是binding

這里我們可以類比一下Model。一個Model對應(yīng)一個adapter炎滞,Model中的成員屬性就是一個個Binding

Binding負(fù)責(zé)基本數(shù)據(jù)類型的解析敢艰。IntBinding里面有個IntAdapter,負(fù)責(zé)解析json中的int類型册赛。StringBinding里有個StringAdapter钠导,負(fù)責(zé)解析json中的string類型。

總的來說森瘪,Binding就是負(fù)責(zé)拿到j(luò)son中字段的類型和值牡属,然后自己保存起來

至于json中字段的類型和值是如何被識別的嘛,Moshi基本上就是抄Gson的JsonReader和JsonWriter

KotlinJsonAdapter通過反射生成一個類對象柜砾,這些binding把成員屬性的值一個個賦值到屬性上湃望,最終生產(chǎn)出一個model對象。

等等等等痰驱,通過反射生成對象证芭?咋這么抽象呢?

很簡單啦担映。其實(shí)就是調(diào)用Android的Constructor類中newInstance(*args)方法

只要有類對象废士,生成實(shí)例對象就是一句話的事

People::class.java.constructors[1].newInstance("張三", 20)// constructors[0]是參數(shù)最多的構(gòu)造函數(shù)// 第三個參數(shù)表示第幾個構(gòu)造參數(shù)屬性用默認(rèn)參數(shù)的值// 所以結(jié)果是:People("張三", 18)People::class.java.constructors[0].newInstance("張三", 20, 2, null)復(fù)制代碼

到目前為止,我們基本上順了一遍Moshi反序列化的過程蝇完。盡量不貼大段代碼官硝,是不希望大家在好不容易啃完一遍源碼之后,過幾個星期就感覺似是而非短蜕,似懂非懂

所以我希望能給大家一個簡單的體系氢架, 有一些不得不用源碼的地方也是盡量給出通俗的解釋。

代碼只是細(xì)節(jié)的實(shí)現(xiàn)朋魔,是知識體系上的枝葉岖研。如果大家想再深入了解某些細(xì)節(jié),可以閱讀以下方法

// factory生成adapterKotlinJsonAdapterFactory#create()// adapter序列化和反序列化:KotlinJsonAdapter#fromJsonKotlinJsonAdapter#toJson// 反射生成對象KCallableImpl#callBy#callDefaultMethodCallerImpl>Constructor#callConstructor#newInstance復(fù)制代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市孙援,隨后出現(xiàn)的幾起案子害淤,更是在濱河造成了極大的恐慌,老刑警劉巖拓售,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窥摄,死亡現(xiàn)場離奇詭異,居然都是意外死亡础淤,警方通過查閱死者的電腦和手機(jī)崭放,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來值骇,“玉大人莹菱,你說我怎么就攤上這事≈ù瘢” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵迹缀,是天一觀的道長使碾。 經(jīng)常有香客問我,道長祝懂,這世上最難降的妖魔是什么票摇? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮砚蓬,結(jié)果婚禮上矢门,老公的妹妹穿的比我還像新娘。我一直安慰自己灰蛙,他們只是感情好祟剔,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摩梧,像睡著了一般物延。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仅父,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天叛薯,我揣著相機(jī)與錄音,去河邊找鬼笙纤。 笑死耗溜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的省容。 我是一名探鬼主播抖拴,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蓉冈!你這毒婦竟也來了城舞?” 一聲冷哼從身側(cè)響起轩触,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎家夺,沒想到半個月后脱柱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拉馋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年榨为,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煌茴。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡随闺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔓腐,到底是詐尸還是另有隱情矩乐,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布回论,位于F島的核電站散罕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏傀蓉。R本人自食惡果不足惜欧漱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望葬燎。 院中可真熱鬧误甚,春花似錦、人聲如沸谱净。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岳遥。三九已至奕翔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浩蓉,已是汗流浹背派继。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捻艳,地道東北人驾窟。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像认轨,于是被迫代替她去往敵國和親绅络。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容