在Gradle中为JPMS构建Java 6-8库

通过提供Java 9 module-info.class来了解如何使用Gradle构建支持JPMS( Java平台模块系统 )的Java 6-8库。

介绍

如果您需要JPMS本身的介绍,请查看此概述

这篇文章主要针对Java库维护者。

任何此类维护者都必须选择要针对的JDK:

因此,对于许多图书馆维护者而言,后者无疑是一个决定性因素 。 例如, vavr 1.0 旨在以JDK 11为目标 ,但最终将以JDK 8为目标

尽管如此,还是建议为JPMS添加一些支持,以期将来会被广泛采用(我想从现在起5年以上)。 Stephen Colebourne在这里描述了三个选项:

  1. 不执行任何操作(不建议)。
  2. 最低要求:在MANIFEST.MF文件中添加一个“ Automatic-Module-Name条目。
  3. 最佳:添加一个针对JDK 9+的module-info.class同时提供所有其余针对JDK 6-8 *的类。

在这里,我们将深入研究如何实现选项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. 与其他所有类,在src/main/java
  2. 在单独的“源集”中,例如src/main/java9

我喜欢选项1,因为它看起来更自然。

module-info.class可以在两个地方结束:

  1. 在根输出目录以及所有其他类中,
  2. META-INF/versions/9 (多发行版JAR,又名MRJAR

阅读了塞德里克·尚波( 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中的拟议方法

摇篮脚本

最初,我想通过添加自定义源集来做到这一点 。 但是,事实证明,这种方法会引入不必要的配置任务 ,而我们真正需要的只是一个额外的任务,它正确地“钩住”了构建生命周期

结果,我想到了以下几点:

  1. compileJava配置为:
    • 排除 module-info.java
    • 使用--release 6/7/8选项。
  2. 添加一个名为compileModuleInfoJava的新JavaCompile任务,并将compileModuleInfoJava配置为:
    • 包含 module-info.java
    • 使用--release 9选项,
    • 使用compileJava类路径作为--module-path *
    • 使用compileJava *目标目录
    • 取决于 compileJava *
  3. 配置classes任务以依赖于compileModuleInfoJava

以上内容在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 MakPaul 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值