Skip to content

Make WrapDynaClass instance cache thread-safe#418

Merged
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:wrapdynaclass-cache-thread-safe
Jul 15, 2026
Merged

Make WrapDynaClass instance cache thread-safe#418
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:wrapdynaclass-cache-thread-safe

Conversation

@rootvector2

Copy link
Copy Markdown
Contributor

WrapDynaClass.createDynaClass populates its per-classloader cache with computeIfAbsent, but the cache is a plain WeakHashMap, so threads that share a context classloader race on an unsynchronized map where computeIfAbsent is not atomic: concurrent callers can build and return different WrapDynaClass instances for one key, and the structural writes can corrupt the map. Switch the cache to BeanUtils.createCache(), the weak-keyed ConcurrentReferenceHashMap that MethodUtils, ConvertUtilsBean and PropertyUtilsBean already use. Found while auditing the package's computeIfAbsent call sites against those thread-safe caches. Like the MethodUtils visibility fix this race has no deterministic unit test so none is added, though a stress loop over concurrent createDynaClass calls does surface the duplicate instances.

  • Read the contribution guidelines for this project.
  • Read the ASF Generative Tooling Guidance if you use Artificial Intelligence (AI).
  • I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute?
  • Run a successful build using the default Maven goal with mvn; that's mvn on the command line by itself.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process.

@garydgregory garydgregory left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootvector2
Please add a unit test to avoid a future regression.

@garydgregory garydgregory changed the title make WrapDynaClass instance cache thread-safe Make WrapDynaClass instance cache thread-safe Jul 14, 2026
Signed-off-by: Naveed Khan <dxbnaveed.k@gmail.com>
@rootvector2

Copy link
Copy Markdown
Contributor Author

added a regression test that races 16 threads on createDynaClass for one bean class over 200 rounds and asserts a single cached instance comes back. it fails against the old WeakHashMap and passes with BeanUtils.createCache().

@garydgregory
garydgregory merged commit 1784728 into apache:master Jul 15, 2026
9 checks passed
@garydgregory

Copy link
Copy Markdown
Member

Merged, TY @rootvector2 , please port to 1.X if possible.

@rootvector2

Copy link
Copy Markdown
Contributor Author

thanks for merging. port is up in #4191.X has no atomic computeIfAbsent to lean on, so it swaps the cache to BeanUtils.createCache() and synchronizes the get/create/put in createDynaClass, with the same regression test ported.

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.

2 participants