Skip to content

Cache MetadataReader by class name to avoid duplicate metadata#36977

Open
LordKay-sudo wants to merge 1 commit into
spring-projects:mainfrom
LordKay-sudo:issue-36737-cache-metadata-by-class-name
Open

Cache MetadataReader by class name to avoid duplicate metadata#36977
LordKay-sudo wants to merge 1 commit into
spring-projects:mainfrom
LordKay-sudo:issue-36737-cache-metadata-by-class-name

Conversation

@LordKay-sudo

@LordKay-sudo LordKay-sudo commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Addresses duplicate metadata caching in CachingMetadataReaderFactory when the same .class file is discovered through different Resource representations during classpath scanning (e.g. ClassPathResource with a relative path vs UrlResource with a filesystem path).

This matches the duplication described by @pkernevez and hypothesized by @sbrannen in gh-36737, and corresponds to issue 1 as split by @bclozel in #36737 (comment).

  • Adds a class-name keyed cache so only one MetadataReader (and its ClassFileAnnotationMetadata on Java 24+) is retained per class
  • Restores class-name caching previously provided by Spring Boot's removed ConcurrentReferenceCachingMetadataReaderFactory (spring-boot#47687), while still delegating to the ClassFile-backed factory on Java 24+

What this does NOT fix

gh-36737 reports several independent memory problems. This PR does not address:

  • ClassFileAnnotationMetadata using more memory per class than the ASM implementation (bclozel's issue 2; workaround: shadow MetadataReaderFactoryDelegate)
  • Micrometer global registry pinning contexts (management.metrics.use-global-registry=false; Spring Boot)
  • PostgreSQL JDBC SharedTimer pinning contexts via InheritableThreadLocals (reported by @pkernevez)
  • Multiple cached ApplicationContext instances in large test suites

Reproduction

On main, the new tests fail:

CachingMetadataReaderFactoryTests > shouldNotDuplicateMetadataForSameClassFromDifferentResources() FAILED
    org.mockito.exceptions.verification.TooManyActualInvocations

CachingMetadataReaderFactoryTests > shouldReuseMetadataReaderForSameClassFromDifferentResources() FAILED
    java.lang.AssertionError

With this PR, all four tests in CachingMetadataReaderFactoryTests pass.

Test plan

  • ./gradlew :spring-core:test --tests "org.springframework.core.type.classreading.CachingMetadataReaderFactoryTests"
  • ./gradlew :spring-core:test --tests "org.springframework.core.type.classreading.*"
  • Verified reproduction tests fail on main before applying the fix

Related to gh-36737

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jun 29, 2026
Avoid retaining duplicate annotation metadata when the same .class file
is discovered through different Resource representations during classpath
scanning (for example, ClassPathResource vs file URL paths).

Adds regression tests that reproduce spring-projectsgh-36737.

Closes spring-projectsgh-36737

Signed-off-by: LordKay-sudo <lkandiro@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants