在今年的敏捷團隊建設中,我通過Suite執行器實現了一鍵自動化單元測試。Juint除了Suite執行器還有哪些執行器呢?由此我的Runner探索之旅開始了!
筆者
近日在做代碼倉庫的存量代碼縮減工作,首先考慮的是基於靜態掃描的縮減,嘗試使用了很多工具來對代碼進行優化,例如PMD、IDEA自帶的inspect功能、findBugs等。
但是無一例外,要麼過於“保守”,只給出掃描結果,但是無法實現一鍵優化,要麼直接就是有bug(這裏特指IDEA2023.1.5專業版-inspect功能掃描problems清單裏的unused declaration)。
對於懶人而言,挨個手動點擊幾百次按鈕和坐牢無異,遂自己寫了一個工具對大部分已明確的優化點進行一鍵修改(具體是使用lombok的@Data註解替換顯式的getter/setter以及toString方法)。
本文內容主要分爲三個部分,第一部分詳細講述工具實現的思路,第二部分會對用到的開源工具javaParser進行簡要的介紹,第三部分提供了工具細緻的使用說明。
實現思路
理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。
在翻閱歷史代碼時,發現不少工程倉庫裏很多類依然是用的IDE生成的getter/setter,如果使用Lombok的@Data註解替換,可以帶來幾個優點。
-
顯而易見的是,能夠使代碼變得更加整潔,減少代碼量,並且減少今後新增字段時帶來的重複勞動。
-
可讀性得到了提高,在其他同事參與開發時無需檢查getter/setter裏是否做了邏輯。
-
避免遺漏,減少犯錯的風險,之前因爲其他同事的接口數據漏寫get方法,徒增了不少的溝通成本。
回過頭來看,如果我們要寫一個工具,對整個代碼工程所有類進行全量掃描,並且使用lombok來替換其中的“沒有特殊邏輯”的getter和setter,需要哪些步驟。
1.掃描整個工程代碼,可以是多模塊的工程。
2.讀取其中的“.java”文件。
3.過濾其中不需要的類,例如interface,沒有field的類(大概率是作爲service出現),註解的聲明等等。
4.刪除getter/setter方法,這裏需要判斷在get和set方法裏是否有特殊邏輯。
5.給類打上@Data註解,並且把lombok包引入進來。
工程掃描比較簡單,給一個工程路徑,然後遞歸調用,過濾出所有的.java文件即可。
private static List<File> scanJavaFiles(File file) {
List<File> result = Lists.newArrayList();
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files == null) {
return result;
}
for (File f : files) {
result.addAll(scanJavaFiles(f));
}
}
if (file.getName().endsWith(".java")) {
result.add(file);
}
return result;
}
使用註解替換getter/setter
1.過濾掉無字段的類。
2.過濾掉已經使用lombok註解的類。
3.判斷是否有顯式getter/setter(這裏需要注意,boolean類型的字段需要特殊處理)
4.判斷getter/setter是否爲簡單的返回和賦值操作。
5.刪除getter/setter。
6.添加@Data註解。
這裏使用github上開源的工具javaParser來對類進行解析、代碼提取、刪除以及內容新增,javaParser會在下一章節進行介紹。
這裏簡單粗暴了一些,直接使用equals判斷方法體,其實javaParser提供了更完善的api來分析語義。
在完成對代碼的清理之後,需要將內容更新到java文件,CompilationUnit重寫了toString方法,可以支持直接將代碼轉換成字符串的形式。
JavaParse介紹
理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。
JavaParser是什麼?
JavaParser 是一個開源的 Java 源代碼分析工具,它提供了一系列簡單的API來解析、修改和生成 Java 代碼。
舉個例子,我們可以使用javaparser輕鬆的實現下面幾個操作:
1.分析代碼中的類、方法、字段等元素,提取類的繼承關係、方法的參數和返回類型等。
2.更改源碼,例如重命名方法、修改方法體、添加或刪除代碼行等。
3.可以使用它來生成代碼片段,例如創建新的類、方法或字段,或者生成代碼文檔。
在上一章節裏就用到了數據提取,源碼替換功能。這裏附上JavaParser的相關鏈接:
官網:https://javaparser.org/ github:https://github.com/javaparser/javaparser wiki:https://github.com/javaparser/javaparser.wiki.git javadoc:https://www.javadoc.io/doc/com.github.javaparser/javaparser-core/latest/index.html
JavaParser 的主要構成由以下幾個組件組成:
1.Lexer(詞法分析器):詞法分析器的作用是讀取源代碼文本,並將其分解成一系列的詞法單元(tokens),如關鍵字、標識符、字面量、運算符等。這是解析過程的第一步。
通常不需要咱們顯式調用,JavaParser將具體的細節實現隱藏在內部,調用方只需要使用開放api即可完成源碼到AST的轉換。具體可以翻閱com.github.javaparser.GeneratedJavaParser
2. Parser(語法解析器):語法分析器接收詞法分析器生成的tokens,並根據Java語言的語法規則將它們組合成各種語法結構,如表達式、語句、類定義等。這個過程構建出一個抽象語法樹(AST)。
com.github.javaparser.JavaParser 這是最常用的類,用於觸發解析過程並生成AST,在上一章節中,使用StaticJavaParser將源文件解析成CompilationUnit,在parse方法的內部使用了JavaParser完成這一解析過程。
3. AST(抽象語法樹):AST 是 JavaParser 的核心數據結構,它以層次化的方式表示了源代碼的結構。AST 由一系列的節點組成,每個節點表示源代碼中的一個元素,如類、方法、字段、表達式等。每個節點都包含有關該元素的信息,例如名稱、類型、修飾符等。
AST是後續操作(如遍歷、分析、修改)的基礎,也是使用方操作最頻繁的類。上一章節使用的com.github.javaparser.ast.CompilationUnit是一個非常重要的類,它代表了Java源代碼文件的根節點,是這個結構的抽象表示,包含整個文件的結構,例如:
通過操作CompilationUnit提供的公有方法,可以訪問和修改文件中的元素。包括:
獲取和設置包聲明
獲取和添加導入聲明
獲取和添加類型聲明
獲取和添加註釋
使用訪問者模式來遍歷AST中的節點
4. Visitors(訪問器):顧名思義,這是一個採用訪問者模式設計的組件,可以用於遍歷和操作 AST 。開發者可以編寫自定義的 Visitors,通過遍歷 AST 來訪問特定類型的節點,執行代碼分析、重構、生成等任務。
com.github.javaparser.ast.visitor.GenericVisitor和com.github.javaparser.ast.visitor.VoidVisitor這兩個訪問器提供了默認實現,如果需要自定義訪問器,可以繼承它們來實現自己的業務邏輯。
5. Printer(打印器):這個也很好理解,Printer 用於將 AST 轉換回 Java 源代碼的字符串表示形式。它可以將修改後的 AST 打印回原始源代碼文件,或將 AST 打印爲格式化的代碼字符串。在上一章節的最後提到的CompilationUnit重寫的toString方法,實際上就是使用了Printer來完成AST到源碼字符串的轉換。
上面的一些組件是javaParser中比較核心且常用的部分,當然javaParser還提供了一些便捷的工具類以及用法,這些內容筆者也沒有接觸過,有需要的讀者可以自行翻閱文檔。
工具使用方式
理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。
第一章提到的jar包和源碼均已上傳私服,可以直接通過maven插件的方式運行。
<dependency>
<groupId>com.jd.omni.opdd</groupId>
<artifactId>lombok-replace</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
添加maven插件
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.jd.omni.opdd.tools.lombok.LombokConverter</mainClass>
<arguments>
<argument>../../pop-jingme-customs</argument>
</arguments>
</configuration>
</plugin>
插件中的argument節點需要替換成工程的路徑,可以是絕對路徑也可以是相對路徑
執行 mvn exec:java
可以在控制檯看到:
使用工具處理完成後,一定要build的一下檢查是否有編譯錯誤,雖然在刪除操作時做了較爲嚴苛的校驗,但是有些特殊的變量名可能沒有考慮到,這部分問題是可以通過編譯檢查出來的。
另外,對於沒有引用lombok的模塊,需要手動添加依賴。
寫在最後
理解,首先 MCube 會依據模板緩存狀態判斷是否需要網絡獲取最新模板,當獲取到模板後進行模板加載,加載階段會將產物轉換爲視圖樹的結構,轉換完成後將通過表達式引擎解析表達式並取得正確的值,通過事件解析引擎解析用戶自定義事件並完成事件的綁定,完成解析賦值以及事件綁定後進行視圖的渲染,最終將目標頁面展示到屏幕。
代碼重構應該像手術刀一樣,快、準、狠,正所謂君子生非異也,善假於物也。本文主要起一個拋磚引玉的作用,重點在於JavaParser的介紹,筆者寫的這個小工具非常簡單,之前也寫過B-PaaS一鍵生成matrix.json,一鍵根據錯誤碼定義生成i18n文件,大都不難。