Using toolchain but building Java 8 bytecode

Just attempted switch to using toolchain in my Java project and immediately ran into some issues. For this project, there is a hard requirement that the bytecode be compatible with Java 8, but I want to use newer Java syntax. To accomplish that I’m using jabel and have the following line in my build.gradle file:

tasks.withType(JavaCompile).all { options.compilerArgs = ["--release", "8"] }

which causes the following error:

Caused by: org.gradle.api.InvalidUserDataException: Cannot specify --release via `CompileOptions.compilerArgs` when using `JavaCompile.release`.
        at org.gradle.api.internal.tasks.compile.JavaCompilerArgumentsBuilder.validateCompilerArgs(JavaCompilerArgumentsBuilder.java:116)
        at org.gradle.api.internal.tasks.compile.JavaCompilerArgumentsBuilder.build(JavaCompilerArgumentsBuilder.java:87)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.createCompileTask(JdkJavaCompiler.java:63)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:54)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:40)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135)

Is there anyway around this problem?

Isn’t the message already telling you?
The JavaCompile task has a release property.
It is set already and you try to set --release additionally using compilerArgs.
Just use only the release property and you should be fine.

Btw. you should avoid .all but use .configureEach instead.
.all would immediately realize all tasks, .configureEach is lazy.

1 Like

Yep that’s the problem, correct syntax is below. Looks like this is a recent change as ‘options.release’ is in incubation. Does the documentation need to be updated if compilerArgs is no longer an acceptable way to specify the release? It lists what I did as a usage example.

tasks.withType(JavaCompile).configureEach { options.release = 8 }

Thanks for the help!

From the error message you got I would expect that you can still use the old approach if you didn’t set release. But I agree that anyway the example should maybe be removed. You should open an issue on GitHub about that. :slight_smile:

I actually hadn’t set release. Maybe gradle did it internally?

Yes, seems so that setting a toolchain also implicitly sets source- and targetversion for =Java9.

1 Like

This works, though I do not recommend using it.
It is just for illustration purpose:

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

tasks.withType<JavaCompile>().configureEach {
    javaCompiler.set(provider { null })
    options.forkOptions.executable = javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(11)) }.get().executablePath.asFile.absolutePath
    options.compilerArgs = listOf("--release", "8")
}

This works by first unsetting the toolchain tool on the task which also eradicates the default values for source- and targetversion and release and then setting the compiler executable and compiler args manually.

So if you are not using the incubating toolchains feature at all, you could also still use the non-incubating way to set the release flag.

1 Like

Thanks for looking into it! I’ll stick with the incubating feature for now since it is much cleaner.

1 Like