BEANUTILS-541 - FluentPropertyBeanIntrospector caches corrupted writeMethod (parallel) #234
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.
Once #68 was merged I realized it can work not properly in a concurrent environment 🤦.
I made some tests and it was pretty hard to trigger failure - the merged fix is relatively resistant and a combination of random factors should happen simultaneously, also it only happened with high number of threads (for this reason I believe
1.x
fix can stay as is). But finally I got proof there is a problem still and tried to find a better solution without erasing the cache.So, how the updated implementation works: now there is no more
PropertyDescriptor.setWriteMethod
and the shared cachedPropertyDescriptor
object is not updated anymore as there is a risk to define a setter method for a field which is wrong in case if getter is defined in super-class and it has several subtypes defining their own setters (with generic types).Instead, in the
IntrospectionContext
thePropertyDescriptor
is just replaced with a copy of the shared object with configured setter. This should be valid, becauseIntrospectionContext
is not a cached type. If you runJira541TestCase.testFluentBeanIntrospectorOnOverriddenSetter
in debugger, you can see that at lineFluentPropertyBeanIntrospector:163
which makes this callthe existing object is replaced with the copied by the same name.
Sorry for missing this initially, I just got this insight. But I'd like to notice that initial fix (merged yesterday) makes the situation much better than it was.
I hope you will find time to check this carefully in the debugger and see the specific how the fluent setters logic is working.
Thanks for your attention and trust.
Hint: to reproduce the failure, run
testFluentBeanIntrospectorOnOverriddenSetterConcurrent
(not the full test class, but a single method) with an old implementation (I mean currentmaster
) ofFluentPropertyBeanIntrospector
several times. Eventually it will fail with:One more reason why we need this change: library should not call
PropertyDescriptor.setWriteMethod(m);
for a descriptor instance which is stored in a static cache, because this cached instance can potentially be reused by other frameworks (like Tomcat or JEE frameworks) when analyzing bean contracts. After callingsetWriteMethod
the behavior in other frameworks may easily change and rely on random factor - lead to flaky issues. Overall, I believe it was a JDK design mistake to makePropertyDescriptor
mutable and statically cacheable at the same time 😢