Skip to content

Commit

Permalink
ArC - fix CreationalContext handling when used directly with BeanManager
Browse files Browse the repository at this point in the history
Co-authored-by: Ladicek <[email protected]>
  • Loading branch information
mkouba and Ladicek committed Apr 27, 2023
1 parent 0baea80 commit 2f95160
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,21 @@ private <T> InstanceHandle<T> instanceHandle(Type type, Annotation... qualifiers

static <T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, CreationalContextImpl<T> parentContext,
boolean resetCurrentInjectionPoint, Consumer<T> destroyLogic) {
return beanInstanceHandle(bean, parentContext, resetCurrentInjectionPoint, destroyLogic, false);
}

static <T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, CreationalContextImpl<T> parentContext,
boolean resetCurrentInjectionPoint, Consumer<T> destroyLogic, boolean useParentCreationalContextDirectly) {
if (bean != null) {
if (parentContext == null && Dependent.class.equals(bean.getScope())) {
parentContext = new CreationalContextImpl<>(null);
}
CreationalContextImpl<T> creationalContext = parentContext != null ? parentContext.child(bean)
: new CreationalContextImpl<>(bean);
CreationalContextImpl<T> creationalContext;
if (parentContext != null) {
creationalContext = useParentCreationalContextDirectly ? parentContext : parentContext.child(bean);
} else {
creationalContext = new CreationalContextImpl<>(bean);
}
InjectionPoint prev = null;
if (resetCurrentInjectionPoint) {
prev = InjectionPointProvider.set(CurrentInjectionPointProvider.EMPTY);
Expand All @@ -494,7 +503,7 @@ static <T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, Creation
}
}

<T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, CreationalContextImpl<T> parentContext) {
static <T> InstanceHandle<T> beanInstanceHandle(InjectableBean<T> bean, CreationalContextImpl<T> parentContext) {
return beanInstanceHandle(bean, parentContext, true, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx
+ "; its bean types are: " + bean.getTypes());
}
if (bean instanceof InjectableBean && ctx instanceof CreationalContextImpl) {
return ArcContainerImpl.instance().beanInstanceHandle((InjectableBean) bean, (CreationalContextImpl) ctx).get();
return ArcContainerImpl.beanInstanceHandle((InjectableBean) bean, (CreationalContextImpl) ctx, true, null, true)
.get();
}
throw new IllegalArgumentException(
"Arguments must be instances of " + InjectableBean.class + " and " + CreationalContextImpl.class + ": \nbean: "
Expand All @@ -80,7 +81,7 @@ public Object getInjectableReference(InjectionPoint ij, CreationalContext<?> ctx
InjectableBean<?> bean = (InjectableBean<?>) resolve(beans);
InjectionPoint prev = InjectionPointProvider.set(ij);
try {
return ArcContainerImpl.beanInstanceHandle(bean, (CreationalContextImpl) ctx, false, null).get();
return ArcContainerImpl.beanInstanceHandle(bean, (CreationalContextImpl) ctx, false, null, true).get();
} finally {
InjectionPointProvider.set(prev);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@
<exclude name="testInstanceUsedForProducerMethodNotShared"/>
<exclude name="testContextIsActive"/>
<exclude name="testContextScopeType"/>
<!-- https://github.com/jakartaee/cdi-tck/issues/454 -->
<exclude name="testDependentScopedInterceptorsAreDependentObjectsOfBean"></exclude>
</methods>
</class>
<class name="org.jboss.cdi.tck.tests.lookup.manager.ManagerTest">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package io.quarkus.arc.test.bean.destroy;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import jakarta.annotation.PreDestroy;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.inject.Inject;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InterceptorBinding;
import jakarta.interceptor.InvocationContext;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.Arc;
import io.quarkus.arc.test.ArcTestContainer;

public class DependentPreDestroyOnlyCalledOnceTest {
@RegisterExtension
ArcTestContainer container = new ArcTestContainer(MyDependency.class, MyBean.class, MyInterceptedBean.class,
MyInterceptorBinding.class, MyInterceptor.class);

@BeforeEach
public void setUp() {
MyDependency.preDestroy = 0;
MyBean.preDestroy = 0;
MyInterceptedBean.preDestroy = 0;
}

@SuppressWarnings("unchecked")
@Test
public void preDestroyOnBeanOnly() {
BeanManager beanManager = Arc.container().beanManager();
Bean<MyBean> bean = (Bean<MyBean>) beanManager.resolve(beanManager.getBeans(MyBean.class));
CreationalContext<MyBean> ctx = beanManager.createCreationalContext(bean);
MyBean instance = (MyBean) beanManager.getReference(bean, MyBean.class, ctx);
bean.destroy(instance, ctx);

assertEquals(1, MyDependency.preDestroy);
assertEquals(1, MyBean.preDestroy);
}

@SuppressWarnings("unchecked")
@Test
public void preDestroyOnBeanAndInterceptor() {
BeanManager beanManager = Arc.container().beanManager();
Bean<MyInterceptedBean> bean = (Bean<MyInterceptedBean>) beanManager.resolve(
beanManager.getBeans(MyInterceptedBean.class));
CreationalContext<MyInterceptedBean> ctx = beanManager.createCreationalContext(bean);
MyInterceptedBean instance = (MyInterceptedBean) beanManager.getReference(bean, MyInterceptedBean.class, ctx);
bean.destroy(instance, ctx);

assertEquals(1, MyDependency.preDestroy);
assertEquals(1, MyInterceptedBean.preDestroy);
assertEquals(1, MyInterceptor.preDestroy);
}

@Dependent
static class MyDependency {
static int preDestroy = 0;

@PreDestroy
void destroy() {
preDestroy++;
}
}

@Dependent
static class MyBean {
static int preDestroy = 0;

@Inject
MyDependency dependency;

@PreDestroy
void destroy() {
preDestroy++;
}
}

@Dependent
@MyInterceptorBinding
static class MyInterceptedBean {
static int preDestroy = 0;

@Inject
MyDependency dependency;

@PreDestroy
void destroy() {
preDestroy++;
}
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
@interface MyInterceptorBinding {
}

@MyInterceptorBinding
@Interceptor
@Priority(1)
static class MyInterceptor {
static int preDestroy = 0;

@PreDestroy
void preDestroy(InvocationContext ctx) throws Exception {
preDestroy++;
ctx.proceed();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void testGetReference() {
});
Legacy legacy = (Legacy) beanManager.getReference(legacyBean, Legacy.class, ctx);
assertNotNull(legacy.getBeanManager());
ctx.release();
legacyBean.destroy((AlternativeLegacy) legacy, ctx);
assertTrue(Legacy.DESTROYED.get());
}

Expand Down Expand Up @@ -179,7 +179,6 @@ public Annotated getAnnotated() {
assertNull(injectableReference.injectionPoint.getBean());
}

@SuppressWarnings("serial")
@Test
public void testResolveInterceptors() {
BeanManager beanManager = Arc.container().beanManager();
Expand Down

0 comments on commit 2f95160

Please sign in to comment.