The Toolchains for JVM projects (gradle.org) documentation is clear on how to make a task Java-toolchain-aware for JavaLauncher
by using launcherFor
. Looking at the documentation of JavaToolchainService
I can also see you can get a JavaCompiler
via compilerFor
and a JavadocTool
via javadocToolFor
. That’s great if I want to directly use the java
, javac
, or javadoc
executables.
But say I want to execute a different tool, such as jlink
, jpackage
, or jmod
. One way I can think to implement this is like so:
import org.gradle.api.DefaultTask
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.TaskAction
import org.gradle.jvm.toolchain.JavaLauncher
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.getByType
import org.gradle.process.ExecOperations
import javax.inject.Inject
@Suppress("LeakingThis")
abstract class JLinkTask : DefaultTask() {
@get:Inject
protected abstract val execOps: ExecOperations
@get:Inject
protected abstract val javaToolchainService: JavaToolchainService
@get:Nested
abstract val launcher: Property<JavaLauncher>
init {
val toolchain = project.extensions.getByType(JavaPluginExtension::class).toolchain
val defaultLauncher = javaToolchainService.launcherFor(toolchain)
launcher.convention(defaultLauncher)
}
@TaskAction
fun execute() {
val result = execOps.exec {
// Is this a good idea?
executable(launcher.get().metadata.installationPath.file("bin/jlink"))
// ... other configuration ...
}
result.rethrowFailure()
result.assertNormalExitValue()
}
}
But is this part:
executable(launcher.get().metadata.installationPath.file("bin/jlink"))
A good idea? Is there a better implementation? Should I not use toolchains for this?
Additionally, will toolchains be extended to support any Java tool, or perhaps simply provide a way (if there isn’t one already?) to get the installation path without going through, e.g., JavaLauncher
(which implies the java
tool will be used)?