Gradle First or No Good Deed Goes Unpunished

Gradle First or No Good Deed Goes Unpunished

Upgrade your Gradle before your Java

·

4 min read

Sometimes software development is like an evil game of Simon Says. Two steps forward. Two steps forward. One little bumble as you approach the finish line, and it’s ten somersaults backwards.

Details

If you are seeing Gradle fail due to an “Unsupported class file major version 65” error, your Gradle is incompatible with the new Java 21 JRE. In order to get out of this, you’ll have to back up a bit.

Gradle 7.6 is not compatible with with Java 21. Even running Gradle's wrapper upgrade fails.

$ ./gradlew --version

------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------

Build time:   2022-11-25 13:35:10 UTC
Revision:     daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8
…

$ ./gradlew wrapper --gradle-version=8.6

FAILURE: Build failed with an exception.

* What went wrong:
Could not open settings generic class cache for settings file 'C:\Users\leeca\Projects\DepanFX\dev\git\grad89.5\settings.gradle' ...
> BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 65

For me, it was back to Java 17. With Java 17 on the PATH and JAVA_HOME, I could upgrade Gradle to the latest version, 8.6.

$ echo $JAVA_HOME
C:\Program Files\Eclipse Adoptium\jdk-17.0.7.7-hotspot\

$ ./gradlew wrapper --gradle-distribution-url=https\://services.gradle.org/distributions/gradle-8.6-bin.zip

After upgrading Gradle, I was able to upgrade to Java 21 with the build executing properly.

$ echo $JAVA_HOME
C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\

$ ./gradlew run
... success

I’m looking forward to enjoying the latest set of Java enhancements.

Discovery

Over the course of whaling away at a placement problem in a graphics library, I had to put together a new development environment. Building the OSS library locally required the installation of Ant, a C compiler, and the Java 8 JDK. Eventually, I got all the parts put together and created a brand new graphics library to test.

Somewhere in the middle of all this, I also installed a brand new Java 21 JDK. I’ve been anxious to use the new pattern matching feature, and Java 21 worked fine for the library build. At this point, I’m feeling good about getting to contribute to an OSS project.

Disaster strikes as I start to move forward. After placing the new build products into my project, I fire up a Gradle build. This leads to a completely new failure mode.

$ ./gradlew run
> Task :buildSrc:compileGroovyPlugins FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':buildSrc:compileGroovyPlugins'.
> BUG! exception in phase 'semantic analysis' in source unit 'precompiled_DepanfxBase' Unsupported class file major version 65

At first, the new library code seems suspect. The library specifically targets Java 8. A little research showed that “class file major version 65” is associated with Java 21. That theory withers.

Next up is to try a Java downgrade. Unfortunately, Java and its applications have a long history of tucking Java into unexpected places and using convoluted discovery mechanisms. Which is a long way of saying that changing the PATH environment variable to use Java 17 did not work.

It turns out that Gradle prefers to use the JAVA_HOME environment variable as its source of Java components. In order to downgrade Java for Gradle, you need to set the JAVA_HOME variable to the intended Java environment.

$ export JAVA_HOME='C:\Program Files\Eclipse Adoptium\jdk-17.0.7.7-hotspot\'

Once this was in place, the upgrade of the Gradle wrapper was successful.

$ ./gradlew wrapper --gradle-distribution-url=https\://services.gradle.org/distributions/gradle-8.6-bin.zip

After upgrading Gradle, I was then able to upgrade to Java 21 and properly complete my application build.

$ export JAVA_HOME='C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\'
$ ./gradlew run

Success in the end, but only after a few somersaults backwards.

Lessons

Upgrading software development environments is a fraught endeavor. Upgrading one component can lead to cascading updates across dependent components. At the beginning, you’re never quite sure that the task is even possible.

In addition to the anticipated challenges, the upgrade to Java 21 comes with an additional sequencing requirement. If you are using Gradle as your build system, upgrade your Gradle installation to 8.5+ (preferably 8.6) before you upgrade to Java 21.

Once you finish this sequence of Simon Says moves, it is time to reap the rewards of these efforts. The new parts of Java 21 look fun.