通过ToolProvider调用jpackage返回null的问题及解决
解决Java 14中ToolProvider无法找到jpackage的问题
问题场景
在AdoptOpenJDK 14.0.0(sdkman标识14.0.0.hs-adpt)或Oracle OpenJDK 14.0.1(sdkman标识14.0.1-open)环境下,使用Gradle 6.3尝试通过ToolProvider API调用jpackage时,ToolProvider.findFirst("jpackage")始终返回null,抛出IllegalStateException。但直接在命令行执行jpackage完全正常,不管是Kotlin编写的Gradle任务还是纯Java测试程序都会触发这个问题。
比如这段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任务执行后会提示:无法创建任务':buildInstaller',未找到jpackage(预期JDK版本14+,检测到14.0.1)
问题原因
Java 14中的jpackage处于孵化阶段,非模块化应用无法直接通过ToolProvider API获取到这个工具——这是当前API对孵化功能的限制导致的。
解决方案
改用Runtime创建进程的方式直接调用jpackage命令,具体实现如下:
1. 修改Kotlin工具类代码
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).apply { add("jpackage") addAll(arguments) }.toTypedArray() return try { val process: Process = Runtime.getRuntime().exec(cmdAndArgs) process.waitFor(3L, TimeUnit.MINUTES) process.exitValue() } catch (e: Exception) { 1 // 异常时返回错误码 } } }
2. 调整Gradle任务配置
确保任务逻辑放在doLast块中执行,并且先做Java版本校验:
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默认会使用自带的JDK 11来调用Gradle,这会导致任务执行失败,需要在IntelliJ的Gradle设置中修改为Java 14及以上版本的JDK。
- Gradle 6.3是兼容Java 14的最低版本,请确保你使用的Gradle版本符合要求。
内容的提问来源于stack exchange,提问作者StephanS
相关产品推荐
相关产品推荐

