中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

json框架的特點有哪些

發布時間:2021-10-20 11:08:11 來源:億速云 閱讀:181 作者:iii 欄目:開發技術

本篇內容主要講解“json框架的特點有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“json框架的特點有哪些”吧!

為何要放棄fastjson?

究其原因,是fastjson漏洞頻發,導致了公司內部需要頻繁的督促各業務線升級fastjson版本,來防止安全問題。

fastjson在2020年頻繁暴露安全漏洞,此漏洞可以繞過autoType開關來實現反序列化遠程代碼執行并獲取服務器訪問權限。

從2019年7月份發布的v1.2.59一直到2020年6月份發布的 v1.2.71  ,每個版本的升級中都有關于AutoType的升級,涉及13個正式版本。

fastjson中與AutoType相關的版本歷史:

  • 1.2.59發布,增強AutoType打開時的安全性 fastjson

  • 1.2.60發布,增加了AutoType黑名單,修復拒絕服務安全問題 fastjson

  • 1.2.61發布,增加AutoType安全黑名單 fastjson

  • 1.2.62發布,增加AutoType黑名單、增強日期反序列化和JSONPath fastjson

  • 1.2.66發布,Bug修復安全加固,并且做安全加固,補充了AutoType黑名單 fastjson

  • 1.2.67發布,Bug修復安全加固,補充了AutoType黑名單 fastjson

  • 1.2.68發布,支持GEOJSON,補充了AutoType黑名單

  • 1.2.69發布,修復新發現高危AutoType開關繞過安全漏洞,補充了AutoType黑名單

  • 1.2.70發布,提升兼容性,補充了AutoType黑名單

  • 1.2.71發布,補充安全黑名單,無新增利用,預防性補充

相比之下,其他的json框架,如Gson和Jackson,漏洞數量少很多,高危漏洞也比較少,這是公司想要替換框架的主要原因。

fastjson替代方案

本文主要討論Gson替換fastjson框架的實戰問題,所以在這里不展開詳細討論各種json框架的優劣,只給出結論。

經過評估,主要有Jackson和Gson兩種json框架放入考慮范圍內,與fastjson進行對比。

三種json框架的特點

FastJson

速度快

fastjson相對其他JSON庫的特點是快,從2011年fastjson發布1.1.x版本之后,其性能從未被其他Java實現的JSON庫超越。

使用廣泛

fastjson在阿里巴巴大規模使用,在數萬臺服務器上部署,fastjson在業界被廣泛接受。在2012年被開源中國評選為最受歡迎的國產開源軟件之一。

測試完備

fastjson有非常多的testcase,在1.2.11版本中,testcase超過3321個。每次發布都會進行回歸測試,保證質量穩定。

使用簡單

fastjson的API十分簡潔。

Jackson

  • 容易使用 - jackson API提供了一個高層次外觀,以簡化常用的用例。

  • 無需創建映射 - API提供了默認的映射大部分對象序列化。

  • 性能高 - 快速,低內存占用,適合大型對象圖表或系統。

  • 干凈的JSON - jackson創建一個干凈和緊湊的JSON結果,這是讓人很容易閱讀。

不依賴 - 庫不需要任何其他的庫,除了JDK。

Gson

  • 提供一種機制,使得將Java對象轉換為JSON或相反如使用toString()以及構造器(工廠方法)一樣簡單。

  • 允許預先存在的不可變的對象轉換為JSON或與之相反。

  • 允許自定義對象的表現形式

  • 支持任意復雜的對象

  • 輸出輕量易讀的JSON

性能對比

本文不詳細討論性能的差異,畢竟這其中涉及了很多各個框架的實現思路和優化,所以只給出結論:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 序列化單對象性能Fastjson > Jackson >  Gson,其中Fastjson和Jackson性能差距很小,Gson性能較差

  3. 序列化大對象性能Jackson> Fastjson > Gson ,序列化大Json對象時Jackson> Gson >  Fastjson,Jackson序列化大數據時性能優勢明顯

  4. 反序列化單對象性能 Fastjson > Jackson > Gson , 性能差距較小

  5. 反序列化大對象性能 Fastjson > Jackson > Gson , 性能差距較很小

最終選擇方案

Jackson適用于高性能場景,Gson適用于高安全性場景

對于新項目倉庫,不再使用fastjson。對于存量系統,考慮到Json更換成本,由以下幾種方案可選:  項目未使用autoType功能,建議直接切換為非fastjson,如果切換成本較大,可以考慮繼續使用fastjson,關閉safemode。業務使用了autoType功能,建議推進廢棄fastjson。

