From 800fea33e1703ce373aee875e0362409d2430039 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Thu, 3 Aug 2023 16:28:25 +0200 Subject: [PATCH] WELD-2750 Tweak how parent-child creational contexts are created. Use WeakReference to keep track of destroyed instance. --- .../weld/contexts/CreationalContextImpl.java | 24 ++++++++++++------- .../jboss/weld/manager/BeanManagerImpl.java | 8 ++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/impl/src/main/java/org/jboss/weld/contexts/CreationalContextImpl.java b/impl/src/main/java/org/jboss/weld/contexts/CreationalContextImpl.java index 7bdf2bfe234..854581c7889 100644 --- a/impl/src/main/java/org/jboss/weld/contexts/CreationalContextImpl.java +++ b/impl/src/main/java/org/jboss/weld/contexts/CreationalContextImpl.java @@ -21,12 +21,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import jakarta.enterprise.context.spi.Contextual; import jakarta.enterprise.context.spi.CreationalContext; @@ -62,7 +62,12 @@ public class CreationalContextImpl implements CreationalContext, WeldCreat private final CreationalContextImpl parentCreationalContext; - // Precondition for access when non-null: synchronized (dependentInstances) + /** + * Needs to be always initialized as a Set that managed WeakReferences to avoid cyclic references and leaks. + * Precondition for access when non-null: synchronized (dependentInstances). + * + * @see #initDestroyedIfNeeded() + */ private transient Set> destroyed; private transient List> resourceReferences; @@ -149,9 +154,7 @@ public void release(Contextual contextual, T instance) { private void destroy(ContextualInstance beanInstance) { // Precondition: synchronized (dependentInstances) - if (this.destroyed == null) { - this.destroyed = new HashSet<>(); - } + initDestroyedIfNeeded(); if (this.destroyed.add(beanInstance)) { beanInstance.getContextual().destroy(beanInstance.getInstance(), beanInstance.getCreationalContext()); } @@ -159,9 +162,7 @@ private void destroy(ContextualInstance beanInstance) { private void release(ContextualInstance beanInstance) { // Precondition: synchronized (dependentInstances) - if (this.destroyed == null) { - this.destroyed = new HashSet<>(); - } + initDestroyedIfNeeded(); if (this.destroyed.add(beanInstance)) { CreationalContext cc = beanInstance.getCreationalContext(); if (cc instanceof CreationalContextImpl) { @@ -311,4 +312,11 @@ private Object readResolve() throws ObjectStreamException { } + private void initDestroyedIfNeeded() { + // we need to use WeakReference set so that we avoid cyclic references and memory leaks + if (this.destroyed == null) { + this.destroyed = Collections.newSetFromMap(new WeakHashMap<>()); + } + } + } diff --git a/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java b/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java index d16a6d2a454..2d2903be502 100644 --- a/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java +++ b/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java @@ -777,7 +777,13 @@ public Object getInjectableReference(InjectionPoint injectionPoint, Bean reso } } } - return getReference(resolvedBean, requestedType, creationalContext, delegateInjectionPoint); + // #getReference always creates a child CC and links it to the CC we pass an argument + // This is exactly what we want for dependent beans but all other beans shouldn't have that + if (Dependent.class.equals(resolvedBean.getScope())) { + return getReference(resolvedBean, requestedType, creationalContext, delegateInjectionPoint); + } else { + return getReference(resolvedBean, requestedType, createCreationalContext(null), delegateInjectionPoint); + } } finally { stack.pop();