如何橋接優化Java方法返回型別實現相容性? - Gunnar
假設我們有一個 Java 庫,它提供了一個公共類和方法,如下所示:
public class SomeService { public Number getSomeNumber() { return 42L; } } |
但過了一段時間,人們開始抱怨:Number他們寧願使用更具體的返回型別而不是通用的返回型別,我們同意最初的 API 定義並不理想,我們改變了方法定義,現在返回Long。
但是在我們釋出了具有該更改的庫的 2.0 版本後不久,使用者報告了一個新問題:升級到新版本後,他們在執行應用程式時突然出現以下錯誤:
java.lang.NoSuchMethodError: 'java.lang.Number dev.morling.demos.bridgemethods.SomeService.getSomeNumber()' at dev.morling.demos.bridgemethods.SomeClientTest.shouldReturn42(SomeClientTest.java:27) |
當將方法返回型別從更改Number為Long時,我們做了一個破壞我們庫的二進位制相容性的更改。JVM 正在尋找SomeService::getSomeNumber()返回的方法Number,但在我們服務的 2.0 版本的類檔案中找不到它。
它還解釋了為什麼不是所有使用者都報告了這個問題:那些在升級到 2.0 時重新編譯自己的應用程式的人不會遇到任何問題,因為編譯器只會使用新版本的方法並將該簽名的呼叫放入任何呼叫者的類檔案。只有那些沒有重新編譯程式碼的使用者才會遇到問題,即更改實際上是原始碼相容的。
有一個工具正是用於此目的: Bridger
Bridger 允許您建立自己的橋接方法,使用 ASM 應用將方法轉換為橋接方法所需的類檔案轉換。它帶有一個 Maven 外掛,用於將此轉換步驟整合到您的構建過程中。下面是我們需要的外掛配置:
<plugin> <groupId>org.jboss.bridger</groupId> <artifactId>bridger</artifactId> <version>1.5.Final</version> <executions> <execution> <id>weave</id> <phase>process-classes</phase> <goals> <goal>transform</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.2</version> </dependency> </dependencies> </plugin> |
- <phase>process-classes</phase> :將transform目標繫結到process-classes構建生命週期階段,以便修改Java編譯器生成的類
- 使用最新版本的 ASM,所以我們可以使用 Java 17
有了外掛,你可以像這樣定義橋接方法,使用$$bridge名稱字尾:
public class SomeService { /** * @hidden */ public Number getSomeNumber$$bridge() { return getSomeNumber(); } public Long getSomeNumber() { return 42L; } } |
- 通過@hiddenJavaDoc 標記(在 Java 9 中新增),此方法將從為我們的庫生成的 JavaDoc 中排除
- public Number getSomeNumber$$bridge() 橋接方法;名稱字尾Bridger 將被刪除,即它會被命名getSomeNumber;它還將具有ACC_BRIDGE和ACC_SYNTHETIC修飾符
利用橋接方法,我們可以糾正 1.0 版 API 中的故障,並在我們庫的新版本中改進方法返回型別,而不會破壞原始碼或與現有使用者的二進位制相容性。
通過@hiddenJavaDoc標籤,我們的bridge方法的原始碼不會出現在渲染文件中(這會比較混亂),並且在類檔案中標記為合成橋方法,它也不會出現在在 IDE 中檢視 JAR。
如果您想開始自己探索 Java 橋接方法,可以在此GitHub 儲存庫中找到示例的完整原始碼。用於跟蹤 API 更改和識別任何潛在破壞性更改的有用工具包括SigTest (例如,我們在 Bean 驗證規範中使用此工具以確保向後相容性)和Revapi (我們在 Debezium 中使用)。
其他橋架專案:
- bridge-method-injector by Koshuke
- OverloadReturn by Jake Wharton
相關文章
- Java模組化的國際化實現- GunnarJava
- java 橋接模式實現程式碼Java橋接模式
- [譯] Java 橋接方法詳解Java橋接
- 橋接模式(c++實現)橋接模式C++
- 3分鐘快速搞懂Java的橋接方法Java橋接
- 搞懂Java橋接模式,打破繼承侷限性,輕鬆實現多維變化Java橋接模式繼承
- 橋接模式:探索JDBC底層實現橋接模式JDBC
- java統一返回標準型別Java型別
- java中介面多個實現類,如何指定實現類,根據子類型別選擇實現方法Java型別
- Java設計模式-橋接模式Java設計模式橋接
- Java實現子類返回型別不一樣也能重寫(特殊情況)Java型別
- 【橋接設計模式詳解】Java/JS/Go/Python/TS不同語言實現橋接設計模式JavaJSGoPython
- 橋接橋接
- PHP通往JAVA的橋接器使用PHPJava橋接
- Java設計模式(7)----------橋接模式Java設計模式橋接
- 什麼是Java多型?如何實現Java多型?Java多型
- 設計模式學習-使用go實現橋接模式設計模式Go橋接
- Spring雜談 | 從橋接方法到JVM方法呼叫Spring橋接JVM
- Java設計模式之(六)——橋接模式Java設計模式橋接
- Android SDK使用了JS橋接方法實現與H5互動 混淆問題AndroidJS橋接H5
- 小白都能懂的設計模式 java版 橋接模式具體實現(超詳細)設計模式Java橋接
- 深入理解 Java 的整型型別:如何實現 2+2=5?Java型別
- 如何實現隱式型別轉換型別
- SpringMVC-方法四種型別返回值總結SpringMVC型別
- 更強大的 MQTT over QUIC 橋接 & Azure 橋接MQQTUI橋接
- 【數字化】如何通過數字化轉型實現生產製造的優化?優化
- 返回hash 型別的json型別JSON
- 2.2 橋接 Bridge橋接
- std::packaged_task<返回型別(引數型別)>Package型別
- java基本型別和包裝型別的“==”和equals()方法Java型別
- 軟體相容性測試包含哪幾種型別?相容性測試如何收費?型別
- 多型中的返回值型別多型型別
- 如何處理http返回型別為206的資料HTTP型別
- 設計模式:橋接模式及程式碼示例、橋接模式在jdbc中的體現、注意事項設計模式橋接JDBC
- 08_橋接模式橋接模式
- 如何更好的使用OPcache實現效能優化opcache優化
- 原始碼 | 靜態工廠返回宣告的返回型別的子型別的例項原始碼型別
- Java的型別化狀態機Java型別