在Gradle中为JPMS构建Java 6-8库
通過提供Java 9 module-info.class來了解如何使用Gradle構建支持JPMS( Java平臺模塊系統 )的Java 6-8庫。
介紹
如果您需要JPMS本身的介紹,請查看此概述 。
這篇文章主要針對Java庫維護者。
任何此類維護者都必須選擇要針對的JDK:
- 針對最新的JDK( JDK 11或剛剛發布的JDK 12 ),開發人員和用戶可以使用新的API和更多功能。
- 但是,這會阻止所有使用較舊JDK的用戶使用該庫。
- 那些較老的JDK仍然很受歡迎, 在2018年約占95%的份額 ,并預計在2019年將約90%的 份額 。
因此,對于許多圖書館維護者而言,后者無疑是一個決定性因素 。 例如, vavr 1.0 旨在以JDK 11為目標 ,但最終將以JDK 8為目標 。
盡管如此,還是建議為JPMS添加一些支持,以期將來會被廣泛采用(我想從現在起5年以上)。 Stephen Colebourne在這里描述了三個選項:
在這里,我們將深入研究如何實現選項3(最佳選擇)。
*我寫的是JDK 6-8(而不是JDK 5-8),因為在JDK 11中, javac的--release選項限制為6-11。
理由
不過,在深入研究“如何”之前,讓我們先略過“為什么”。
為什么JPMS完全值得打擾? 主要是因為JPMS:
- 提供強大的封裝 ,
- 防止引入拆分包 ,
- 確保更快的類加載 。
綜上所述,JPMS 非常酷 (更多信息請參見此處 ),鼓勵我們采用JPMS是我們的最大利益!
因此,我鼓勵Java 6-8庫的維護者充分利用JPMS:
- 自己針對模塊的JDK 6-8類和其他模塊編譯module-info.java ,
- 對于他們的用戶,通過提供module-info.class來使庫在module-path上正常工作。
可能的行為
可以在兩個位置找到module-info.java :
我喜歡選項1,因為它看起來更自然。
module-info.class可以在兩個地方結束:
閱讀了塞德里克·尚波( CédricChampeau)關于MRJAR的帖子后 ,我對MRJAR頗為懷疑,因此我更喜歡選項1。
但是請注意, Gunnar Morling報告說選項1存在一些問題。另一方面,我希望距JDK 9發行1.5年后,所有主要庫都已打補丁以正確處理module-info.class 。
每個構建工具的示例庫
本節包含一些在針對JDK 6-8時提供module-info.class的庫示例。
螞蟻
- Lombok (JDK 6 main + JDK 9 module-info.class )
馬文
- ThreeTen-extra (JDK 8 main + JDK 9 module-info.class )
- Google Gson –尚未發布(JDK 6 main + JDK 9 module-info.class )
- SLF4J –尚未發布( META-INF/versions/9 JDK 6 main + JDK 9 module-info.class )
請注意, Maven編譯器插件提供了如何提供這種支持的示例 。
搖籃
我還沒有找到任何流行的庫使用Gradle提供這種支持(請注釋,如果您知道的話)。 我只知道vavr試圖這樣做( #2230 )。
Gradle中的現有方法
修改
ModiTect (由Gunnar Morling編寫 )及其Gradle插件 (由Serban Iordache編寫 )具有一些非常酷的功能 。 本質上,ModiTect基于特殊符號或直接從module-info.java 生成 module-info.class -info.class, 而無需使用javac 。
但是,在從module-info.java直接生成的情況下,ModiTect有效地復制了javac所做的操作,同時引入了自己的問題(例如#90 )。 這就是為什么我覺得它不是最好的工具。
Badass Jar插件
Serban Iordache還創建了一個Gradle插件 ,該插件可以“無縫創建針對9之前的Java版本的模塊化jar”。
看起來不錯,但是:
- 為了構建適當的JAR并驗證module-info.java ,Gradle構建必須運行兩次,
- 它不使用javac的--release選項,該選項保證僅引用正確的API,
- 它不使用javac來編譯module-info.java 。
同樣,我覺得這里不是正確的工具。
JpmsGradlePlugin
這是我最近的發現: JpmsGradlePlugin由阿克塞爾Howind 。
該插件可以做一些不錯的事情(例如,從javadoc任務中排除module-info.java ),但是:
- 它也不使用javac的--release選項,
- 它不完全支持Java模塊化(例如,模塊修補),
- 感覺還不夠成熟( 難以遵循的代碼,非標準行為,例如直接調用javac )。
Gradle中的擬議方法
搖籃腳本
最初,我想通過添加自定義源集來做到這一點 。 但是,事實證明,這種方法會引入不必要的配置和任務 ,而我們真正需要的只是一個額外的任務,它正確地“鉤住”了構建生命周期 。
結果,我想到了以下幾點:
- 排除 module-info.java ,
- 使用--release 6/7/8選項。
- 僅包含 module-info.java ,
- 使用--release 9選項,
- 使用compileJava的類路徑作為--module-path * ,
- 使用compileJava *的目標目錄 ,
- 取決于 compileJava * 。
以上內容在Groovy DSL中表示為Gradle腳本,可以在我的Stack Overflow答案中找到。
*這三個步驟對于compileModuleInfoJava查看由compileJava編譯的類是compileJava 。 否則,由于未解析的引用, javac將無法編譯module-info.java 。 請注意,在這種配置中,每個類僅被編譯一次 (與推薦的Maven Compiler Plugin配置不同 )。
不幸的是,這樣的配置:
- 在存儲庫之間不容易重用,
- 不完全支持Java模塊化。
Gradle模塊插件
最后,有一個插件( Gradle Modules Plugin ),它為Gradle添加了對JPMS的完全支持(由Java 9 Modularity的作者Sander Mak和Paul Bekker創建 )。
該插件僅不支持本文所述的方案。 因此,我決定:
- 通過此插件提交功能請求: #72
- 提供具有#72的完整實現的“拉取請求”(作為“概念證明”): #73
我盡力做出這些高質量的貢獻。 最初的反饋意見非常受歡迎 (甚至Mark Reinhold都喜歡!)。 謝謝!
現在,我正在耐心地等待進一步的反饋 (以及潛在的改進要求),然后才能(希望)合并PR。
摘要
在本文中,我展示了如何使用Gradle構建Java 6-8庫,以便將module-info.java編譯為JDK 9格式(JPMS支持),而將所有其他類編譯為JDK 6-8格式。
我還建議對這種配置使用Gradle Modules插件 (一旦我的PR合并并且發布了新的插件版本)。
翻譯自: https://www.javacodegeeks.com/2019/03/building-java-6-8-libraries-jpms-gradle.html
總結
以上是生活随笔為你收集整理的在Gradle中为JPMS构建Java 6-8库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为特使建立控制平面的指南-部署权衡
- 下一篇: ddos会影响吞吐量吗(DDOS会影响吞