背景
一切還要從我的上一家公司講起,我的上一家公司是一家獨角獸企業,説大不大説小不小的那種,公司氛圍也是比較注重技術,我當時入職之後的第一課就是閲讀我們 CTO 寫的開發規範,其中他把 Java 項目的目錄結構劃分的非常清楚,大概是下面這個樣子的:
我當時覺得這種分層結構劃分的非常優雅與合理,當然以上只是一個大概,更細節的分層我沒有表露,但是隨之而來在實際中使用的過程中,這樣一個三層結構也帶來了一個問題,那就是對象傳輸非常麻煩,因為每層都會有一個特有的對象。
下面我舉一個例子,假如我們要插入一個 User 對象,那麼它可能要經過以下二次對象轉換:
以上只是一個比較簡單的例子,相信大家已經可以從中看出開發者們需要寫一些很繁瑣但是很沒意思的代碼(手動 get/set),比如上圖中的三個對象可能字段都是一模一樣的,但卻需要重複寫兩次 Convert 去進行對象的轉換。
當然這樣設計當然也有好處,那就是解耦,比如我們現在用的數據庫是 Mysql,如果要換成 Mongo 只需要把第二次對象轉換的代碼稍微修改一下即可,這也是這樣設計的初衷。
常見方案
這麼一個繁瑣的事難道就沒有一些方案進行解決嗎?當然有,一般來説有兩種方式:
- BeanUtil / JSONObject
- MapStruct
先來説第一種方式吧,無論 BeanUtil 是深拷貝還是淺拷貝,它對我們開發者來説細節都是不可見的,一旦某個字段賦值出現了問題,我們並沒有辦法去進行代碼的排查,因為我們沒辦法查看對象轉換的細節,JSONObject 也有相同的問題。
然後就是第二種方式,MapStruct 在前段時間是一個非常火的方案,它和 Lombok 非常類似,在代碼編譯期幫助我們去生成對象之間的轉換代碼,我們也可以通過 IDEA 的提示去查看編譯後的代碼,我司除了手動 get/set 代碼,最多的就是使用 MapStruct 進行處理。
但是對我而言,MapStruct 還是有一些缺點,首先我的 IDEA 經常沒有查看編譯後代碼的提示,其次就是如果轉換對象的某個字段不一樣的時候,需要學習 MapStruct 的一些用法進行處理,有一定的學習負擔,反正我到現在都沒學會😂。
我的方案
最終我為了方便,決定自己開發一個 IDEA 插件並起名為 BeanMappingKey,目前已經迭代到 1.X 版本,主要思想是通過插件的方式為我們需要轉換的對象自動生成轉換代碼。
目前暫時有三種用法:
- 根據對象生成對應的 get/set 方法,支持建造者模式。
- 根據 Class 生成對應的 get/set 方法,支持建造者模式。
- 根據一個方法的入參和返回值,進行對象的轉換代碼生成,支持建造者模式。
其中,第一種和第二種生成起來是差不多的,具體可見以下例子:
上圖的示例,是我們選中一個 Class 類進行代碼的生成,根據這個類是否是建造者模式,來生成對應風格的代碼,生成之後的代碼被拷貝到剪貼板上,可以自由粘貼。
第二種方式,對於我來説是更加常用的,因為轉換代碼往往是寫在一個方法裏面的,通過選中方法名匹配入參和返回值進行代碼生成,類似下面的例子:
匹配的邏輯就是根據字段名進行匹配,匹配失敗的話則會留空,同時不只支持一個入參,可以對多個入參進行匹配,就像下面這樣:
以上就是我對這個插件的介紹了,各位讀者如果有興趣的話可以在IDEA上面下載上試試:
-
在
Windows系統上安裝:File>Settings>Plugins>Browse repositories...>Search for "BeanMappingKey">Install Plugin
-
在
MacOS系統上安裝:Preferences>Settings>Plugins>Browse repositories...>Search for "BeanMappingKey">Install Plugin
-
手動安裝:- 下載 latest release 之後, 選擇
Preferences>Plugins>Install plugin from disk...
- 下載 latest release 之後, 選擇
注:暫且只支持 2020 以上版本的 IDEA,安裝之後無需重啓。
目前我的這個插件依然還在完善中,對於複雜類型支持的還不夠完善,比如對象裏面嵌套對象的情況,我打算下一階段繼續對這塊痛點進行升級完善,下面是此插件的地址:
- Github:https://github.com/rookie-ricardo/BeanMappingKey
- Plugin:https://plugins.jetbrains.com/plugin/18264-beanmappingkey
2022-06-06更新:插件更新 2.0 版本,已經支持對象嵌套的生成,歡迎大家在IDEA中下載使用。