Publish a Java 11 main artifact and a jdk21 classifier - #68
Merged
Merged
Conversation
Mirrors the split cfparser now publishes. One source tree, two jars: cflint-VERSION.jar class file 55 (Java 11) -- 11, 17, 21, 25 cflint-VERSION-all.jar class file 55 (Java 11) -- shaded, same cflint-VERSION-jdk21.jar class file 65 (Java 21) -- 21+ The default is the one that loads everywhere; the classifier is for consumers who specifically want a 21-targeted build. Both variants compile against the Java 11 cfparser artifact -- a pom has one dependency set, and a Java 11 CFLint linked against a Java 21 parser would fail at runtime on 11. maven.compiler.source/target become release, which checks the API surface rather than only the language level, so a Java 12+ method call fails the build instead of producing a jar that NoSuchMethodErrors on 11. The resource copy into classes-jdk21 stays at process-classes for the reason cfparser's pom documents: setting outputDirectory on a compiler execution leaks into what dependents resolve, and running the copy later breaks the test run with an error that reads like a missing resource. CI gains a java-version axis of [11, 21] across all three operating systems, with fail-fast: false. Both JDKs are installed with 21 last, so Gradle's daemon stays on 21 while the toolchain moves to the matrix JDK for compiling and running the tests -- compiling to 11 on a 21 JDK cannot see a problem that only appears on an 11 runtime. Verified: 675 Maven tests, ./gradlew build, and the packaged jars carry the expected class file versions with matching class counts between the main and jdk21 variants. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GzpZFd4rnE1Yi2sVHAji35
Gradle treats a -SNAPSHOT as a changing module and caches it for 24 hours, and the CI workflows restore a Gradle cache. A green run shortly after a cfparser republish can therefore have tested the previous artifact -- which reads as a pass rather than as a stale dependency. This is not hypothetical here: the Java 11 CI jobs on this branch failed with "class file has wrong version 65.0, should be 55.0" against the cfparser SNAPSHOT published before the Java 11 split landed, and without this the re-run after republishing could have resolved the same cached jar again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GzpZFd4rnE1Yi2sVHAji35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mirrors the split cfparser now publishes (cfmleditor/cfparser#73). One source tree, three jars:
cflint-VERSION.jarcflint-VERSION-all.jarcflint-VERSION-jdk21.jarThe default is the one that loads everywhere; the classifier is there for consumers who specifically want a 21-targeted build.
Both variants depend on the Java 11 parser
Maven cannot pair main→main and jdk21→jdk21 — a pom has one dependency set, so both CFLint variants compile against whichever cfparser artifact is declared. Declaring the Java 11 one is the only correct choice: a Java 11 CFLint linked against a Java 21 parser would fail at runtime on 11, which is the exact case this change exists to support. The jdk21 classifier is a bytecode-level variant, not a separate dependency graph.
releaserather thansource/targetmaven.compiler.source/targetonly set the language level — they will happily compile a call to a Java 17 method into class file 55 and hand you a jar that throwsNoSuchMethodErroron 11.--releasechecks the API surface too, so that fails the build instead.The resource copy stays at process-classes
maven-jar-plugintakes a singleclassesDirectory, andclasses-jdk21holds only.classfiles, so the classified jar needs resources copied in.That copy cannot move later. Setting
outputDirectoryon a compiler execution leaks into what the reactor hands dependent modules — in cfparser, moving this toprepare-packagemade all 326 tests fail withProblem loading dictionaryconfig.xml, which reads like a missing resource rather than a phase-ordering problem. The comment sits at the line where someone would otherwise move it.CI runs on both runtimes
gradle.ymlgains ajava-versionaxis of[11, 21]across all three operating systems, withfail-fast: falseso one platform failing does not mask the others.Compiling to 11 on a 21 JDK cannot catch a problem that only appears on an 11 runtime, so the matrix is the only thing that actually exercises Java 11.
Both JDKs are installed with 21 last, so it becomes
JAVA_HOMEand Gradle's daemon runs there; the matrix JDK is picked up by the toolchain to compile and run the tests. That separation is load-bearing on the cfparser side, where the bnd OSGi plugin is class file 61 and throwsUnsupportedClassVersionErrorif the daemon is on 11. Keeping the two builds symmetric is worth more than shaving a step here.Gradle builds the Java 11 line only. Maven is what publishes, so the classifier is produced there.
The second commit: always re-resolve the cfparser SNAPSHOT
The first CI run failed on all three Java 11 jobs, identically:
Not a defect in this change — the published
2.16.1-SNAPSHOTwas still the Java 21 build. cfparser#73 merging tomasterpublishes nothing; that repository's publish workflow fires only on a tag push, a release, or a dispatch. This ordering is now permanent: a cfparser change that CFLint's Java 11 leg depends on has to be published before CFLint's CI can go green. Merging cfparser first is not enough.Republishing the parser fixed it, but exposed a second problem worth closing while it was visible. Gradle treats a
-SNAPSHOTas a changing module and caches it for 24 hours, and the CI workflows restore a Gradle cache — so a green run shortly after a cfparser republish can have tested the previous artifact, and here the re-run could have resolved the same stale jar and failed for a reason that no longer existed.resolutionStrategy.cacheChangingModulesFor 0, 'seconds'makes CFLint always take the newest parser. It is one small jar; a stale one costs far more than the download.Verification
mvn clean test— 0 failures, 0 errors./gradlew build -PjavaTestVersion=21— BUILD SUCCESSFUL, and the Gradle jar is class file 55mvn clean packageproduces the three jars at the class file versions above, with matching class counts between the main andjdk21variants (128 each; the shaded-allis 9,437)Follow-up
CFLint's
cfparser.versionis a SNAPSHOT pin. When cfparser next cuts a fixed version, this should move to it — at which point thecacheChangingModulesForsetting stops mattering for that dependency, though it stays correct.🤖 Generated with Claude Code
https://claude.ai/code/session_01GzpZFd4rnE1Yi2sVHAji35