diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java b/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java index 4887679ff7..7c635afc2f 100644 --- a/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java +++ b/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java @@ -209,11 +209,10 @@ static String getProxyName(String contextId, Class proxiedBeanType, Set proxiedBeanType, Set bean, TypeInfo typeInfo, StringBuilder name) { + return createCompoundProxyName(contextId, bean, typeInfo, name, null); + } + + private static ProxyNameHolder createCompoundProxyName(String contextId, Bean bean, TypeInfo typeInfo, + StringBuilder name, String knownProxyPackage) { String className; - String proxyPackage = null; + String proxyPackage = knownProxyPackage; // we need a sorted collection without repetition, hence LinkedHashSet final Set interfaces = new LinkedHashSet<>(); // for producers, try to determine the most specific class and make sure the proxy starts with the same package and class if (bean != null && bean instanceof AbstractProducerBean) { Class mostSpecificClass = ((AbstractProducerBean) bean).getType(); + // for producers, always override the proxy package proxyPackage = mostSpecificClass.getPackage().getName(); if (mostSpecificClass.getDeclaringClass() != null) { interfaces.add(mostSpecificClass.getDeclaringClass().getSimpleName()); diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/TestProxyCreationForEjbLocalBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/TestProxyCreationForEjbLocalBean.java new file mode 100644 index 0000000000..8b8e6b4874 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/TestProxyCreationForEjbLocalBean.java @@ -0,0 +1,46 @@ +package org.jboss.weld.tests.classDefining.ejb; + +import jakarta.inject.Inject; + +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.test.util.Utils; +import org.jboss.weld.tests.category.Integration; +import org.jboss.weld.tests.classDefining.ejb.ifaces.LocalInterface1; +import org.jboss.weld.tests.classDefining.ejb.impl.StatelessLocalBean; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +@Category(Integration.class) +@RunWith(Arquillian.class) +public class TestProxyCreationForEjbLocalBean { + + @Deployment + public static Archive deploy() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(TestProxyCreationForEjbLocalBean.class)) + .addPackage(TestProxyCreationForEjbLocalBean.class.getPackage()) + .addPackage(StatelessLocalBean.class.getPackage()) + .addPackage(LocalInterface1.class.getPackage()); + } + + @Inject + StatelessLocalBean bean; + + @Test + public void testProxyPackageMatchesTheClass() { + // sanity check of the testing setup + Assert.assertEquals(LocalInterface1.class.getSimpleName(), bean.ping1()); + + // The assertion is based solely on inspecting the proxy format - expected package and first mentioned class + // We cannot rely on verifying that the class can be defined because this runs on WFLY which directly uses + // ClassLoader#defineClass in which case it's a non-issue. The mismatch only shows when using MethodHandles.Lookup + // see https://github.com/jakartaee/platform-tck/issues/1194 for more information + Assert.assertEquals(StatelessLocalBean.class.getPackage(), bean.getClass().getPackage()); + Assert.assertTrue(bean.getClass().getName().startsWith(StatelessLocalBean.class.getName())); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface1.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface1.java new file mode 100644 index 0000000000..61db969f8e --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface1.java @@ -0,0 +1,5 @@ +package org.jboss.weld.tests.classDefining.ejb.ifaces; + +public interface LocalInterface1 { + String ping1(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface2.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface2.java new file mode 100644 index 0000000000..bd11e3e723 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/LocalInterface2.java @@ -0,0 +1,5 @@ +package org.jboss.weld.tests.classDefining.ejb.ifaces; + +public interface LocalInterface2 { + String ping2(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/NotImplementedButDeclaredInterface.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/NotImplementedButDeclaredInterface.java new file mode 100644 index 0000000000..19c714f131 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/ifaces/NotImplementedButDeclaredInterface.java @@ -0,0 +1,8 @@ +package org.jboss.weld.tests.classDefining.ejb.ifaces; + +import jakarta.ejb.Local; + +@Local +public interface NotImplementedButDeclaredInterface extends LocalInterface1 { + String ping3(); +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/impl/StatelessLocalBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/impl/StatelessLocalBean.java new file mode 100644 index 0000000000..6248572716 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/classDefining/ejb/impl/StatelessLocalBean.java @@ -0,0 +1,31 @@ +package org.jboss.weld.tests.classDefining.ejb.impl; + +import jakarta.ejb.Local; +import jakarta.ejb.LocalBean; +import jakarta.ejb.Stateless; + +import org.jboss.weld.tests.classDefining.ejb.ifaces.LocalInterface1; +import org.jboss.weld.tests.classDefining.ejb.ifaces.LocalInterface2; +import org.jboss.weld.tests.classDefining.ejb.ifaces.NotImplementedButDeclaredInterface; + +// NOTE: the bean intentionally declares NotImplementedButDeclaredInterface but does *not* implement it directly +@Stateless +@LocalBean +@Local({ LocalInterface1.class, LocalInterface2.class, + NotImplementedButDeclaredInterface.class }) +public class StatelessLocalBean implements LocalInterface1, LocalInterface2 { + + @Override + public String ping1() { + return LocalInterface1.class.getSimpleName(); + } + + @Override + public String ping2() { + return LocalInterface2.class.getSimpleName(); + } + + public String ping3() { + return NotImplementedButDeclaredInterface.class.getSimpleName(); + } +}