Repository navigation
Add unbundleProtobufRuntime() for fat JARs - #796
Merged
Merged
Conversation
A fat JAR bundling the unrelocated Protobuf runtime pins the runtime of the build that made it on the classpath of its consumers, and code generated by a newer Protobuf fails with `ProtobufRuntimeVersionException`. The runtime cannot be relocated, as it depends on the names of its classes. `Project.unbundleProtobufRuntime()` excludes `Protobuf.libs` from `shadowJar` by the dependency filter, and declares them as non-transitive `runtime` dependencies: in a `protobufRuntime` configuration extended by `shadowRuntimeElements`, and in the POM of the given artifact-only publication. It replaces the copies of this code in tool-base and compiler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Allow a call per publication of the fat JAR, use the name constants of Shadow and the `publications` accessor, and state in the KDoc the order of calls and the effect on the compile classpath of consumers. Extend the test: merging into the `dependencies` element of a POM, whether Gradle or a build script wrote it, two calls in one module, the default and a custom publication, the dependencies the Shadow filter leaves in, and a run with the configuration cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alexander-yevsyukov
enabled auto-merge (squash)
October 16, 2026 17:52
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The expanded integration tests still await verification on the reviewed revision.
0 open findings
What changed in this PR
Adds an opt-in publishing helper so fat JAR consumers can resolve Protobuf versions instead of using a bundled runtime.
Changes:
- Excludes Protobuf from Shadow JARs and declares non-transitive runtime dependencies in publication metadata.
- Adds integration coverage for JAR contents, manifests, POMs, and shadowed variants.
- Records implementation progress and downstream adoption steps.
| File | Description |
|---|---|
buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtobufRuntimeIgTest.kt |
Tests runtime exclusion and publication metadata. |
buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtobufRuntime.kt |
Implements unbundleProtobufRuntime(). |
.agents/tasks/unbundle-protobuf-runtime.md |
Tracks verification and downstream adoption. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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.
Problem
Fat JARs that bundle the Protobuf runtime unrelocated pin the runtime of the build that made them on their consumers' classpath. Gradle cannot see the copy, because it is bytecode inside another artifact rather than a dependency, so
force(...)cannot replace it. Code generated by a newer Protobuf then fails withProtobufRuntimeVersionException. During the dependency refresh (Protobuf4.36.0 → 4.36.2) this brokecore-jvm-compiler,core-jvm, andjdbc-storage.Relocation is not an option, because the Protobuf runtime depends on the names of its classes. SpineEventEngine/tool-base#196 and SpineEventEngine/compiler#89 fix their fat JARs with two copies of the same code. This PR moves that code here, so both can call it.
Change
buildSrc/…/io/spine/gradle/publish/ProtobufRuntime.ktaddsProject.unbundleProtobufRuntime(publication: String = "fatJar"). For each library ofProtobuf.libs, it:shadowJarthrough the dependency filter, not by path. This keeps the SBOM accurate (SbomContent.bundled(task));protobufRuntimeconfiguration. Shadow'sshadowRuntimeElementsextends it, so the shadowed variant, such as a Gradle plugin's publication, lists the library in its metadata;fatJarofuber-jar-moduleby default, orcliFatJarin compiler. If the POM already has a<dependencies>element, the entries go into it.Why some alternatives were not used:
shadowconfiguration. Shadow would also write the library into the manifestClass-Path(Class-Path: protobuf-java-4.36.2.jar …). In a directory that holds several Protobuf JARs, that entry would put the build-time version first again.uber-jar-module. The function is opt-in, because the IntelliJ Platform uber JARs use that script too, bundle no Protobuf, and must not declare it.protobuf-javais declared itself, and Gradle provides Kotlin.Tests
ProtobufRuntimeIgTestruns an offline TestKit build with the configuration cache. The repository holds stand-in Protobuf JARs;protobuf-java-utildepends on a Gson stand-in. The test checks:com/google/protobuf/entries, while Gson and the other libraries stay bundled.includedDependenciesno longer lists Protobuf.Class-Path..moduledeclare the three libraries,runtime, with*:*exclusions.<dependencies>element, written by Gradle or by hand, the entries are added to it and the POM keeps a single one../gradlew :buildSrc:test --tests '*ProtobufRuntimeIgTest' detektpasses: 9 of 9 tests, and Detekt is clean.After merge
SpineEventEngine/tool-base#196 and SpineEventEngine/compiler#89 run
./config/pulland replace their copies with:unbundleProtobufRuntime()unbundleProtobufRuntime(publication = "cliFatJar")🤖 Generated with Claude Code