替換依賴注意事項

企業項目或者說大型項目的特點:

  • 代碼結構復雜,團隊多人維護。

  • 承擔重要線上業務,一旦出現嚴重bug會導致重大事故。

  • 如果是老項目,可能缺少文檔,不能隨意修改,牽一發而動全身。

  • 項目有很多開發分支,不斷在迭代上線。

所以對于大型項目,想要做到將底層的fastjson遷移到gson是一件復雜且痛苦的事情,其實對于其他依賴的替換,也都一樣。

我總結了如下幾個在替換項目依賴過程中要特別重視的問題。

謹慎,謹慎,再謹慎

再怎么謹慎都不為過,如果你要更改的項目是非常重要的業務,那么一旦犯下錯誤,代價是非常大的。并且,對于業務方和產品團隊來說,沒有新的功能上線,但是系統卻炸了,是一件“無法忍受”的事情。盡管你可能覺得很委屈,因為只有你或者你的團隊知道,雖然業務看上去沒變化,但是代碼底層已經發生了翻天覆地的變化。

所以,謹慎點!

做好開發團隊和測試團隊的溝通

在依賴替換的過程中,需要做好項目的規劃,比如分模塊替換,嚴格細分排期。

把前期規劃做好,開發和測試才能有條不紊的進行工作。

開發之間,需要提前溝通好開發注意事項,比如依賴版本問題,防止由多個開發同時修改代碼,最后發現使用的版本不同,接口用法都不同這種很尷尬,并且要花額外時間處理的事情。

而對于測試,更要事先溝通好。一般來說,測試不會太在意這種對于業務沒有變化的技術項目,因為既不是優化速度,也不是新功能。但其實遷移涉及到了底層,很容易就出現BUG。要讓測試團隊了解更換項目依賴,是需要大量的測試時間投入的,成本不亞于新功能,讓他們盡量重視起來。

做好回歸/接口測試

上面說到測試團隊需要投入大量工時,這些工時主要都用在項目功能的整體回歸上,也就是回歸測試。

當然,不只是業務回歸測試,如果有條件的話,要做接口回歸測試。

如果公司有接口管理平臺,那么可以極大提高這種項目測試的效率。

打個比方,在一個模塊修改完成后,在測試環境(或者沙箱環境),部署一個線上版本,部署一個修改后的版本,直接將接口返回數據進行對比。一般來說是Json對比,網上也有很多的Json對比工具:

  • https://www.sojson.com/

考慮遷移前后的性能差異

正如上面描述的Gson和Fastjson性能對比,替換框架需要注意框架之間的性能差異,尤其是對于流量業務,也就是高并發項目,響應時間如果發生很大的變化會引起上下游的注意,導致一些額外的后果。

使用Gson替換Fastjson

這里總結了兩種json框架常用的方法,貼出詳細的代碼示例,幫助大家快速的上手Gson,無縫切換!

Json反序列化

String jsonCase = "[{\"id\":10001,\"date\":1609316794600,\"name\":\"小明\"},{\"id\":10002,\"date\":1609316794600,\"name\":\"小李\"}]";  // fastjson JSONArray jsonArray = JSON.parseArray(jsonCase); System.out.println(jsonArray); System.out.println(jsonArray.getJSONObject(0).getString("name")); System.out.println(jsonArray.getJSONObject(1).getString("name")); // 輸出: // [{"date":1609316794600,"name":"小明","id":10001},{"date":1609316794600,"name":"小李","id":10002}] // 小明 // 小李  // Gson JsonArray jsonArrayGson = gson.fromJson(jsonCase, JsonArray.class); System.out.println(jsonArrayGson); System.out.println(jsonArrayGson.get(0).getAsJsonObject().get("name").getAsString()); System.out.println(jsonArrayGson.get(1).getAsJsonObject().get("name").getAsString()); // 輸出: // [{"id":10001,"date":1609316794600,"name":"小明"},{"id":10002,"date":1609316794600,"name":"小李"}] // 小明 // 小李

看得出,兩者區別主要在get各種類型上,Gson調用方法有所改變,但是變化不大。

那么,來看下空對象反序列化會不會出現異常:

String jsonObjectEmptyCase = "{}";  // fastjson JSONObject jsonObjectEmpty = JSON.parseObject(jsonObjectEmptyCase); System.out.println(jsonObjectEmpty); System.out.println(jsonObjectEmpty.size()); // 輸出: // {} // 0  // Gson JsonObject jsonObjectGsonEmpty = gson.fromJson(jsonObjectEmptyCase, JsonObject.class); System.out.println(jsonObjectGsonEmpty); System.out.println(jsonObjectGsonEmpty.size()); // 輸出: // {} // 0

