How to download java for use by the build

Is there any example somewhere of having gradle download a specific version of java and then use it for the build? I get that gradle requires some version of java to work at all, but it would be nice to have project-specific versions of java that don’t require a specific java location or an env var. Basically, I’d like for any member of the team to be able to clone the project and build as long as they have a java that is capable of running gradle, but I want to control the exact version of java used in the build.

Different versions of our product require different versions of java, and I’d like to be able to put those versions into our internal nexus and download them at the start of the build if they’re not already there, and then use that version of java for the remainder of the build.

I’m on windows and people generally use the plain old command prompt for building, so cygwin/git-bash possibilities like direnv or sdkman seem like non-starters for me. I’m really looking for something where gradle does the work itself.

We wrote our own plugin that generates a wrapper script to check our Artifactory server and install an rpm as required (we don’t need to support windows, but it should be possible to do something for Windows as well). After installing any required JDKs it launches the wrapper generated by Gradle’s wrapper task. In short, we wrote a wrapper for the wrapper.

Our wrapper task depends on the wrapper task from Gradle, which is configured to generate its scripts in a custom directory known by our generated wrapper scripts.

Looks something like this at execution time:

./gradlew tasks
    |-- check installed jdk version against required/available on server
    |-- install as necessary
    \-- set JAVA_HOME and launch Gradle generated wrapper script, passing over args
        \-- JAVA_HOME=<installed location> gradle/wrapper/gradle-wrapper tasks

Our wrapper plugin allows the project to specify the java version required which then gets used by the plugin to generate the scripts (similar to how the Gradle wrapper plugin uses the gradleVersion property to generate the wrapper’s properties file).

Thanks. I was able to do something a little different by changing my requirements a bit.

It’s really only the JavaCompile tasks that I care about using the correct version of Java, so I came up with something like this:

task getJdk(type: Copy) {
    from zipTree(configurations.jdk.singleFile)
    into file('.gradle/java')
}

task getJre(type: Copy) {
    from zipTree(configurations.jre.singleFile)
    into file('.gradle/java')
}

task getJava(dependsOn: [getJdk, getJre]) {
    afterEvaluate {
        // For anything in a sub-project, just grab the right java
        subprojects.each { it.tasks.each { it.dependsOn getJava } }
    }
}

And then this to make sure subprojects use it:

subprojects {

    tasks.withType(JavaCompile) {
        options.fork = true
        options.forkOptions.javaHome = jdkHome // THIS IS SET TO A KNOWN LOCATION
    }
}
1 Like

I think you might also want to apply the right version of Java when running tests, otherwise you’re not necessarily testing what you’re shipping.

FYI: wrote a plugin to download an openjdk in the gradle wrapper: https://github.com/rmee/gradle-plugins/tree/master/jdk-bootstrap