简短版本:我正在尝试从gradle任务中调用jpackage,但ToolProvider返回null(或者最好是失败的Optional)。在AdoptOpenJDK 14.0.0(sdkman标识符14.0.0.hs-adpt)以及Java.net(我认为是Oracle OpenJDK !?)14.0.1(sdkman标识符14.0.1-open)中就是这种情况。我正在使用Gradle 6.3(但这并不像gradle的问题)。
较长版本:我遵循此talk on jpackage,其中在12:12处显示从构建工具调用jpackage的代码。 (official jpackage page还提到:除了命令行界面,还可以通过ToolProvider API(java.util.spi.ToolProvider)以名称“jpackage”访问jpackage。)
还是我的(Kotlin)代码(位于buildSrc / src / main / kotlin中)
object JPackage {
fun buildInstaller(
...
): Int {
val jpackageTool: ToolProvider = ToolProvider.findFirst("jpackage").orElseThrow {
val javaVersion: String = System.getProperty("java.version")
IllegalStateException(
"jpackage not found (expected JDK version: 14 or above, detected: $javaVersion)"
)
}
val arguments: Array<String> = ...
return jpackageTool.run(System.out, System.err, *arguments)
}
}
由新的Gradle任务调用
tasks {
register("buildInstaller") {
JPackage.buildInstaller(
...
)
dependsOn("build")
}
}
未能说明
> Could not create task ':buildInstaller'.
> jpackage not found (expected JDK version: 14 or above, detected: 14.0.1)
我应该补充一点,我从命令行调用jpackage没有任何问题。
更新:我已验证这与Kotlin或Gradle无关。这个基本的Java-14程序会产生相同的异常:
public class Main {
public static void main(String[] args) {
java.util.spi.ToolProvider.findFirst("jpackage").orElseThrow(() -> {
String javaVersion = System.getProperty("java.version");
return new IllegalStateException("jpackage not found (expected JDK version: 14 or above, detected: " + javaVersion + ")");
});
System.out.println("success");
}
}
解决方案:(包含Slaw的答案)
由于jpackage正在“孵化”中,因此对于我的非模块化应用程序来说不易使用,因此我决定通过创建一个新过程来调用它:
object JPackage {
fun buildInstaller(
...
): Int {
val arguments: Array<String> = ...
return execJpackageViaRuntime(arguments)
}
private fun execJpackageViaRuntime(arguments: Array<String>): Int {
val cmdAndArgs = ArrayList<String>(arguments.size+1).let {
it.add("jpackage")
it.addAll(arguments)
it.toTypedArray()
}
return try {
val process: Process = Runtime.getRuntime().exec(cmdAndArgs)
process.waitFor(3L, TimeUnit.MINUTES)
return process.exitValue()
} catch (e: Exception) {
1
}
}
}
我的任务定义如下:
tasks {
register("buildInstaller") {
dependsOn("build")
doLast {
if (JavaVersion.current() < JavaVersion.VERSION_14) {
throw GradleException("Require Java 14+ to run 'jpackage' (currently ${JavaVersion.current()})")
}
JPackage.buildInstaller(
...
)
}
}
}
我无法从IntelliJ内部执行任务,因为它似乎是 bundle 了JDK11来调用Gradle的,但是至少IntelliJ可以编译构建脚本本身(因为版本检查位于doLast块中,而不是直接在寄存器块)。或者,您可以更改IntelliJ用来调用Gradle的JDK,向下滚动到Slaw在他的回答下的注释以了解操作方法。
顺便说一句:我很确定 Gradle版本6.3 是实现此要求的硬性要求,因为它是第一个兼容Java 14的Gradle版本。
最佳答案
问题与JEP 11: Incubator Modules有关。 JEP声明:
在Java 14中,可能在以后的几个发行版中,jpackage工具包含在名为 jdk.incubator.jpackage
的模块中。从名称的前缀,我们可以看到该模块是一个孵化器模块。相同的JEP后来指出:
由于孵化器模块不参与服务绑定(bind),因此无法在运行时解析jdk.incubator.jpackage
模块。不幸的是,这意味着无法通过ToolProvider
找到该工具,除非您执行以下操作之一:
--add-modules jdk.incubator.jpackage
和requires jdk.incubator.jpackage;
指令。 由于您尝试从Gradle任务中调用jpackage,因此我认为选项二是不可行的。但是,第一种选择似乎确实可行。执行Gradle时,您可以指定适当的
org.gradle.jvmargs
系统属性。例如:./gradlew "-Dorg.gradle.jvmargs=--add-modules=jdk.incubator.jpackage" buildInstaller
您不必每次都在命令行中键入它。 checkout this Gradle documentation,看看您还能在哪里定义该系统属性。虽然不确定,但也可以通过您的IDE进行某些操作。也就是说,也可以使用
jpackage
任务将Exec
作为另一个进程来调用。例如:tasks {
val build by existing
register<Exec>("buildInstaller") {
if (JavaVersion.current() < JavaVersion.VERSION_14) {
throw GradleException("Require Java 14+ to run 'jpackage'")
}
dependsOn(build)
executable = "jpackage"
args(/* your args */)
}
}
关于java - 通过ToolProvider无法找到jpackage,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61307077/