Build with java11+, run and test with java8

plantuml runs in many settings, therefor it should keep running with java8 at the moment. normally one would set the javac release flag, even parameterized as suggested here.

tasks.compileJava {
	options.release.set(8)
}

plantum is a little special, as the java rendering, e.g. using java 2d api, sometimes seems to be different when running with java8, compared to later java versions. to achieve compiling with java11+ and use new java syntax, but permit tests running with java8 we do use maven profiles to set the release flag depending on the jdk.

    <profile>
      <!-- set the release flag only for jdk which do support it, plantuml should keep running with java8. -->
      <id>javac-release-flag</id>
      <activation>
        <jdk>[9,)</jdk>
      </activation>
      <properties>
        <maven.compiler.release>8</maven.compiler.release>
      </properties>
    </profile>
    <profile>
      <!-- the source contains java11+ syntax, let mvn shout. allow "mvn test" with java8 as rendering sometimes
      can give different results with java8. -->
      <id>javac-source-flag</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
    </profile>

how would one do this in gradle?

Just don’t set it?
You have a full scripting language at hand in the build scripts, just wrap an if around with your condition.

thanks for the feedback, updated the description a little more. i failed to write a proper if condition.

tasks.compileJava {
	if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
		options.release.set(Integer.parseInt(javacRelease))
	} else {
		java.sourceCompatibility = JavaVersion.VERSION_17
		java.targetCompatibility = JavaVersion.VERSION_1_8
	}
}

when i do the same as with maven, like switch to java11 or java17, i can build. when switching to java8 and then run “gradle test” it fails with an error invalid source release: 17

So if I understood you correctly, you want to run the tests using Java 8 and Java X (whatever X is, 11, 17, doesn’t matter right now).

And with Maven for that you run Maven one time with Java 8 and one time with Java X, using profiles to set either source/target if Java 8 or release if Java X.

Right?

My suggestion would be to decouple the version Gradle is run with from the version you build and test your code with.
That’s exactly what the Java toolchains feature is for.
You can even define two test tasks, one that uses a toolchain for Java 8, one that uses a toolchain for Java X and then you can run both tasks in one go without the need to run the build tool twice.

That also has the advantage that you compile the sources like you release them and then just run the tests with different Java versions instead of rebuilding with a different version and actually not testing what is going to be released.

If you really want to continue with the other approach, as I said, just use an if statement like

tasks.compileJava {
    if (JavaVersion.current().isJava9Compatible) {
        options.release.set(8)
    } else {
        sourceCompatibility = "17"
        targetCompatibility = "1.8"
    }
}

Though actually I wonder that sourceCompatibility = "17" works when you run on Java 8.

1 Like

yes, exactly. the toolchain feature is a little tricky, as the main usage should be the continuous integration run, and the path of java is just /usr/bin, the version depends on githubs setup java done before.
and yes, again, you are right, the sourceCompatibility does not work when you are in java8. when maven sees the source is compiled it just runs the test. if it is not, it complains with an error message Fatal error compiling: invalid source release: 17 just like gradle does. gradle contrary does not care if it is already compiled, at least with this if condition above. therefor i think i must overlook something here.

You overlook that Gradle is more intelligent than Maven.
For Gradle the used Java (at least the major version) is an input for the compile task.
So the input of the task changes if you change the Java version and thus the task is rightfully considered out of date and is run again.

If you really want to follow that strategy, either use -x compileJava argument to prevent the task from running, or add enabled = false in the else branch. This might work. But it might also trigger a warning and later error, that you are using the output of the task before the task is run.

Why is the toolchain feature tricky?
With it you just need a Java version that is supported for running Gradle.
The Java version used for compilation and execution is defined by the toolchains feature.
If the version running Gradle happens to be compatible it is used.
If not, a compatible version is searched in well-known places or auto-provisioned.
This should work perfectly well on GitHub Actions.

1 Like

uh, yes. gradle is far more intelligent than i thought. currently this works, i just left out the VERSION_17 line.

tasks.compileJava {
	if (JavaVersion.current().isJava8) {
		java.targetCompatibility = JavaVersion.VERSION_1_8
	} else {
		options.release.set(Integer.parseInt(javacRelease))
	}
}

but i want to look into the toolchains feature as you suggested. on arch linux the following works:

> gradle -q javaToolchains

 + Options
     | Auto-detection:     Enabled
     | Auto-download:      Enabled

 + N/A JDK 17.0.1+12
     | Location:           /usr/lib/jvm/java-17-openjdk
     | Language Version:   17
     | Vendor:             N/A
     | Is JDK:             true
     | Detected by:        Common Linux Locations

 + OpenJDK 1.8.0_312-b10
     | Location:           /usr/lib/jvm/java-8-openjdk
     | Language Version:   8
     | Vendor:             Oracle
     | Is JDK:             true
     | Detected by:        Common Linux Locations

 + OpenJDK 11.0.13+8
     | Location:           /usr/lib/jvm/java-11-openjdk
     | Language Version:   11
     | Vendor:             Oracle
     | Is JDK:             true
     | Detected by:        Common Linux Locations

thank you so much @Vampire !

1 Like