最近的項目里面對解析Json出現(xiàn)了一些問題奈梳,主要集中在iOS和Android兩者在同一個字符串識別的時候出現(xiàn)的結(jié)果不同
先看一個Json例子
{
"aa": 1,
"bb": "bb",
"cc": true
}
這是一個簡單的Json字符串萄窜,包含了數(shù)字,字符串和bool值懂拾,而引起這篇文章的動機就是cc的bool值,在標準Json中對bool值的定義是 true或者false铐达,也就是說只有標準的小寫并且不帶引號的這兩個字符串才是正確的bool值岖赋。
類似于True和False這樣不標準的bool值在標準Json中是錯誤的,但是強大的抓包工具能夠讓我們對發(fā)送的請求和response的數(shù)據(jù)進行更改瓮孙,也就是說在中途如果我們將標準的true改成True唐断,那么會發(fā)生什么呢?接下來請看下面分解杭抠。
為了和上面的Json數(shù)據(jù)對應脸甘,我們創(chuàng)建一個對象
data class JsonData(var aa: Int, var bb: String, var cc: Boolean)
Google的Gson庫進行解析
val jsonStr = "{\"aa\": 1,\"bb\": \"bb\",\"cc\": true}"
@Test
fun testParseJsonByGson(){
val jsonObj = Gson().fromJson(jsonStr, JsonData::class.java)
assertEquals(jsonObj.cc, true)
}
上面的代碼直接將字符串轉(zhuǎn)換成了對象,沒有問題偏灿,下面我們用同樣的方法將Json字符串里面的true改成大寫的True試試
val jsonStr = "{\"aa\": 1,\"bb\": \"bb\",\"cc\": True}"
@Test
fun testParseJsonByGson(){
val jsonObj = Gson().fromJson(jsonStr, JsonData::class.java)
assertEquals(jsonObj.cc, true)
}
這樣測試也沒問題丹诀,這就表示Gson庫是大小寫不敏感的,好了翁垂,現(xiàn)在我們來看看Gson關于這部分的源碼就自知道了铆遭,找到 com.google.gson.stream.JsonReader
類,里面的peekKeyword方法沿猜,如下
if (c == 't' || c == 'T') {
keyword = "true";
keywordUpper = "TRUE";
peeking = PEEKED_TRUE;
} else if (c == 'f' || c == 'F') {
keyword = "false";
keywordUpper = "FALSE";
peeking = PEEKED_FALSE;
} else if (c == 'n' || c == 'N') {
keyword = "null";
keywordUpper = "NULL";
peeking = PEEKED_NULL;
} else {
return PEEKED_NONE;
}
可以看出Gson里面是部分大小寫的疚脐,不管是T開頭還是t開頭的true都會認為是bool類型。
而如果我們將JsonData類中的cc改成String類型的呢邢疙?
data class JsonData(var aa: Int, var bb: String, var cc: String)
這時你會發(fā)現(xiàn)Gson會將bool中的True轉(zhuǎn)換成true棍弄,然后再把小寫的true轉(zhuǎn)換成字符串的 true
。而如果此時是Tru
這樣一個錯誤的值疟游,那么就不會被轉(zhuǎn)換成小寫的true然后再轉(zhuǎn)換成字符串呼畸,而是直接轉(zhuǎn)換成字符串 "Tru"這樣大寫的。
阿里的FastJson進行解析
這里不重復說明颁虐,在正確的書寫情況下蛮原,F(xiàn)astJson和Gson是一樣的解析結(jié)果,而如果是下面這種情況另绩,將 True
進行大寫
val jsonStr = "{\"aa\": 1,\"bb\": \"bb\",\"cc\": True}"
再使用FastJson進行解析
@Test
fun testParseJsonByFastJson(){
val jsonObj = JSON.parseObject(jsonStr, JsonData::class.java)
assertEquals(jsonObj.cc, true)
}
結(jié)果是拋出異常
om.alibaba.fastjson.JSONException: default constructor not found.
我們?nèi)astJson的源碼看看為什么會這樣儒陨,找到 com.alibaba.fastjson.parser.DefaultJSONParser中的parseObject方法
if (lexer.text.startsWith("true", lexer.bp)) {
lexer.bp += 3;
lexer.next();
object.put(key, Boolean.TRUE);
}
} else if (ch == 'f') {
if (lexer.text.startsWith("false", lexer.bp)) {
lexer.bp += 4;
lexer.next();
object.put(key, Boolean.FALSE);
}
這段代碼對true和false進行了限制花嘶,只有當這個值符合小寫的true和false時才被認為是bool值,如果不是蹦漠,我們這里不關心椭员,只要明白如果不是小寫的字母那么就不被認可為bool值了。
總結(jié)
這次的問題出在之前對Gson解析的不完全了解笛园,而Gson庫對出現(xiàn)的Json對象數(shù)據(jù)進行了最大程度的包容處理隘击,這里不能說誰對錯,關鍵看項目怎么用了研铆,如果要求嚴格一點埋同,那么就換成FastJson這樣的三方庫來保證,如果要求更松那么Gson就能滿足你的要求了