使用 gradle 依赖于 Java 9 Module System 库中的遗留 jar

问题描述

问题

你如何创建一个 Java 库 jar:

  • 是java模块(有module-info
  • 一个依赖的遗留(非模块)jar。 (比如commons-exec)?

依赖项是一个实现细节 - 不应导出。

来源

具有以下 build.gradle(使用 gradle-6.8):

plugins {
    id 'java-library'
}

group = 'test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '15'

repositories {
    mavenCentral()
}
java {
    modularity.inferModulePath = true
}

dependencies {
    implementation 'org.apache.commons:commons-exec:1.3'
}

以及以下 module-info.java

module test.module {
    requires commons.exec;
}

错误

我收到以下编译错误

module-info.java:2: error: module not found: commons.exec
    requires commons.exec;
                    ^

如果我不包括 requires commons.exec 那么错误会变成:

error: package org.apache.commons.exec is not visible
import org.apache.commons.exec.CommandLine;
                         ^
  (package org.apache.commons.exec is declared in the unnamed module,but module test.module does not read it)

commons.exec 模块名称

运行 jar --file=commons-exec-1.3.jar --describe-module 输出

No module descriptor found. Derived automatic module.

commons.exec@1.3 automatic
requires java.base mandated
contains org.apache.commons.exec
contains org.apache.commons.exec.environment
contains org.apache.commons.exec.launcher
contains org.apache.commons.exec.util

所以 commons.exec 看起来像是 commons-exec-1.3.jar 的有效模块名称。 Intelij Idea 似乎同意并在 module-info.java自动完成它。尽管它在构建时失败了。

解决方法

我使用 java-module-info 插件设法解决了同样的问题。

此插件允许您将模块信息添加到 Java 库中 那没有。如果你这样做,你可以给它一个适当的 模块名称,Gradle 可以捡起来放到模块路径上 在编译、测试和执行期间。

plugins {
   id 'java-library'
   id("de.jjohannes.extra-java-module-info") version "0.6"
}

将此部分添加到您的 build.gradle 中以添加 commons-exec 模块信息

  extraJavaModuleInfo {
    module("commons-exec-1.3.jar","org.apache.commons.exec","1.3") {
        exports("org.apache.commons.exec")
    }
}

requires org.apache.commons.exec; 添加到您的 module-info.java

编辑 1

Gradle 7.0 完全支持 Java 模块系统。用户现在可以通过 Gradle build,test,and run Java 模块。仅仅存在 module-info.java 就会让 Gradle 推断您的 jar 是一个模块,并且必须放在模块路径而不是传统的类路径中。

Using libraries that are not modules