Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WELD-2776 manually registered extensions in Weld SE should reside in synthetic bean archive #2909

Merged
merged 2 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1057,11 +1057,13 @@ beanDefiningAnnotations, isEnabled(Jandex.DISABLE_JANDEX_DISCOVERY_STRATEGY, fal
}

if (isEnabled(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, true)) {
deployment = new WeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions);
// use special impl of WeldDeployment to ensure manually registered extensions land in synth. archives.
deployment = createWeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions);
CommonLogger.LOG.archiveIsolationEnabled();
} else {
Set<WeldBeanDeploymentArchive> flatDeployment = new HashSet<WeldBeanDeploymentArchive>();
flatDeployment.add(WeldBeanDeploymentArchive.merge(bootstrap, beanDeploymentArchives));
// there's only one archive, no need to use #createWeldDeployment
deployment = new WeldDeployment(resourceLoader, bootstrap, flatDeployment, extensions);
CommonLogger.LOG.archiveIsolationDisabled();
}
Expand All @@ -1073,6 +1075,32 @@ beanDefiningAnnotations, isEnabled(Jandex.DISABLE_JANDEX_DISCOVERY_STRATEGY, fal
return deployment;
}

/**
* Create an anonymous impl of {@link WeldDeployment} overriding its {@link WeldDeployment#loadBeanDeploymentArchive(Class)}
* method.
*
* This is used by Weld SE in other than flat deployment mode to ensure that manually registered extensions land in the
* synthetic bean archive.
*/
private WeldDeployment createWeldDeployment(ResourceLoader resourceLoader, CDI11Bootstrap bootstrap,
Set<WeldBeanDeploymentArchive> beanDeploymentArchives, Iterable<Metadata<Extension>> extensions) {
return new WeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions) {
@Override
public BeanDeploymentArchive loadBeanDeploymentArchive(Class<?> beanClass) {
if (isSyntheticBeanArchiveRequired()
&& Weld.this.extensions.stream().anyMatch(ext -> ext.getValue().getClass().equals(beanClass)
&& ext.getLocation().startsWith(Weld.SYNTHETIC_LOCATION_PREFIX))) {
for (BeanDeploymentArchive bda : getBeanDeploymentArchives()) {
if (bda.getId().equals(WeldDeployment.SYNTHETIC_BDA_ID)) {
return bda;
}
}
}
return super.loadBeanDeploymentArchive(beanClass);
}
};
}

/**
* Utility method allowing managed instances of beans to provide entry points for non-managed beans (such as
* {@link WeldContainer}). Should only called once
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.jboss.weld.environment.se.test.synthethic.extension;

import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanAttributes;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.InjectionTargetFactory;

public class AfterBeanDiscoveryAddFooInjectedExtension implements Extension {
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
AnnotatedType<FooInjected> annotatedType = beanManager.createAnnotatedType(FooInjected.class);
BeanAttributes<FooInjected> beanAttributes = beanManager.createBeanAttributes(annotatedType);
InjectionTargetFactory<FooInjected> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
Bean<FooInjected> bean = beanManager.createBean(beanAttributes, FooInjected.class, injectionTargetFactory);
afterBeanDiscovery.addBean(bean);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.jboss.weld.environment.se.test.synthethic.extension;

import static org.junit.Assert.assertEquals;

import java.util.function.Consumer;

import jakarta.enterprise.inject.se.SeContainer;

import org.jboss.arquillian.container.se.api.ClassPath;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.BeanArchive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.test.util.Utils;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* This test is tailored to pass only when manually registered SE extension resides in a synthetic bean archive
* due to per-archive alternative enablement.
*
* See https://issues.redhat.com/browse/WELD-2776 and the linked PR.
*/
@RunWith(Arquillian.class)
public class ExtensionInSyntheticArchiveTest {

@Deployment
public static Archive<?> createTestArchive() {
return ClassPath.builder()
.add(ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(ExtensionInSyntheticArchiveTest.class))
.addPackage(ExtensionInSyntheticArchiveTest.class.getPackage()))
.build();
}

@Test
public void testAlternatives() {
// given Foo and enabled FooAlternative alternative for Foo, injection should work similarly
// with respect to selecting the alternative FooAlternative for Foo, in both following cases:

// added with addBeanClass to Weld (presumably covered elsewhere serves here to compare)
testAlternatives(weld -> weld.addBeanClass(FooInjected.class));
// added in an extension with @Observes AfterBeanDiscovery
testAlternatives(weld -> weld.addExtension(new AfterBeanDiscoveryAddFooInjectedExtension()));
}

void testAlternatives(Consumer<Weld> weldModifier) {
Weld weld = new Weld().disableDiscovery();
weld.addBeanClass(Foo.class);
weld.addBeanClass(FooAlternative.class);
weld.addAlternative(FooAlternative.class);

weldModifier.accept(weld);

try (SeContainer container = weld.initialize()) {
FooInjected fooInjected = container.select(FooInjected.class).get();
assertEquals(FooAlternative.class.getSimpleName(), fooInjected.getFoo().tellMyType());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.jboss.weld.environment.se.test.synthethic.extension;

public class Foo {
public String tellMyType() {
return getClass().getSimpleName();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.jboss.weld.environment.se.test.synthethic.extension;

import jakarta.enterprise.inject.Alternative;

@Alternative
public class FooAlternative extends Foo {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.jboss.weld.environment.se.test.synthethic.extension;

import jakarta.inject.Inject;

public class FooInjected {
@Inject
Foo foo;

Foo getFoo() {
return foo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ public ExtensionBeanDeployer deployBeans() {
private <E extends Extension> void deployBean(Metadata<E> extension, ClassTransformer classTransformer) {
// Locate the BeanDeployment for this extension
BeanDeployment beanDeployment = DeploymentStructures.getOrCreateBeanDeployment(deployment, beanManager, bdaMapping,
contexts, extension.getValue()
.getClass());
contexts, extension.getValue().getClass());

// Do not register synthetic extension as a bean, only register container lifecycle observer methods
if (extension.getValue() instanceof SyntheticExtension) {
Expand Down