Skip to content

Backport 26.1: Remove dependency annotations from shaded classes - #4452

Merged
andimarek merged 1 commit into
26.xfrom
codex/backport-4445-to-26.x
Aug 20, 2026
Merged

Backport 26.1: Remove dependency annotations from shaded classes#4452
andimarek merged 1 commit into
26.xfrom
codex/backport-4445-to-26.x

Conversation

@andimarek

Copy link
Copy Markdown
Member

Backport of #4445 to the 26.x maintenance branch.

This also upgrades the Shadow Gradle plugin from 9.3.2 to 9.4.2 so the backport can retain the original artifact lifecycle configuration.

Summary

  • define an explicit list of unbundled CLASS-retention annotations to remove from shaded class files
  • add an ASM-powered cleanup stage after shadowing and before final JAR assembly
  • preserve invisible annotations whose annotation classes are bundled, including GraphQL Java and relocated dependency annotations
  • reject new RuntimeInvisibleAnnotations and RuntimeInvisibleParameterAnnotations whose annotation classes are not bundled and are not in the removal list
  • share the class-file rewrite machinery with the existing JaCoCo annotation task
  • compile a Java 11 consumer with class-file warnings treated as errors
  • make the annotation-cleaned JAR the sole unclassified binary artifact and the sole main artifact used by consumers, signing, and publication

Artifact pipeline

The regular jar and shadowJar outputs are internal inputs to the cleanup pipeline. They now have explicit plain and shadow classifiers and live under build/intermediates, outside build/libs.

buildFinalJar is the only task that writes the unclassified binary JAR to build/libs. It consumes the annotation-cleaned class tree directly, so Gradle tracks the actual final archive instead of a temporary archive that is renamed in doLast.

The Java API and runtime variants both expose buildFinalJar. The Shadow Java variant and assemble hook are disabled, and shadowRuntimeElements is non-consumable, so dependency resolution cannot select the uncleaned intermediate. Direct signing, Maven Local publication, and remote publication all depend on verification of the final JAR.

This separation matters because multiple tasks previously owned the same output path. A direct shadowJar invocation could overwrite the cleaned JAR while Gradle still considered the cleanup/reassembly tasks up to date. Unique intermediate paths plus a single final producer remove that failure mode.

Verification

  • ./gradlew outgoingVariants: API and runtime variants expose only buildFinalJar; no consumable Shadow variant remains
  • ./gradlew clean test assemble verifyShadedClassAnnotations compileShadedJarConsumer: passed, including 5,737 tests
  • ./gradlew check -x test -x testng: passed
  • isolated publishGraphqlJavaPublicationToMavenLocal: published only the main, sources, Javadoc, and POM artifacts
  • the isolated Maven-local main JAR had the same SHA-256 as the buildFinalJar output
  • direct ./gradlew jar shadowJar invocation left the final JAR SHA-256 unchanged

The cleanup currently removes 1,345 annotations from 330 shaded class files.

Artifact size

Both artifacts were built through their complete publication pipelines with the same fixed 999.0.0-size-test release version.

Artifact Size
origin/master before removal 3,878,053 bytes
This PR after removal 3,873,126 bytes
Reduction 4,927 bytes (0.127%)

The uncompressed JAR contents decrease by 16,152 bytes. Both archives contain 2,394 entries, and their manifests are identical.

@github-actions

Copy link
Copy Markdown
Contributor

Test Report

Test Results

Java Version Total Passed Failed Errors Skipped
Java 11 5733 (-194 🔴) 5677 (-194 🔴) 0 (±0) 0 (±0) 56 (±0)
Java 17 5733 (-194 🔴) 5676 (-194 🔴) 0 (±0) 0 (±0) 57 (±0)
Java 21 5733 (-194 🔴) 5676 (-194 🔴) 0 (±0) 0 (±0) 57 (±0)
Java 25 5733 (-194 🔴) 5676 (-194 🔴) 0 (±0) 0 (±0) 57 (±0)
jcstress 32 (±0) 32 (±0) 0 (±0) 0 (±0) 0 (±0)
Total 22964 (-776 🔴) 22737 (-776 🔴) 0 (±0) 0 (±0) 227 (±0)

Code Coverage (Java 25)

Metric Covered Missed Coverage vs Master
Lines 28903 3119 90.3% -0.3% 🔴
Branches 8418 1504 84.8% -0.4% 🔴
Methods 7730 1222 86.3% -0.6% 🔴

Changed Class Coverage (35 classes)