沒有異常,開心。

看看空數組呢,畢竟[]感覺比{}更加容易出錯。

String jsonArrayEmptyCase = "[]";  // fastjson JSONArray jsonArrayEmpty = JSON.parseArray(jsonArrayEmptyCase); System.out.println(jsonArrayEmpty); System.out.println(jsonArrayEmpty.size()); // 輸出: // [] // 0  // Gson JsonArray jsonArrayGsonEmpty = gson.fromJson(jsonArrayEmptyCase, JsonArray.class); System.out.println(jsonArrayGsonEmpty); System.out.println(jsonArrayGsonEmpty.size()); // 輸出: // [] // 0

兩個框架也都沒有問題,完美解析。

范型處理

解析泛型是一個非常常用的功能,我們項目中大部分fastjson代碼就是在解析json和Java Bean。

// 實體類 User user = new User(); user.setId(1L); user.setUserName("馬云");  // fastjson List<User> userListResultFastjson = JSONArray.parseArray(JSON.toJSONString(userList), User.class); List<User> userListResultFastjson2 = JSON.parseObject(JSON.toJSONString(userList), new TypeReference<List<User>>(){}); System.out.println(userListResultFastjson); System.out.println("userListResultFastjson2" + userListResultFastjson2); // 輸出: // userListResultFastjson[User [Hash = 483422889, id=1, userName=馬云], null] // userListResultFastjson2[User [Hash = 488970385, id=1, userName=馬云], null]  // Gson List<User> userListResultTrue = gson.fromJson(gson.toJson(userList), new TypeToken<List<User>>(){}.getType()); System.out.println("userListResultGson" + userListResultGson); // 輸出: // userListResultGson[User [Hash = 1435804085, id=1, userName=馬云], null]

可以看出,Gson也能支持泛型。

List/Map寫入

這一點fastjson和Gson有區別,Gson不支持直接將List寫入value,而fastjson支持。

所以Gson只能將List解析后,寫入value中,詳見如下代碼:

// 實體類 User user = new User(); user.setId(1L); user.setUserName("馬云");  // fastjson JSONObject jsonObject1 = new JSONObject(); jsonObject1.put("user", user); jsonObject1.put("userList", userList); System.out.println(jsonObject1); // 輸出: // {"userList":[{"id":1,"userName":"馬云"},null],"user":{"id":1,"userName":"馬云"}}  // Gson JsonObject jsonObject = new JsonObject(); jsonObject.add("user", gson.toJsonTree(user)); System.out.println(jsonObject); // 輸出: // {"user":{"id":1,"userName":"馬云"},"userList":[{"id":1,"userName":"馬云"},null]}

如此一來,Gson看起來就沒有fastjson方便,因為放入List是以gson.toJsonTree(user)的形式放入的。這樣就不能先入對象,在后面修改該對象了。(有些同學比較習慣先放入對象,再修改對象,這樣的代碼就得改動)

駝峰與下劃線轉換

駝峰轉換下劃線依靠的是修改Gson的序列化模式,修改為LOWER_CASE_WITH_UNDERSCORES

GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); Gson gsonUnderScore = gsonBuilder.create(); System.out.println(gsonUnderScore.toJson(user)); // 輸出: // {"id":1,"user_name":"馬云"}

常見問題排雷

下面整理了我們在公司項目遷移Gson過程中,踩過的坑,這些坑現在寫起來感覺沒什么技術含量。但是這才是我寫這篇文章的初衷,幫助大家把這些很難發現的坑避開。

這些問題有的是在測試進行回歸測試的時候發現的,有的是在自測的時候發現的,有的是在上線后發現的,比如Swagger掛了這種不會去測到的問題。

Date序列化方式不同

不知道大家想過一個問題沒有,如果你的項目里有緩存系統,使用fastjson寫入的緩存,在你切換Gson后,需要用Gson解析出來。所以就一定要保證兩個框架解析邏輯是相同的,但是,顯然這個愿望是美好的。

在測試過程中,發現了Date類型,在兩個框架里解析是不同的方式。

  • fastjson:Date直接解析為Unix

  • Gson:直接序列化為標準格式Date

json框架的特點有哪些

導致了Gson在反序列化這個json的時候,直接報錯,無法轉換為Date。

解決方案:

