一招教你在Gradle中为JPMS构建Java 6-8库

这篇文章主要针对Java库维护者。 任何这样的维护者都必须选择要定位的JDK:

l 针对最新的JDK(JDK 11或新发布的JDK 12),可为开发人员和用户提供最新API和更多功能的访问。

l 但是,它会阻止旧版JDK上的用户使用该库。

而那些较旧的JDK仍然非常受欢迎,在2018年占据约95%的份额,预计在2019年占据约90%。特别是JDK 8(> 80%份额)的普及使其成为现在的事实上的标准。

因此,后者正是许多图书馆维护者的决定性因素。 例如,vavr 1.0旨在以JDK 11为目标,但最终将以JDK 8为目标。

尽管如此,建议为JPMS添加一些支持,希望它将来能够被广泛采用。 Stephen Colebourne在这里描述了三个选项:

1. 什么都不做(不推荐)。

2. 最小值:在MANIFEST.MF文件中添加自动模块名称条目。

3. 最佳:添加针对JDK 9+的module-info.class,同时提供针对JDK 6-8 *的所有剩余类。

下面我们将深入研究如何实现选项三

注:我写的是关于JDK 6-8(而不是例如JDK 5-8),因为在JDK 11中,javac的--release选项限制在6-11范围内。

no1

为什么会选择JPMS呢? 主要是因为JPMS的以下三点特征:

1. 提供强大的封装

2. 防止引入拆分包

3. 确保更快的类加载

总而言之,JPMS非常酷,所以,我鼓励Java 6-8库的维护者充分利用JPMS:

l 对于他们自己,通过针对其模块的JDK 6-8类和其他模块编译module-info.java

l 对于他们的用户,通过提供module-info.class使库在模块路径上运行良好

no2

module-info.java的位置

module-info.java有两个位置:

1. 与所有其他类一样,在src / main / java中

2. 在单独的“源集”中,例如 在src / main / java9中。

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

module-info.class的位置

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

1.在根输出目录中,包含所有其他类

2.在META-INF / versions / 9(Multi-Release JAR,AKA MRJAR)

no3

构建工具的示例库

本节包含一些库,这些库在定位JDK 6-8时提供module-info.class。

Ant

· Lombok (JDK 6 main + JDK 9 module-info.class)

Maven

· ThreeTen-extra (JDK 8 main + JDK 9 module-info.class)

· ·GoogleGson - 尚未发布(JDK 6 main + JDK 9 module-info.class)

· SLF4J - 尚未发布(META-INF / versions / 9中的JDK 6 main + JDK 9 module-info.class)

需注意的是,Maven Compiler Plugin提供了如何提供此类支持的示例。

Gradle

我没有找到任何使用Gradle提供此类支持的流行库(如果您知道,请发表评论)。 我只知道vavr尝试这样做

Gradle中的现有方法

ModiTect:ModiTect(由Gunnar Morling制作)及其Gradle插件(Serban Iordache)有一些非常酷的功能。 实质上,ModiTect在不使用javac的情况下生成module-info.class,基于特殊符号或直接来自module-info.java。

但是,在从module-info.java直接生成的情况下,ModiTect有效地复制了javac在引入自己的问题时所做的事情

这就是为什么我觉得这不是最好的工具。

Badass Jar插件:Serban Iordache还创建了一个Gradle插件,可以“无缝地创建模块化的jar,它们定位于9之前的Java版本”。

但是看起来很不错:

为了构建适当的JAR并验证module-info.java,Gradle构建必须运行两次,它不使用javac的--release选项,它保证只引用正确的API;它不使用javac来编译module-info.java。

JpmsGradlePlugin

这是我最近的发现:Axel Howind的JpmsGradlePlugin。

该插件做了一些不错的事情(例如,从javadoc任务中排除module-info.java),其特征如下:

l 它也不使用javac的--release选项,

l 它不完全支持Java模块化(例如模块修补),

l 它感觉不够成熟(代码难以理解,非标准行为,如直接调用javac)。

Gradle中提出的方法

Gradle脚本

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

结果,我想出了以下方法:

1.将compileJava配置为:excludemodule-info.java,

使用--release 6/7/8选项。

2.添加名为compileModuleInfoJava的新JavaCompile任务,并将其配置为:

仅包含module-info.java,

使用--release 9选项,

使用compileJava的类路径作为--module-path *,

使用compileJava *的目标目录

取决于oncompileJava *。

1.配置要依赖于compileModuleInfoJava的类任务。

这三个步骤是compileModuleInfoJava查看compileJava编译的类所必需的。 否则,由于未解析的引用,javac将无法编译module-info.java。 请注意,在这样的配置中,每个类只编译一次(与推荐的Maven编译器插件配置不同)。

Gradle Modules插件

(Gradle Modules Plugin)为Gradle添加了对JPMS的全面支持。

在这篇文章中,我展示了如何使用Gradle构建Java 6-8库,以便将module-info.java编译为JDK 9格式(JPMS支持),而所有其他类都编译为JDK 6-8格式。

我还建议使用Gradle Modules Plugin进行此类配置(只要我的PR合并并且新的插件版本被释放)。

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();