Class Line Branch Method
g.l.AstSignature
$3
+100.0% 🟢 +100.0% 🟢 +100.0% 🟢
g.l.AstSignatureInputReferences removed removed removed
g.l.AstSignatureReferenceCollector removed removed removed
g.l.AstSignatureWithInputResult removed removed removed
g.l.AstSignatureWithInputResult
$Builder
removed removed removed
g.l.Directive -3.2% 🔴 ±0.0% -5.9% 🔴
g.l.DirectiveDefinition -19.2% 🔴 ±0.0% ±0.0%
g.l.DirectiveExtensionDefinition removed removed removed
g.l.DirectiveExtensionDefinition
$Builder
removed removed removed
g.l.DirectiveLocation -4.3% 🔴 ±0.0% -8.3% 🔴
g.l.FragmentSpread -16.1% 🔴 ±0.0% -27.8% 🔴
g.l.FragmentSpread
$Builder
-6.5% 🔴 ±0.0% -9.1% 🔴
g.l.PrettyAstPrinter ±0.0% -2.0% 🔴 ±0.0%
g.l.VariableDefinition -14.5% 🔴 ±0.0% -26.1% 🔴
g.l.VariableDefinition
$Builder
-6.2% 🔴 ±0.0% -8.8% 🔴
g.s.d.a.EditOperationAnalyzer -0.3% 🔴 ±0.0% -0.7% 🔴
g.s.d.a.SchemaDifference
$AppliedDirectiveDirectiveLocation
removed removed removed
g.s.GraphQLDirective -3.1% 🔴 ±0.0% -6.7% 🔴
g.s.GraphqlDirectivesContainerTypeBuilder -14.7% 🔴 -50.0% 🔴 -18.2% 🔴
g.s.GraphQLInterfaceType
$Builder
-1.4% 🔴 ±0.0% -3.8% 🔴
g.s.GraphQLObjectType -1.7% 🔴 ±0.0% -3.6% 🔴
g.s.i.e.DirectiveExtensionDirectiveRedefinitionError removed removed removed
g.s.i.e.DirectiveExtensionMissingBaseError removed removed removed
g.s.i.e.SchemaProblem -16.7% 🔴 ±0.0% -25.0% 🔴
g.s.i.TypeDefinitionRegistry ±0.0% -0.3% 🔴 ±0.0%
g.s.i.UnionTypesChecker ±0.0% -7.1% 🔴 ±0.0%
g.s.t.FieldVisibilitySchemaTransformation
$ElementRemovalVisitor
removed removed removed
g.s.t.FieldVisibilitySchemaTransformation
$FieldRemovalVisitor
+100.0% 🟢 +100.0% 🟢 +100.0% 🟢
g.s.t.VisibleInterfaceImplementationPredicateEnvironmentImpl removed removed removed
g.s.v.NoDefaultValueCircularRefs removed removed removed
g.s.v.NoUnbrokenInputCycles -2.6% 🔴 -4.4% 🔴 ±0.0%
g.v.OperationValidator ±0.0% -1.3% 🔴 ±0.0%
g.v.TraversalContext +99.4% 🟢 +94.1% 🟢 +100.0% 🟢
g.v.ValidationContext -2.8% 🔴 ±0.0% -5.0% 🔴
g.v.ValidationError
$Builder
±0.0% -50.0% 🔴 ±0.0%
Directive — method details
Method Line Branch
deepCopy 0.0% (-100.0% 🔴)
DirectiveDefinition — method details
Method Line Branch
<init> new 100.0%
withNewChildren 0.0% (-100.0% 🔴)
deepCopy 0.0% (-100.0% 🔴)
lambda$withNewChildren$0 0.0% (-100.0% 🔴)
<init> removed removed
getDirectives removed removed
getDirectivesByName removed removed
getDirectives removed removed
hasDirective removed removed
DirectiveLocation — method details
Method Line Branch
deepCopy 0.0% (-100.0% 🔴)
FragmentSpread — method details
Method Line Branch
getDirectivesByName 0.0% (-100.0% 🔴)
getDirectives 0.0% (-100.0% 🔴)
hasDirective 0.0% (-100.0% 🔴)
withNewChildren 0.0% (-100.0% 🔴)
lambda$withNewChildren$0 0.0% (-100.0% 🔴)
FragmentSpread.Builder — method details
Method Line Branch
directive 0.0% (-100.0% 🔴)
PrettyAstPrinter — method details
Method Line Branch
lambda$directiveDefinition$0 100.0% 50.0% (-50.0% 🔴)
directiveExtensionDefinition removed removed
lambda$directiveExtensionDefinition$0 removed removed
VariableDefinition — method details
Method Line Branch
<init> new 100.0%
getDirectivesByName 0.0% (-100.0% 🔴)
getDirectives 0.0% (-100.0% 🔴)
hasDirective 0.0% (-100.0% 🔴)
withNewChildren 0.0% (-100.0% 🔴)
newVariableDefinition 0.0% (-100.0% 🔴)
lambda$withNewChildren$0 0.0% (-100.0% 🔴)
<init> removed removed
VariableDefinition.Builder — method details
Method Line Branch
directive 0.0% (-100.0% 🔴)
description removed removed
EditOperationAnalyzer — method details
Method Line Branch
appliedDirectiveDeleted 85.5% 72.5% (-0.2% 🔴)
appliedDirectiveArgumentDeleted 82.6% (-0.3% 🔴) 73.5% (-0.6% 🔴)
appliedDirectiveArgumentAdded 79.6% (-0.4% 🔴) 69.4% (-0.8% 🔴)
appliedDirectiveArgumentChanged 99.1% 68.6% (-0.3% 🔴)
appliedDirectiveAdded 85.5% 72.5% (-0.2% 🔴)
isAppliedDirectiveAdded 80.4% (-8.9% 🔴) 78.6% (-4.8% 🔴)
lambda$isAppliedDirectiveAdded$6 0.0% (-100.0% 🔴)
GraphQLDirective — method details
Method Line Branch
<init> new 100.0%
copy 0.0% (-100.0% 🔴)
<init> removed removed
getExtensionDefinitions removed removed
isDeprecated removed removed
getDeprecationReason removed removed
getDirectives removed removed
getDirectivesByName removed removed
getAllDirectivesByName removed removed
getDirective removed removed
getAppliedDirectives removed removed
getAllAppliedDirectivesByName removed removed
getAppliedDirective removed removed
GraphqlDirectivesContainerTypeBuilder — method details
Method Line Branch
withDirectives 0.0% (-100.0% 🔴) 0.0% (-100.0% 🔴)
withDirective 0.0% (-100.0% 🔴)
GraphQLInterfaceType.Builder — method details
Method Line Branch
replaceInterfaces 0.0% (-100.0% 🔴)
GraphQLObjectType — method details
Method Line Branch
getDirective 0.0% (-100.0% 🔴)
SchemaProblem — method details
Method Line Branch
toString 0.0% (-100.0% 🔴)
TypeDefinitionRegistry — method details
Method Line Branch
<init> new 100.0%
add 95.6% (-0.3% 🔴) 92.9% (-0.5% 🔴)
remove 92.3% (-0.5% 🔴) 90.9% (-0.8% 🔴)
remove 74.1% (-1.8% 🔴) 68.2% (-2.7% 🔴)
isPossibleType 92.6% (+14.8% 🟢) 83.3% (+16.7% 🟢)
<init> removed removed
removeDirectiveExtension removed removed
defineDirectiveExt removed removed
directiveExtensions removed removed
implementsInterface removed removed
getImplementingTypeExtensions removed removed
isUnionMember removed removed
lambda$isUnionMember$0 removed removed
lambda$implementsInterface$0 removed removed
lambda$defineDirectiveExt$0 removed removed
lambda$merge$15 removed removed
lambda$merge$16 removed removed
UnionTypesChecker — method details
Method Line Branch
checkUnionType 100.0% 90.0% (-10.0% 🔴)
hasMemberTypes removed removed
lambda$hasMemberTypes$0 removed removed
NoUnbrokenInputCycles — method details
Method Line Branch
unwrapNonNull 83.3% (-16.7% 🔴) 75.0% (-25.0% 🔴)
OperationValidator — method details
Method Line Branch
checkVariable new 100.0% 100.0%
validateDeferDirectiveOnRootLevel 92.9% 68.8% (-12.5% 🔴)
validateDeferDirectiveOnValidOperation new 90.9% 80.0%
getOperationDefinition new 100.0%
lambda$getOperationDefinition$1 new 100.0%
lambda$getOperationDefinition$0 new 100.0%
enterTraversal removed removed
enterField removed removed
enterVariableDefinition removed removed
enterArgument removed removed
enterArrayValue removed removed
enterObjectField removed removed
leaveTraversal removed removed
resolveSelectionSetParent removed removed
getSelectionSetOwnerType removed removed
getOperationType removed removed
getFieldDefinition removed removed
getArgumentDefinition removed removed
getNullableType removed removed
getParentType removed removed
getFieldDefinition removed removed
getInputType removed removed
getDefaultValue removed removed
getDirectiveDefinition removed removed
enterName removed removed
leaveName removed removed
lastElement removed removed
pop removed removed
checkVariable removed removed
validateVariableNotAllowedInConstantDirective removed removed
getInlineFragmentType removed removed
validateDeferDirectiveOnValidOperation removed removed
ValidationContext — method details
Method Line Branch
getTraversalContext new 100.0%
getParentType new 100.0%
getInputType new 100.0%
getDefaultValue new 100.0%
getFieldDef new 100.0%
getDirective new 100.0%
getArgument new 100.0%
getOutputType new 100.0%
getQueryPath new 100.0%
toString new 0.0%
ValidationError.Builder — method details
Method Line Branch
sourceLocation 100.0% 50.0% (-50.0% 🔴)

Full HTML report: build artifact jacoco-html-report

Updated: 2026-08-20 00:51:28 UTC

@andimarek
andimarek merged commit 1dadd71 into 26.x Aug 20, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant