Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
4.6 KiB
15. Build files: what the 21 to 25 upgrade does to Maven, Gradle and Lombok
Prev: 14. The 21 to 25 lane · Back to the README
The build half of the upgrade guide, run by scripts/upgrade.sh.
Everything below is a run on JDK 21, 23, 24, 25, 26 or 27; the transcripts are in output/92 to output/97.
15.1 Maven: maven.compiler.release
lanes/upgrade/pom.xml sets maven.compiler.source, target and release to 25.
- Building on JDK 21 fails at once:
error: release version 25 not supported. The build JDK has to be 25 before the release can be 25 (92). - Building on JDK 25 succeeds and the class file has major version 69. Building on JDK 27 with
releasestill 25 also succeeds and also produces version 69: a newer JDK can compile for 25. Running that class on JDK 21 givesUnsupportedClassVersionError(65 is Java 21). --release Nrestricts the compiler to the API of release N, not just the language level and byte-code version. 94: JDK 27'sjavac --release 25rejectsString.equalsFoldCase(new in 26).javac -source 25 -target 25compiles it with a warning, and the class then dies on a JDK 25 withNoSuchMethodError. That, and not "rejecting internal APIs", is what--releasebuys you.
15.2 Gradle: the toolchain block, and the JDK that runs Gradle
lanes/upgrade/build.gradle.kts asks for a Java 25 toolchain. Two different JDKs are involved (93):
- the toolchain JDK, which compiles your code: Gradle 8.14.3 found and used JDK 25 for this while itself running on JDK 21;
- the JDK that runs Gradle itself: Gradle 8.14.3 on JDK 25 fails (
25.0.4.1with a Kotlin DSL script;Unsupported class file major version 69with a Groovy one, seen in a side run), Gradle 9.1.0 on JDK 25 works.
Gradle's compatibility table, read 2026-09-21: Java 25 needs Gradle 9.1.0, Java 26 needs 9.4.0, and Java 27 is not listed for any release yet.
15.3 Lombok and annotation processing
lanes/src/LombokProbe.java needs Lombok's processor to compile. 95:
| Lombok | JDK 25 | JDK 26 | JDK 27 |
|---|---|---|---|
| 1.18.34 | fails: ExceptionInInitializerError |
fails | fails |
| 1.18.40 | compiles | compiles | fails |
| 1.18.46 | compiles | compiles | fails |
| 1.18.48 | compiles | compiles | compiles |
The probe uses one annotation, so "compiles" is a lower bound: the Lombok changelog is the support statement (JDK 25 in 1.18.40, JDK 26 in 1.18.46, JDK 27 in 1.18.48). 1.18.40 compiling on 26 does not contradict it.
Separate trap, same file: since JDK 23 javac no longer runs annotation processors it merely finds on the class path. JDK 21 compiles the probe with a Note: Annotation processing is enabled...; JDK 23, 24 and 25 give cannot find symbol for getName().
Maven and Gradle projects that declare the processor with annotationProcessorPaths / annotationProcessor are unaffected; hand-run javac lines and IDE setups that relied on discovery are not.
15.4 Mockito and ByteBuddy
lanes/src/MockitoProbe.java mocks an interface and stubs one call. 97, each Mockito with the ByteBuddy it declares:
| Mockito | ByteBuddy | JDK 21 | JDK 25 | JDK 27 |
|---|---|---|---|---|
| 5.12.0 | 1.14.15 | works | fails | fails |
| 5.17.0 | 1.15.11 | works | fails | fails |
| 5.18.0 | 1.17.5 | works | works | works |
| 5.23.0 | 1.17.7 | works | works | works |
The failure is Mockito cannot mock this class (ByteBuddy cannot instrument class files newer than it knows). 5.18.0 was the first version that worked; 5.14.2, 5.16.1 and 5.17.0 failed in a side run (not committed).
Even on the working versions the JVM prints WARNING: A Java agent has been loaded dynamically on 21, 25 and 27, and Mockito 5.23.0 adds a note that self-attaching will stop working: the fix is to add Mockito as an agent, as its documentation describes.
15.5 jdeps --jdk-internals
96 is jdeps --jdk-internals on the class from UnsafeWarning.java: it names sun.misc.Unsafe before the JVM prints its run-time warning (86).