done with https://issues.apache.org/jira/browse/OWB-1344

thanks again Vicente for the precise analysis.

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> |  Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>


Le mer. 29 juil. 2020 à 12:48, vicente Rossello <[email protected]>
a écrit :

> Your change is good, I did the same thing without the computeIfAbsent, I
> prefer yours, simpler
>
> On Wed, Jul 29, 2020 at 12:29 PM Romain Manni-Bucau <[email protected]>
> wrote:
>
>> Oki, it is
>> https://github.com/apache/tomee/blob/8f6bd834a37a8745331c6580c458813e713db92c/container/openejb-core/src/main/java/org/apache/openejb/cdi/transactional/InterceptorBase.java#L92
>>  which
>> is really a runtime call and I think the original author wanted to keep it
>> lazy since it is only about the error case (;)).
>> Do you have another fix than the concurrent map one or should I push it
>> as this - also happy to go through a PR if you have something handy?
>>
>> Romain Manni-Bucau
>> @rmannibucau <https://twitter.com/rmannibucau> |  Blog
>> <https://rmannibucau.metawerx.net/> | Old Blog
>> <http://rmannibucau.wordpress.com> | Github
>> <https://github.com/rmannibucau> | LinkedIn
>> <https://www.linkedin.com/in/rmannibucau> | Book
>> <https://www.packtpub.com/application-development/java-ee-8-high-performance>
>>
>>
>> Le mer. 29 juil. 2020 à 11:46, Vicente Rossello <[email protected]>
>> a écrit :
>>
>>> Hi, I did this change (similar) in our build yesterday and everything
>>> works fine.
>>>
>>> The whole stacktrace is:
>>>
>>> java.util.concurrent.ExecutionException: java.lang.RuntimeException: 
>>> java.lang.NullPointerException: Cannot invoke 
>>> "java.util.Optional.isPresent()" because "repeatableMethod" is null
>>>     at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
>>>     at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:205)
>>>     at org.apache.openejb.threads.future.CUFuture.get(CUFuture.java:60)
>>>     at 
>>> com.infratr2.interceptor.async.FutureDelegator.get(FutureDelegator.java:23)
>>>     at 
>>> com.tr2.test.TestDataRepository.saveConcurrentDatasheets(TestDataRepository.java:232)
>>>     at 
>>> com.tr2.test.TestDataRepository$$OwbInterceptProxy0.saveConcurrentDatasheets(com/tr2/test/TestDataRepository.java)
>>>     at 
>>> com.tr2.test.TestDataRepository$$OwbNormalScopeProxy0.saveConcurrentDatasheets(com/tr2/test/TestDataRepository.java)
>>>     at 
>>> com.tr2.web.business.HotelDataSheetServiceIT.save_concurrent_hoteldatasheets(HotelDataSheetServiceIT.java:40)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native 
>>> Method)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>>     at 
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>     at 
>>> org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
>>>     at 
>>> org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
>>>     at 
>>> org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
>>>     at 
>>> org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
>>>     at 
>>> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
>>>     at 
>>> org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
>>>     at 
>>> org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
>>>     at 
>>> org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
>>>     at 
>>> org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
>>>     at 
>>> org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
>>>     at 
>>> org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
>>>     at 
>>> org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
>>>     at 
>>> org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
>>>     at 
>>> org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
>>>     at 
>>> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
>>>     at 
>>> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
>>>     at 
>>> org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:115)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.executeNonConcurrentTasks(ForkJoinPoolHierarchicalTestExecutorService.java:141)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:121)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
>>>     at 
>>> org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:171)
>>>     at 
>>> java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:189)
>>>     at 
>>> java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
>>>     at 
>>> java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016)
>>>     at 
>>> java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665)
>>>     at 
>>> java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598)
>>>     at 
>>> java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
>>> Caused by: java.lang.RuntimeException: java.lang.NullPointerException: 
>>> Cannot invoke "java.util.Optional.isPresent()" because "repeatableMethod" 
>>> is null
>>>     at 
>>> org.apache.webbeans.portable.AnnotatedElementFactory.newAnnotatedType(AnnotatedElementFactory.java:204)
>>>     at 
>>> org.apache.webbeans.container.BeanManagerImpl.createAnnotatedType(BeanManagerImpl.java:585)
>>>     at 
>>> org.apache.webbeans.container.InjectableBeanManager.createAnnotatedType(InjectableBeanManager.java:91)
>>>     at 
>>> org.apache.openejb.cdi.transactional.InterceptorBase.intercept(InterceptorBase.java:92)
>>>     at 
>>> org.apache.openejb.cdi.transactional.RequiredInterceptor.intercept(RequiredInterceptor.java:35)
>>>     at jdk.internal.reflect.GeneratedMethodAccessor125.invoke(Unknown 
>>> Source)
>>>     at 
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>     at 
>>> org.apache.webbeans.component.InterceptorBean.intercept(InterceptorBean.java:136)
>>>     at 
>>> org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:65)
>>>     at 
>>> org.apache.webbeans.intercept.DefaultInterceptorHandler.invoke(DefaultInterceptorHandler.java:139)
>>>     at 
>>> com.tr2.engine.business.HotelDataSheetRepository$$OwbInterceptProxy0.save(com/tr2/engine/business/HotelDataSheetRepository.java)
>>>     at 
>>> com.tr2.engine.business.HotelDataSheetRepository$$OwbNormalScopeProxy0.save(com/tr2/engine/business/HotelDataSheetRepository.java)
>>>     at 
>>> com.tr2.engine.HotelDataSheetService.saveDataSheet(HotelDataSheetService.java:44)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native 
>>> Method)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>>     at 
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>     at 
>>> org.apache.webbeans.intercept.AbstractInvocationContext.directProceed(AbstractInvocationContext.java:113)
>>>     at 
>>> org.apache.webbeans.intercept.AbstractInvocationContext.proceed(AbstractInvocationContext.java:106)
>>>     at 
>>> org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:78)
>>>     at 
>>> org.apache.openejb.cdi.transactional.InterceptorBase.intercept(InterceptorBase.java:67)
>>>     at 
>>> org.apache.openejb.cdi.transactional.RequiredInterceptor.intercept(RequiredInterceptor.java:35)
>>>     at jdk.internal.reflect.GeneratedMethodAccessor125.invoke(Unknown 
>>> Source)
>>>     at 
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>     at 
>>> org.apache.webbeans.component.InterceptorBean.intercept(InterceptorBean.java:136)
>>>     at 
>>> org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:65)
>>>     at 
>>> org.apache.webbeans.intercept.DefaultInterceptorHandler.invoke(DefaultInterceptorHandler.java:139)
>>>     at 
>>> com.tr2.engine.HotelDataSheetService$$OwbInterceptProxy0.saveDataSheet(com/tr2/engine/HotelDataSheetService.java)
>>>     at 
>>> com.tr2.engine.HotelDataSheetService$$OwbNormalScopeProxy0.saveDataSheet(com/tr2/engine/HotelDataSheetService.java)
>>>     at 
>>> com.tr2.test.TestDataRepository.saveDatasheet(TestDataRepository.java:245)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native 
>>> Method)
>>>     at 
>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>>     at 
>>> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>>     at java.base/java.lang.reflect.Method.invoke(Method.java:564)
>>>     at 
>>> org.apache.webbeans.intercept.AbstractInvocationContext.directProceed(AbstractInvocationContext.java:113)
>>>     at 
>>> org.apache.webbeans.intercept.AbstractInvocationContext.proceed(AbstractInvocationContext.java:106)
>>>     at 
>>> org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:78)
>>>     at 
>>> com.tr2.engine.base.monitoring.JavaMelodyUtil.lambda$intercept$1(JavaMelodyUtil.java:91)
>>>     at 
>>> com.tr2.engine.base.monitoring.JavaMelodyUtil.intercept(JavaMelodyUtil.java:54)
>>>     at 
>>> com.tr2.engine.base.monitoring.JavaMelodyUtil.intercept(JavaMelodyUtil.java:89)
>>>     at 
>>> com.tr2.engine.base.monitoring.JavaMelodyUtil.interceptAsync(JavaMelodyUtil.java:103)
>>>     at 
>>> com.infratr2.interceptor.async.AsyncInterceptor.asyncExecution(AsyncInterceptor.java:67)
>>>     at 
>>> com.infratr2.interceptor.async.AsyncInterceptor.lambda$aroundInvoke$0(AsyncInterceptor.java:47)
>>>     at org.apache.openejb.threads.task.CUTask.invoke(CUTask.java:100)
>>>     at org.apache.openejb.threads.task.CUCallable.call(CUCallable.java:31)
>>>     at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
>>>     at 
>>> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
>>>     at 
>>> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
>>>     at java.base/java.lang.Thread.run(Thread.java:832)
>>> Caused by: java.lang.NullPointerException: Cannot invoke 
>>> "java.util.Optional.isPresent()" because "repeatableMethod" is null
>>>     at 
>>> org.apache.webbeans.portable.AbstractAnnotated.buildRepeatableAnnotations(AbstractAnnotated.java:107)
>>>     at 
>>> org.apache.webbeans.portable.AbstractAnnotated.setAnnotations(AbstractAnnotated.java:166)
>>>     at 
>>> org.apache.webbeans.portable.AnnotatedTypeImpl.<init>(AnnotatedTypeImpl.java:76)
>>>     at 
>>> org.apache.webbeans.portable.AnnotatedElementFactory.newAnnotatedType(AnnotatedElementFactory.java:183)
>>>     ... 50 more
>>>
>>>
>>> The test is an application composer with CDI and jpa enabled.
>>>
>>>
>>>
>>> On Wed, Jul 29, 2020 at 8:54 AM Romain Manni-Bucau <
>>> [email protected]> wrote:
>>>
>>>> Reviewed a bit more this part and think we can just drop the 2
>>>> structure state to only use the concurrent map we already have, the
>>>> computeIfAbsent overhead will be negligible compared to the simple contains
>>>> and it will solve by construction the locking issue:
>>>>
>>>> diff --git
>>>> a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
>>>> b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
>>>> index 24033f4ec..b5442c446 100644
>>>> ---
>>>> a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
>>>> +++
>>>> b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
>>>> @@ -62,7 +62,7 @@ import java.util.Map;
>>>>  import java.util.Optional;
>>>>  import java.util.Set;
>>>>  import java.util.concurrent.ConcurrentHashMap;
>>>> -import java.util.concurrent.CopyOnWriteArraySet;
>>>> +import java.util.concurrent.ConcurrentMap;
>>>>
>>>>  /**
>>>>   * Manages annotation usage by classes in this application.
>>>> @@ -74,8 +74,7 @@ public final class AnnotationManager
>>>>      private Map<Class<? extends Annotation>, Boolean>
>>>> checkedStereotypeAnnotations =
>>>>          new ConcurrentHashMap<>();
>>>>
>>>> -    private CopyOnWriteArraySet<Class<?>> repeatableMethodCheckedTypes
>>>> = new CopyOnWriteArraySet<>();
>>>> -    private Map<Class<?>, Optional<Method>> repeatableMethodCache =
>>>> new ConcurrentHashMap<>();
>>>> +    private ConcurrentMap<Class<?>, Optional<Method>>
>>>> repeatableMethodCache = new ConcurrentHashMap<>();
>>>>
>>>>      private final BeanManagerImpl beanManagerImpl;
>>>>      private final WebBeansContext webBeansContext;
>>>> @@ -938,23 +937,12 @@ public final class AnnotationManager
>>>>
>>>>      public void clearCaches()
>>>>      {
>>>> -        repeatableMethodCheckedTypes.clear();
>>>>          repeatableMethodCache.clear();
>>>>      }
>>>>
>>>>      public Optional<Method> getRepeatableMethod(Class<?> type)
>>>>      {
>>>> -        if (repeatableMethodCheckedTypes.contains(type))
>>>> -        {
>>>> -            return repeatableMethodCache.get(type);
>>>> -        }
>>>> -
>>>> -        Optional<Method> method =
>>>> Optional.ofNullable(resolveRepeatableMethod(type));
>>>> -
>>>> -        repeatableMethodCheckedTypes.add(type);
>>>> -        repeatableMethodCache.put(type, method); // don't put null
>>>> here!
>>>> -
>>>> -        return method;
>>>> +        return repeatableMethodCache.computeIfAbsent(type, it ->
>>>> Optional.ofNullable(resolveRepeatableMethod(it)));
>>>>      }
>>>>
>>>>      protected Method resolveRepeatableMethod(Class<?> type)
>>>>
>>>>
>>>> still needs the stack to validate the hypothesis but even if it does
>>>> not fix the original issue it looks better in terms of impl, wdyt?
>>>> Romain Manni-Bucau
>>>> @rmannibucau <https://twitter.com/rmannibucau> |  Blog
>>>> <https://rmannibucau.metawerx.net/> | Old Blog
>>>> <http://rmannibucau.wordpress.com> | Github
>>>> <https://github.com/rmannibucau> | LinkedIn
>>>> <https://www.linkedin.com/in/rmannibucau> | Book
>>>> <https://www.packtpub.com/application-development/java-ee-8-high-performance>
>>>>
>>>>
>>>> Le mar. 28 juil. 2020 à 21:39, Romain Manni-Bucau <
>>>> [email protected]> a écrit :
>>>>
>>>>> Hi
>>>>>
>>>>> It is a startup method normally so synchro should be useless until you
>>>>> abuse of createAnnotatedType at runtime - which can be another library bug
>>>>> ;).
>>>>>
>>>>> Would be great to have more of the stacktrace to check it - which
>>>>> means we would lock only this specific runtime api and not startup ones 
>>>>> (we
>>>>> have that state and there are different methods calling it).
>>>>>
>>>>> Hope it makes sense
>>>>>
>>>>> Le mar. 28 juil. 2020 à 11:20, Vicente Rossello <
>>>>> [email protected]> a écrit :
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> In our CI server I can see an occasional NPE:
>>>>>>
>>>>>> Caused by: java.lang.NullPointerException: Cannot invoke 
>>>>>> "java.util.Optional.isPresent()" because "repeatableMethod" is null
>>>>>>  at 
>>>>>> org.apache.webbeans.portable.AbstractAnnotated.buildRepeatableAnnotations(AbstractAnnotated.java:107)
>>>>>>  at 
>>>>>> org.apache.webbeans.portable.AbstractAnnotated.setAnnotations(AbstractAnnotated.java:166)
>>>>>>  at 
>>>>>> org.apache.webbeans.portable.AnnotatedTypeImpl.<init>(AnnotatedTypeImpl.java:76)
>>>>>>  at 
>>>>>> org.apache.webbeans.portable.AnnotatedElementFactory.newAnnotatedType(AnnotatedElementFactory.java:183)
>>>>>>
>>>>>>
>>>>>> (It's a test that spans some threads and persists some concurrent data).
>>>>>>
>>>>>>
>>>>>> It happens once a day at most, and I think it happens lately since I 
>>>>>> upgraded to 2.0.16 or 17 (I have no idea why because this hasn't changed 
>>>>>> in a while, I can't confirm this)
>>>>>>
>>>>>>
>>>>>> I've been unable to reproduce it locally neither.
>>>>>>
>>>>>>
>>>>>> The thing is that looking at AnnotationManager.java:
>>>>>>
>>>>>>
>>>>>> public Optional<Method> getRepeatableMethod(Class<?> type)
>>>>>> {
>>>>>>     if (repeatableMethodCheckedTypes.contains(type))
>>>>>>     {
>>>>>>         return repeatableMethodCache.get(type);
>>>>>>     }
>>>>>>
>>>>>>     Optional<Method> method = 
>>>>>> Optional.ofNullable(resolveRepeatableMethod(type));
>>>>>>
>>>>>>     repeatableMethodCheckedTypes.add(type);
>>>>>>     repeatableMethodCache.put(type, method); // don't put null here!
>>>>>>
>>>>>>     return method;
>>>>>> }
>>>>>>
>>>>>>
>>>>>> The repeatableMethodCheckedTypes can have the value and the 
>>>>>> repeatableMethodCache empty at the same time, which I guess is what's 
>>>>>> happening here.
>>>>>>
>>>>>>
>>>>>> A solution can be to synchronize the add and put, or the 
>>>>>> repeatableMethodCheckedTypes can be removed (it's not used anywhere 
>>>>>> else, I guess it's there for performance reasons?)
>>>>>>
>>>>>> WDYT?
>>>>>>
>>>>>>

Reply via email to