Skip to content

GROOVY-12280: hold cached awaitable adapters through SoftReferences - #2818

Merged
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12280
Aug 19, 2026
Merged

GROOVY-12280: hold cached awaitable adapters through SoftReferences#2818
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12280

Conversation

@paulk-asert

@paulk-asert paulk-asert commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

A ClassValue association lives as long as its key class, and the common keys here are platform classes such as CompletableFuture, so the cached Groovy-loaded adapter pinned Groovy's class loader for the lifetime of the JVM (JDK-8136353 behavior, working as intended). The value is now held through a SoftReference: the association strongly reaches only java.base objects. A cleared reference is removed and recomputed once; should the fresh reference already be cleared, the answer comes from an uncached scan, so lookups terminate under any memory pressure. A NO_ADAPTER sentinel keeps unsupported types distinguishable from cleared references.

The site deliberately stays on java.lang.ClassValue rather than routing through GroovyClassValueFactory: with soft values nothing strongly Groovy-loaded remains in the association, so there is nothing left for the groovy.use.classvalue escape hatch to release here.

Soft references are cleared by the collector under heap pressure, so the class loader becomes collectible rather than instantly collected — the designed semantics of the strategy agreed in the GROOVY-12142 review discussion, not a gap.

The change was also verified against the groovy-concurrent-java deliverable, whose jar is a filtered extraction of core promising Java users no Groovy-runtime dependency: jdeps over the registry classes with only that jar on the classpath resolves every reference from java.base or the jar itself (SoftReference and ClassValue are java.base). That check is a second, independent reason the factory-routing alternative was declined — GroovyClassValueFactory lives in org.codehaus.groovy.reflection, outside the extraction set, so routing through it would have shipped the extracted jar with an unresolvable reference.

Comment thread src/main/java/groovy/concurrent/AwaitableAdapterRegistry.java
@codecov-commenter

codecov-commenter commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.1852%. Comparing base (1c2f0f2) to head (359464e).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
...va/groovy/concurrent/AwaitableAdapterRegistry.java 78.9474% 3 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #2818        +/-   ##
==================================================
+ Coverage     70.1794%   70.1852%   +0.0058%     
- Complexity      35853      35882        +29     
==================================================
  Files            1563       1563                
  Lines          132546     132575        +29     
  Branches        24385      24397        +12     
==================================================
+ Hits            93020      93048        +28     
  Misses          31113      31113                
- Partials         8413       8414         +1     
Files with missing lines Coverage Δ
...va/groovy/concurrent/AwaitableAdapterRegistry.java 72.0000% <78.9474%> (-1.0159%) ⬇️

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

This comment has been minimized.

A ClassValue association lives as long as its key class, and the common
keys here are platform classes such as CompletableFuture, so the cached
Groovy-loaded adapter pinned Groovy's class loader for the lifetime of
the JVM (JDK-8136353 behavior, working as intended). The value is now
held through a SoftReference: the association strongly reaches only
java.base objects. A cleared reference is removed and recomputed once;
should the fresh reference already be cleared, the answer comes from an
uncached scan, so lookups terminate under any memory pressure. A
NO_ADAPTER sentinel keeps unsupported types distinguishable from
cleared references.

The site deliberately stays on java.lang.ClassValue rather than routing
through GroovyClassValueFactory: with soft values nothing strongly
Groovy-loaded remains in the association, so there is nothing left for
the groovy.use.classvalue escape hatch to release here.
@paulk-asert
paulk-asert merged commit 3c32710 into apache:master Aug 19, 2026
29 checks passed
@paulk-asert
paulk-asert deleted the groovy12280 branch August 19, 2026 09:03
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.

3 participants