Skip to content

Commit

Permalink
ArC - use reflection fallback for PreDestroy callbacks if needed
Browse files Browse the repository at this point in the history
- resolves quarkusio#30636
  • Loading branch information
mkouba committed Jan 27, 2023
1 parent 232980d commit a94ad69
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ Collection<Resource> generateSyntheticBean(BeanInfo bean) {
implementGetIdentifier(bean, beanCreator);
implementSupplierGet(beanCreator);
if (bean.hasDestroyLogic()) {
implementDestroy(bean, beanCreator, providerType, Collections.emptyMap(), isApplicationClass, baseName);
implementDestroy(bean, beanCreator, providerType, Collections.emptyMap(), isApplicationClass, baseName,
targetPackage);
}
implementCreate(classOutput, beanCreator, bean, providerType, baseName,
Collections.emptyMap(), Collections.emptyMap(),
Expand Down Expand Up @@ -363,7 +364,7 @@ Collection<Resource> generateClassBean(BeanInfo bean, ClassInfo beanClass) {
implementSupplierGet(beanCreator);
if (bean.hasDestroyLogic()) {
implementDestroy(bean, beanCreator, providerType, injectionPointToProviderSupplierField, isApplicationClass,
baseName);
baseName, targetPackage);
}
implementCreate(classOutput, beanCreator, bean, providerType, baseName,
injectionPointToProviderSupplierField,
Expand Down Expand Up @@ -448,7 +449,8 @@ Collection<Resource> generateProducerMethodBean(BeanInfo bean, MethodInfo produc
implementGetIdentifier(bean, beanCreator);
implementSupplierGet(beanCreator);
if (bean.hasDestroyLogic()) {
implementDestroy(bean, beanCreator, providerType, injectionPointToProviderField, isApplicationClass, baseName);
implementDestroy(bean, beanCreator, providerType, injectionPointToProviderField, isApplicationClass, baseName,
targetPackage);
}
implementCreate(classOutput, beanCreator, bean, providerType, baseName,
injectionPointToProviderField,
Expand Down Expand Up @@ -529,7 +531,7 @@ Collection<Resource> generateProducerFieldBean(BeanInfo bean, FieldInfo producer
implementGetIdentifier(bean, beanCreator);
implementSupplierGet(beanCreator);
if (bean.hasDestroyLogic()) {
implementDestroy(bean, beanCreator, providerType, null, isApplicationClass, baseName);
implementDestroy(bean, beanCreator, providerType, null, isApplicationClass, baseName, targetPackage);
}
implementCreate(classOutput, beanCreator, bean, providerType, baseName,
Collections.emptyMap(), Collections.emptyMap(),
Expand Down Expand Up @@ -617,7 +619,7 @@ protected void createConstructor(ClassOutput classOutput, ClassCreator beanCreat
initConstructor(classOutput, beanCreator, bean, injectionPointToProviderField, interceptorToProviderField,
decoratorToProviderSupplierField,
annotationLiterals, reflectionRegistration)
.returnValue(null);
.returnValue(null);
}

protected MethodCreator initConstructor(ClassOutput classOutput, ClassCreator beanCreator, BeanInfo bean,
Expand Down Expand Up @@ -795,7 +797,8 @@ protected MethodCreator initConstructor(ClassOutput classOutput, ClassCreator be
}

protected void implementDestroy(BeanInfo bean, ClassCreator beanCreator, ProviderType providerType,
Map<InjectionPointInfo, String> injectionPointToProviderField, boolean isApplicationClass, String baseName) {
Map<InjectionPointInfo, String> injectionPointToProviderField, boolean isApplicationClass, String baseName,
String targetPackage) {

MethodCreator destroy = beanCreator
.getMethodCreator("destroy", void.class, providerType.descriptorName(), CreationalContext.class)
Expand All @@ -817,9 +820,11 @@ protected void implementDestroy(BeanInfo bean, ClassCreator beanCreator, Provide
DotNames.PRE_DESTROY,
bean.getDeployment().getBeanArchiveIndex());
for (MethodInfo callback : preDestroyCallbacks) {
if (Modifier.isPrivate(callback.flags())) {
privateMembers.add(isApplicationClass, String.format("@PreDestroy callback %s#%s()",
callback.declaringClass().name(), callback.name()));
if (isReflectionFallbackNeeded(callback, targetPackage)) {
if (Modifier.isPrivate(callback.flags())) {
privateMembers.add(isApplicationClass, String.format("@PreDestroy callback %s#%s()",
callback.declaringClass().name(), callback.name()));
}
reflectionRegistration.registerMethod(callback);
destroy.invokeStaticMethod(MethodDescriptors.REFLECTIONS_INVOKE_METHOD,
destroy.loadClass(callback.declaringClass().name().toString()),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package io.quarkus.arc.test.interceptors.postConstruct.inherited;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class OriginalBean {

public static int TIMES_INVOKED = 0;
static final AtomicBoolean POST_CONSTRUCT = new AtomicBoolean();
static final AtomicBoolean PRE_DESTROY = new AtomicBoolean();

// package private, not visible from AlternativeBean without reflection access
@PostConstruct
void postConstruct() {
TIMES_INVOKED++;
POST_CONSTRUCT.set(true);
}

@PreDestroy
void preDestroy() {
PRE_DESTROY.set(true);
}

public String ping() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.quarkus.arc.test.interceptors.postConstruct.inherited;

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

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

import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.arc.test.ArcTestContainer;
import io.quarkus.arc.test.interceptors.postConstruct.inherited.subpackage.AlternativeBean;

public class PackagePrivateCallbackInheritanceTest {

@RegisterExtension
public ArcTestContainer container = new ArcTestContainer(AlternativeBean.class, OriginalBean.class);

@Test
public void testCallbacks() {
ArcContainer container = Arc.container();
InstanceHandle<OriginalBean> origBeanInstance = container.instance(OriginalBean.class);
InstanceHandle<AlternativeBean> alternativeBeanInstance = container.instance(AlternativeBean.class);

assertTrue(origBeanInstance.isAvailable());
assertTrue(alternativeBeanInstance.isAvailable());

// AlternativeBean overrides the OriginalBean
assertEquals(origBeanInstance.getBean(), alternativeBeanInstance.getBean());
assertEquals(AlternativeBean.class.getSimpleName(), alternativeBeanInstance.get().ping());
assertTrue(origBeanInstance.get().ping().equals(alternativeBeanInstance.get().ping()));

// post construct should be invoked via during creation of AlternativeBean even though it's pack-private
assertTrue(OriginalBean.POST_CONSTRUCT.get());

alternativeBeanInstance.destroy();

// pre destroy should be invoked even though it's package-private and AlternativeBean lives in a different package
assertTrue(OriginalBean.PRE_DESTROY.get());
}
}

This file was deleted.

0 comments on commit a94ad69

Please sign in to comment.