如何橋接優化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++
- java中相同名字不同返回型別的方法Java型別
- 3分鐘快速搞懂Java的橋接方法Java橋接
- 搞懂Java橋接模式,打破繼承侷限性,輕鬆實現多維變化Java橋接模式繼承
- 橋接模式:探索JDBC底層實現橋接模式JDBC
- PHP實現強型別函式返回值PHP型別函式
- java統一返回標準型別Java型別
- java中介面多個實現類,如何指定實現類,根據子類型別選擇實現方法Java型別
- Java設計模式-橋接模式Java設計模式橋接
- 自定義函式實現字串分割,返回集合型別函式字串型別
- 橋接橋接
- Java實現子類返回型別不一樣也能重寫(特殊情況)Java型別
- Java設計模式(7)----------橋接模式Java設計模式橋接
- PHP通往JAVA的橋接器使用PHPJava橋接
- [OOD] 隔離變化-橋接模式橋接模式
- 設計模式學習-使用go實現橋接模式設計模式Go橋接
- 什麼是Java多型?如何實現Java多型?Java多型
- 橋接模式橋接模式
- 【橋接設計模式詳解】Java/JS/Go/Python/TS不同語言實現橋接設計模式JavaJSGoPython
- 對於返回值型別不確定的函式如何限定返回值型別型別函式
- java效能優化方案5——使用原始型別和棧Java優化型別
- Java設計模式之(六)——橋接模式Java設計模式橋接
- java設計模式之一 橋接模式Java設計模式橋接
- 小白都能懂的設計模式 java版 橋接模式具體實現(超詳細)設計模式Java橋接
- 設計模式--橋接模式Bridge(結構型)設計模式橋接
- 如何實現隱式型別轉換型別
- 更強大的 MQTT over QUIC 橋接 & Azure 橋接MQQTUI橋接
- 深入理解 Java 的整型型別:如何實現 2+2=5?Java型別
- Spring雜談 | 從橋接方法到JVM方法呼叫Spring橋接JVM
- __bridge - 橋接橋接
- JS 橋接模式JS橋接模式
- vmware橋接不通橋接
- Android SDK使用了JS橋接方法實現與H5互動 混淆問題AndroidJS橋接H5
- 【數字化】如何通過數字化轉型實現生產製造的優化?優化