short version: I'm trying to invoke jpackage from a gradle task but the ToolProvider returns null (or better a failed Optional). This is the case on AdoptOpenJDK 14.0.0 (sdkman identifier 14.0.0.hs-adpt) as well as on Java.net (i think that's Oracle OpenJDK!?) 14.0.1 (sdkman identifier 14.0.1-open). I'm using Gradle 6.3 (but this doesn't feel like a gradle issue).
long version: I'm following this talk on jpackage, where at 12:12 the code to invoke jpackage from a build tool is displayed. (The official jpackage page also mentions: In addition to the command-line interface, jpackage is accessible via the ToolProvider API (java.util.spi.ToolProvider) under the name "jpackage".)
And still my (Kotlin) code (lying in 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)
}
}
invoked by a new Gradle task
tasks {
register("buildInstaller") {
JPackage.buildInstaller(
...
)
dependsOn("build")
}
}
fails with stating
> Could not create task ':buildInstaller'.
> jpackage not found (expected JDK version: 14 or above, detected: 14.0.1)
I should add that I have no issues invoking jpackage from the command line.
UPDATE: I verified that this has nothing to do with either Kotlin or Gradle. This basic Java-14 program produces the same exception:
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");
}
}
Solution: (incorporating Slaw's answer) Since jpackage is in "incubating" and therefor not readily available for my non-modular application I decided to invoke it by creating a new process:
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
}
}
}
and my task definition looks like this:
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(
...
)
}
}
}
I can't execute the task from within IntelliJ since it seems to invoke Gradle with the JDK11 it itself comes bundled, but at least IntelliJ can compile the build script itself (since the version check is in the doLast-block and not directly in the register-block). Alternatively you can change the JDK that IntelliJ uses to invoke Gradle, scroll down to Slaw's comment under his answer to see how.
Btw: I'm pretty sure Gradle version 6.3 is a hard requirement for this to work, since it's the first Gradle version to be compatible with Java 14.