新建一個專門用于解析Date類型的類:

import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter;  import java.io.IOException; import java.util.Date;  public class MyDateTypeAdapter extends TypeAdapter<Date> {     @Override     public void write(JsonWriter out, Date value) throws IOException {         if (value == null) {             out.nullValue();         } else {             out.value(value.getTime());         }     }      @Override     public Date read(JsonReader in) throws IOException {         if (in != null) {             return new Date(in.nextLong());         } else {             return null;         }     } }

接著,在創建Gson時,把他放入作為Date的專用處理類:

Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,new MyDateTypeAdapter()).create();

這樣就可以讓Gson將Date處理為Unix。

當然,這只是為了兼容老的緩存,如果你覺得你的倉庫沒有這方面的顧慮,可以忽略這個問題。

SpringBoot異常

切換到Gson后,使用SpringBoot搭建的Web項目的接口直接請求不了了。報錯類似:

org.springframework.http.converter.HttpMessageNotWritableException

因為SpringBoot默認的Mapper是Jackson解析,我們切換為了Gson作為返回對象后,Jackson解析不了了。

解決方案:

application.properties里面添加:

#Preferred JSON mapper to use for HTTP message conversion spring.mvc.converters.preferred-json-mapper=gson

Swagger異常

這個問題和上面的SpringBoot異常類似,是因為在SpringBoot中引入了Gson,導致 swagger 無法解析 json。

json框架的特點有哪些

采用類似下文的解決方案(添加Gson適配器):

  • http://yuyublog.top/2018/09/03/springboot%E5%BC%95%E5%85%A5swagger/

GsonSwaggerConfig.java

@Configuration public class GsonSwaggerConfig {     //設置swagger支持gson     @Bean     public IGsonHttpMessageConverter IGsonHttpMessageConverter() {         return new IGsonHttpMessageConverter();     } }

IGsonHttpMessageConverter.java

public class IGsonHttpMessageConverter extends GsonHttpMessageConverter {     public IGsonHttpMessageConverter() {         //自定義Gson適配器         super.setGson(new GsonBuilder()                 .registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter())                 .serializeNulls()//空值也參與序列化                 .create());     } }

SpringfoxJsonToGsonAdapter.java

public class SpringfoxJsonToGsonAdapter implements JsonSerializer<Json> {     @Override     public JsonElement serialize(Json json, Type type, JsonSerializationContext jsonSerializationContext) {         return new JsonParser().parse(json.value());     } }

@Mapping JsonObject作為入參異常

有時候,我們會在入參使用類似:

public ResponseResult submitAudit(@RequestBody JsonObject jsonObject) {}

如果使用這種代碼,其實就是使用Gson來解析json字符串。但是這種寫法的風險是很高的,平常請大家盡量避免使用JsonObject直接接受參數。

在Gson中,JsonObject若是有數字字段,會統一序列化為double,也就是會把count = 0這種序列化成count = 0.0。

為何會有這種情況?簡單的來說就是Gson在將json解析為Object類型時,會默認將數字類型使用double轉換。

  • 如果Json對應的是Object類型,最終會解析為Map類型;其中Object類型跟Json中具體的值有關,比如雙引號的""值翻譯為STRING。我們可以看下數值類型(NUMBER)全部轉換為了Double類型,所以就有了我們之前的問題,整型數據被翻譯為了Double類型,比如30變為了30.0。

可以看下Gson的ObjectTypeAdaptor類,它繼承了Gson的TypeAdaptor抽象類:

json框架的特點有哪些

解決方案:

  • 第一個方案:把入參用實體類接收,不要使用JsonObject

  • 第二個方案:與上面的解決Date類型問題類似,自己定義一個Adaptor,來接受數字,并且處理。這種想法我覺得可行但是難度較大,可能會影響到別的類型的解析,需要在設計適配器的時候格外注意。

到此,相信大家對“json框架的特點有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

云梦县| 永州市| 九寨沟县| 达日县| 武功县| 靖边县| 长汀县| 永和县| 日喀则市| 石渠县| 大同县| 汉源县| 贵阳市| 庆阳市| 图们市| 绥芬河市| 遂溪县| 潞西市| 兴海县| 高尔夫| 无极县| 正蓝旗| 呼图壁县| 黄龙县| 石屏县| 鲁山县| 海伦市| 台东市| 白水县| 龙南县| 裕民县| 桃江县| 孝义市| 宝丰县| 阿拉尔市| 诸城市| 呼图壁县| 寻乌县| 景洪市| 肃北| 永和县|