3

I want to run Gradle with the default system JRE, in my case Java8.

And in the build I want to use a specific JDK 13 with the option.fork=true

compileJava {
    options.encoding = 'UTF-8'
    sourceCompatibility = 13
    targetCompatibility = 13
    options.compilerArgs << "-parameters"
    options.compilerArgs << "--release" << "13"
    options.compilerArgs << "--enable-preview"
    options.fork = true
    options.forkOptions.executable = "${projectDir}/tools/java/bin/javac.exe"
}

When I start gradle with the JRE 8, this fails with message:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not target platform: 'Java SE 13' using tool chain: 'JDK 8 (1.8)'.

But when I set the JAVA_HOME to the JDK 13, then it runs successfully.

Is there a way I can make this run, with the Gradle started with JRE8 but using the JDK13 for the build?

Frank

fbenoit
  • 3,220
  • 6
  • 21
  • 32

1 Answers1

3

Gradle has a check that targetCompatibility is not higher than the currently running version of Java. To be honest, I don't know why it checks for this when you fork the compiler to a newer version (it should probably check that version if anything instead). But maybe there is a good reason for it.

However, the two properties are also completely redundant when you use the --release flag. This already tells the compiler that it should generate byte code for that particular version. I don't even think the compiler supports having both source and target arguments along with --release at the same time. So if you remove the two properties sourceCompatibility and targetCompatibility, it should work.

Also, the Java compiler defaults to compiling for the same version, so you don't need the --release flag either.

Lastly, you are only configuring the 'main' source set compilation and you should do the same for 'test' as well. And while it may not be important, you may also want to configure JavaDoc and any tasks of type JavaExec to use Java 13, or they will default to Java 8.

So to bring it all together, when targeting a higher version of Java than what is used for Gradle, use something like this:

// Paths for the various executables in the Java 'bin' directory
def javaHome = "${projectDir}/tools/java"
def javaCompilerPath = "$javaHome/bin/javac.exe"
def javaExecutablePath = "$javaHome/bin/java.exe"
def javaDocPath = "$javaHome/bin/javadoc.exe"

tasks.withType(AbstractCompile) { // Configures all compile tasks (both for main and test)
    // The sourceCompatibility and targetCompatibility properties have been removed
    options.encoding = 'UTF-8'
    options.compilerArgs.addAll(["-parameters", "--enable-preview"]) // The --release flag is optional when used for the same version
    options.fork = true
    options.forkOptions.executable = javaCompilerPath
    options.forkOptions.javaHome = file(javaHome)
}

tasks.withType(Javadoc) { // Configures JavaDoc to use the tool in Java 13
    executable = javaDocPath
}

tasks.withType(JavaExec) { // Only needed if you have any tasks of this type
    executable = javaExecutablePath
}

When Gradle 6.0 releases, in about a week's time from now, it will have support for Java 13 so you don't need any of this (until you decide to update to Java 14 before Gradle gets support for it, of cause).

Bjørn Vester
  • 6,851
  • 1
  • 20
  • 20