diff --git a/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/AbstractEnhancedAnnotatedCallable.java b/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/AbstractEnhancedAnnotatedCallable.java index 3a267aec74..c30c12dd71 100644 --- a/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/AbstractEnhancedAnnotatedCallable.java +++ b/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/AbstractEnhancedAnnotatedCallable.java @@ -57,7 +57,7 @@ protected static void validateParameterCount(AnnotatedCallable callable) { } if (callable.getParameters().size() != parameterTypes.length) { // For enums, BackedAnnotatedConstructor sets parameters to an empty list, so we shouldn't throw the DefinitionException - Class declaringClass = callable.getDeclaringType().getJavaClass(); + Class declaringClass = callable.getJavaMember().getDeclaringClass(); if (!declaringClass.isEnum() && !declaringClass.isMemberClass()) { throw ReflectionLogger.LOG.incorrectNumberOfAnnotatedParametersMethod(callable.getParameters().size(), callable, callable.getParameters(), Arrays.asList(parameterTypes)); diff --git a/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/EnhancedAnnotatedTypeImpl.java b/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/EnhancedAnnotatedTypeImpl.java index 1a4f2c3847..bda1bc1bba 100644 --- a/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/EnhancedAnnotatedTypeImpl.java +++ b/impl/src/main/java/org/jboss/weld/annotated/enhanced/jlr/EnhancedAnnotatedTypeImpl.java @@ -195,12 +195,12 @@ protected EnhancedAnnotatedTypeImpl(SlimAnnotatedType annotatedType, EnhancedAnnotatedField weldField = EnhancedAnnotatedFieldImpl.of(annotatedField, this, classTransformer); fieldsTemp.add(weldField); - if (annotatedField.getDeclaringType().getJavaClass().equals(javaClass)) { + if (annotatedField.getJavaMember().getDeclaringClass().equals(javaClass)) { declaredFieldsTemp.add(weldField); } for (Annotation annotation : weldField.getAnnotations()) { annotatedFields.put(annotation.annotationType(), weldField); - if (annotatedField.getDeclaringType().getJavaClass().equals(javaClass)) { + if (annotatedField.getJavaMember().getDeclaringClass().equals(javaClass)) { declaredAnnotatedFields.put(annotation.annotationType(), weldField); } } diff --git a/impl/src/main/java/org/jboss/weld/annotated/slim/backed/BackedAnnotatedType.java b/impl/src/main/java/org/jboss/weld/annotated/slim/backed/BackedAnnotatedType.java index 0ace6c7d87..de4de7ccd2 100644 --- a/impl/src/main/java/org/jboss/weld/annotated/slim/backed/BackedAnnotatedType.java +++ b/impl/src/main/java/org/jboss/weld/annotated/slim/backed/BackedAnnotatedType.java @@ -9,6 +9,7 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Objects; @@ -64,13 +65,13 @@ private BackedAnnotatedType(Class rawType, Type baseType, SharedObjectCache s ReflectionCache reflectionCache, String contextId, String bdaId, String suffix) { super(baseType, sharedObjectCache); + this.identifier = AnnotatedTypeIdentifier.forBackedAnnotatedType(contextId, rawType, baseType, bdaId, suffix); this.javaClass = rawType; this.sharedObjectCache = sharedObjectCache; this.reflectionCache = reflectionCache; this.constructors = new BackedAnnotatedConstructors(); this.fields = new BackedAnnotatedFields(); this.methods = new BackedAnnotatedMethods(); - this.identifier = AnnotatedTypeIdentifier.forBackedAnnotatedType(contextId, rawType, baseType, bdaId, suffix); } @Override @@ -186,7 +187,7 @@ protected Set> computeValue() { Class clazz = javaClass; while (clazz != Object.class && clazz != null) { for (Field field : SecurityActions.getDeclaredFields(clazz)) { - fields.add(BackedAnnotatedField.of(field, BackedAnnotatedType.this, sharedObjectCache)); + fields.add(BackedAnnotatedField.of(field, getDeclaringAnnotatedType(field), sharedObjectCache)); } clazz = clazz.getSuperclass(); } @@ -201,7 +202,7 @@ protected Set> computeValue() { Class clazz = javaClass; while (clazz != Object.class && clazz != null) { for (Method method : SecurityActions.getDeclaredMethods(clazz)) { - methods.add(BackedAnnotatedMethod.of(method, BackedAnnotatedType.this, sharedObjectCache)); + methods.add(BackedAnnotatedMethod.of(method, getDeclaringAnnotatedType(method), sharedObjectCache)); } clazz = clazz.getSuperclass(); } @@ -209,7 +210,7 @@ protected Set> computeValue() { for (Class interfaceClazz : Reflections.getInterfaceClosure(javaClass)) { for (Method method : SecurityActions.getDeclaredMethods(interfaceClazz)) { if (Reflections.isDefault(method)) { - methods.add(BackedAnnotatedMethod.of(method, BackedAnnotatedType.this, sharedObjectCache)); + methods.add(BackedAnnotatedMethod.of(method, getDeclaringAnnotatedType(method), sharedObjectCache)); } } } @@ -217,6 +218,16 @@ protected Set> computeValue() { } } + private BackedAnnotatedType getDeclaringAnnotatedType(Member member) { + Class declaringClass = Reflections.> cast(member.getDeclaringClass()); + if (declaringClass.equals(getJavaClass())) { + return cast(this); + } else { + return BackedAnnotatedType.of(declaringClass, sharedObjectCache, reflectionCache, identifier.getSuffix(), + identifier.getBdaId()); + } + } + public ReflectionCache getReflectionCache() { return reflectionCache; } diff --git a/impl/src/main/java/org/jboss/weld/bean/attributes/BeanAttributesFactory.java b/impl/src/main/java/org/jboss/weld/bean/attributes/BeanAttributesFactory.java index df9a27986b..2c645897da 100644 --- a/impl/src/main/java/org/jboss/weld/bean/attributes/BeanAttributesFactory.java +++ b/impl/src/main/java/org/jboss/weld/bean/attributes/BeanAttributesFactory.java @@ -220,7 +220,7 @@ protected boolean initScopeFromStereotype() { Class declaringClass; if (annotated instanceof EnhancedAnnotatedMember) { EnhancedAnnotatedMember member = (EnhancedAnnotatedMember) annotated; - declaringClass = member.getDeclaringType().getJavaClass(); + declaringClass = member.getJavaMember().getDeclaringClass(); stack = "\n at " + Formats.formatAsStackTraceElement(member.getJavaMember()); } else { declaringClass = annotated.getJavaClass(); diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/ObserverMethodConfiguratorImpl.java b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/ObserverMethodConfiguratorImpl.java index 08c44d24f7..0e7a30c0a3 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/ObserverMethodConfiguratorImpl.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/events/configurator/ObserverMethodConfiguratorImpl.java @@ -129,7 +129,7 @@ public ObserverMethodConfigurator read(AnnotatedMethod method) { if (priority != null) { priority(priority.value()); } - beanClass(eventParameter.getDeclaringCallable().getDeclaringType().getJavaClass()); + beanClass(eventParameter.getDeclaringCallable().getJavaMember().getDeclaringClass()); observedType(eventParameter.getBaseType()); qualifiers(Configurators.getQualifiers(eventParameter)); return this; diff --git a/impl/src/main/java/org/jboss/weld/injection/producer/ProducerMethodProducer.java b/impl/src/main/java/org/jboss/weld/injection/producer/ProducerMethodProducer.java index 45d6c4b1c4..a42f28ca76 100644 --- a/impl/src/main/java/org/jboss/weld/injection/producer/ProducerMethodProducer.java +++ b/impl/src/main/java/org/jboss/weld/injection/producer/ProducerMethodProducer.java @@ -60,7 +60,7 @@ public ProducerMethodProducer(EnhancedAnnotatedMethod enhancedAnno super(enhancedAnnotatedMethod, disposalMethod); // Note that for producer method injection points the declaring bean is the producer method itself this.method = InjectionPointFactory.instance().createMethodInjectionPoint(MethodInjectionPointType.PRODUCER, - enhancedAnnotatedMethod, getBean(), enhancedAnnotatedMethod.getDeclaringType().getJavaClass(), null, + enhancedAnnotatedMethod, getBean(), enhancedAnnotatedMethod.getJavaMember().getDeclaringClass(), null, getBeanManager()); checkProducerMethod(enhancedAnnotatedMethod); checkDelegateInjectionPoints(); 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 c7517058fd..ff71fd2112 100644 --- a/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java +++ b/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java @@ -1445,7 +1445,7 @@ public Bean createBean(BeanAttributes attributes, Class beanClas private FieldInjectionPointAttributes createFieldInjectionPoint(AnnotatedField field) { EnhancedAnnotatedField enhancedField = services.get(MemberTransformer.class).loadEnhancedMember(field, getId()); - return InferringFieldInjectionPointAttributes.of(enhancedField, null, field.getDeclaringType().getJavaClass(), this); + return InferringFieldInjectionPointAttributes.of(enhancedField, null, field.getJavaMember().getDeclaringClass(), this); } @Override @@ -1454,7 +1454,7 @@ private FieldInjectionPointAttributes createFieldInjectionPoint(Annota EnhancedAnnotatedParameter enhancedParameter = services.get(MemberTransformer.class) .loadEnhancedParameter(parameter, getId()); return validateInjectionPoint(InferringParameterInjectionPointAttributes.of(enhancedParameter, null, - parameter.getDeclaringCallable().getDeclaringType().getJavaClass(), this)); + parameter.getDeclaringCallable().getJavaMember().getDeclaringClass(), this)); } private T validateInjectionPoint(T injectionPoint) { @@ -1543,13 +1543,13 @@ public WeldInjectionTargetFactory getInjectionTargetFactory(AnnotatedType @Override public FieldProducerFactory getProducerFactory(AnnotatedField field, Bean declaringBean) { - BeanManagerImpl manager = BeanManagerLookupService.lookupBeanManager(field.getDeclaringType().getJavaClass(), this); + BeanManagerImpl manager = BeanManagerLookupService.lookupBeanManager(field.getJavaMember().getDeclaringClass(), this); return new FieldProducerFactory(field, declaringBean, manager); } @Override public MethodProducerFactory getProducerFactory(AnnotatedMethod method, Bean declaringBean) { - BeanManagerImpl manager = BeanManagerLookupService.lookupBeanManager(method.getDeclaringType().getJavaClass(), this); + BeanManagerImpl manager = BeanManagerLookupService.lookupBeanManager(method.getJavaMember().getDeclaringClass(), this); return new MethodProducerFactory(method, declaringBean, manager); } diff --git a/impl/src/main/java/org/jboss/weld/util/reflection/Formats.java b/impl/src/main/java/org/jboss/weld/util/reflection/Formats.java index b65eb7a182..1474912d09 100644 --- a/impl/src/main/java/org/jboss/weld/util/reflection/Formats.java +++ b/impl/src/main/java/org/jboss/weld/util/reflection/Formats.java @@ -616,7 +616,7 @@ public static String formatAnnotatedConstructor(AnnotatedConstructor construc return Formats.formatSimpleClassName(constructor) + " " + Formats.addSpaceIfNeeded(Formats.formatAnnotations(constructor.getAnnotations())) + Formats.addSpaceIfNeeded(Formats.formatModifiers(constructor.getJavaMember().getModifiers())) - + constructor.getDeclaringType().getJavaClass().getName() + + constructor.getJavaMember().getDeclaringClass().getName() + Formats.formatAsFormalParameterList(constructor.getParameters()); } @@ -624,7 +624,7 @@ public static String formatAnnotatedField(AnnotatedField field) { return Formats.formatSimpleClassName(field) + " " + Formats.addSpaceIfNeeded(Formats.formatAnnotations(field.getAnnotations())) + Formats.addSpaceIfNeeded(Formats.formatModifiers(field.getJavaMember().getModifiers())) - + field.getDeclaringType().getJavaClass().getName() + "." + + field.getJavaMember().getDeclaringClass().getName() + "." + field.getJavaMember().getName(); } @@ -632,7 +632,7 @@ public static String formatAnnotatedMethod(AnnotatedMethod method) { return Formats.formatSimpleClassName(method) + " " + Formats.addSpaceIfNeeded(Formats.formatAnnotations(method.getAnnotations())) + Formats.addSpaceIfNeeded(Formats.formatModifiers(method.getJavaMember().getModifiers())) - + method.getDeclaringType().getJavaClass().getName() + "." + + method.getJavaMember().getDeclaringClass().getName() + "." + method.getJavaMember().getName() + Formats.formatAsFormalParameterList(method.getParameters()); } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Child.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Child.java index d03eb2b99d..df02590b1a 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Child.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Child.java @@ -16,5 +16,8 @@ */ package org.jboss.weld.tests.annotatedType; +import jakarta.enterprise.context.Dependent; + +@Dependent public class Child extends Parent { } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/DeclaringTypeTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/DeclaringTypeTest.java index 57dda9adf0..7313435191 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/DeclaringTypeTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/DeclaringTypeTest.java @@ -49,28 +49,20 @@ public static Archive deploy() { @Test public void testInheritance() { AnnotatedType type = beanManager.createAnnotatedType(Child.class); + Assert.assertEquals(1, type.getConstructors().size()); + Assert.assertEquals(1, type.getFields().size()); - for (AnnotatedField field : type.getFields()) { - if (field.getJavaMember().getName().equals("parent")) { - Assert.assertEquals(Parent.class, field.getJavaMember().getDeclaringClass()); // OK - Returns Parent - // this assertion is commented out because the spec is not clear which type to return and the flat type actually makes more sense - // Assert.assertEquals(Parent.class, field.getDeclaringType().getJavaClass()); // FAIL - Returns Child - } else { - Assert.fail("Unknown field " + field.getJavaMember()); - } - } + AnnotatedField field = type.getFields().stream().findAny().get(); + Assert.assertEquals("parent", field.getJavaMember().getName()); + Assert.assertEquals(Parent.class, field.getJavaMember().getDeclaringClass()); + Assert.assertEquals(Parent.class, field.getDeclaringType().getJavaClass()); Assert.assertEquals(1, type.getMethods().size()); - for (AnnotatedMethod method : type.getMethods()) { - if (method.getJavaMember().getName().equals("parentMethod")) { - Assert.assertEquals(Parent.class, method.getJavaMember().getDeclaringClass()); // OK - Returns Parent - // this assertion is commented out because the spec is not clear which type to return and the flat type actually makes more sense - // Assert.assertEquals(Parent.class, method.getDeclaringType().getJavaClass()); // FAIL - Returns Child - } else { - Assert.fail("Unknown method " + method.getJavaMember()); - } - } + AnnotatedMethod method = type.getMethods().stream().findAny().get(); + Assert.assertEquals("parentMethod", method.getJavaMember().getName()); + Assert.assertEquals(Parent.class, method.getJavaMember().getDeclaringClass()); + Assert.assertEquals(Parent.class, method.getDeclaringType().getJavaClass()); } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Parent.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Parent.java index cd81ff9caa..1646f8c3bb 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Parent.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/annotatedType/Parent.java @@ -16,6 +16,9 @@ */ package org.jboss.weld.tests.annotatedType; +import jakarta.enterprise.context.Dependent; + +@Dependent public class Parent { int parent; diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/processProducerField/GetDisposedParameterTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/processProducerField/GetDisposedParameterTest.java index fa72954ade..4ba0171fee 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/processProducerField/GetDisposedParameterTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/extensions/lifecycle/processProducerField/GetDisposedParameterTest.java @@ -62,6 +62,6 @@ public void testDisposedParameter() { assertTrue(parameter.isAnnotationPresent(Zero.class)); assertEquals(int.class, parameter.getBaseType()); assertEquals(0, parameter.getPosition()); - assertEquals(Producer.class, parameter.getDeclaringCallable().getDeclaringType().getJavaClass()); + assertEquals(Producer.class, parameter.getDeclaringCallable().getJavaMember().getDeclaringClass()); } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/DisposerInheritanceTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/DisposerInheritanceTest.java new file mode 100644 index 0000000000..200a75b030 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/DisposerInheritanceTest.java @@ -0,0 +1,224 @@ +package org.jboss.weld.tests.inheritance.producer; + +import java.util.function.Consumer; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.context.spi.CreationalContext; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.Disposes; +import jakarta.enterprise.inject.Produces; +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.enterprise.inject.spi.Extension; +import jakarta.enterprise.inject.spi.ProcessAnnotatedType; +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.shrinkwrap.api.spec.JavaArchive; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @see https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#member_level_inheritance + */ +public class DisposerInheritanceTest { + + abstract static class Foo { + boolean isDisposed; + } + + interface Parent { + } + + interface Child { + } + + @Dependent + static class MethodParent implements Parent { + @Produces + Foo foo() { + return new Foo() { + }; + } + + void disposeFoo(@Disposes Foo foo) { + foo.isDisposed = true; + } + } + + @Dependent + static class MethodChild extends MethodParent implements Child { + } + + interface DefaultMethodParent extends Parent { + default void disposeFoo(@Disposes Foo foo) { + foo.isDisposed = true; + } + } + + @Dependent + static class DefaultMethodChild implements DefaultMethodParent, Child { + @Produces + Foo foo() { + return new Foo() { + }; + } + } + + public static class ProcessAnnotatedTypeExtension implements Extension { + void processAnnotatedType(@Observes ProcessAnnotatedType processAnnotatedType) { + // calling configureAnnotatedType() appears to be sufficient for the AnnotatedType pat.getAnnotatedType() + // to get replaced after this method processAnnotatedType has returned with (zero or more) changes applied. + processAnnotatedType.configureAnnotatedType(); + } + } + + static final Consumer assertDisposed = foo -> Assert.assertTrue(foo.isDisposed); + static final Consumer assertNotDisposed = foo -> Assert.assertFalse(foo.isDisposed); + + static class TestCaseBuilder implements Cloneable { + Class testClass; + Class parentClass; + Class childClass; + boolean deployProcessAnnotatedTypeObserver; + Consumer assertion = assertDisposed; + + protected TestCaseBuilder clone() { + try { + return (TestCaseBuilder) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + TestCaseBuilder parent(Class parentClass) { + TestCaseBuilder builder = clone(); + builder.parentClass = parentClass; + return builder; + } + + TestCaseBuilder child(Class childClass) { + TestCaseBuilder builder = clone(); + builder.childClass = childClass; + return builder; + } + + TestCaseBuilder pat() { + TestCaseBuilder builder = clone(); + builder.deployProcessAnnotatedTypeObserver = true; + return builder; + } + + TestCaseBuilder disposesFoo(boolean disposes) { + TestCaseBuilder builder = clone(); + builder.assertion = disposes ? assertDisposed : assertNotDisposed; + return builder; + } + + JavaArchive deploy(Class testClass) { + this.testClass = testClass; + JavaArchive archive = ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash(testClass)) + .addClass(testClass); + archive = archive.addClass(parentClass); + archive = archive.addClass(childClass); + if (deployProcessAnnotatedTypeObserver) { + archive = archive.addClass(ProcessAnnotatedTypeExtension.class); + } + return archive; + } + } + + @RunWith(Arquillian.class) + abstract static class AbstractTest { + final TestCaseBuilder testCaseBuilder; + + AbstractTest(TestCaseBuilder testCaseBuilder) { + this.testCaseBuilder = testCaseBuilder; + } + + @Before + public void assertSomeAssumptionAboutTheTestItself() { + Assert.assertEquals(getClass(), testCaseBuilder.testClass); + } + + @Inject + BeanManager beanManager; + + @Test + public void testDisposer() { + Bean bean = Utils.getBean(beanManager, Foo.class, Default.Literal.INSTANCE); + CreationalContext ctx = beanManager.createCreationalContext(bean); + Foo foo = bean.create(ctx); + assertNotDisposed.accept(foo); + + bean.destroy(foo, ctx); + testCaseBuilder.assertion.accept(foo); + } + } + + static TestCaseBuilder disposerMethod = new TestCaseBuilder().parent(MethodParent.class).child(MethodChild.class); + + /** + * {@code foo} cannot be resolved because neither {@link Parent} nor {@link Child} dispose {@link Foo}. + * Both {@link Parent} and {@link Child}'s disposer methods are considered inherited and therefore both + * don't actually dispose. + */ + static TestCaseBuilder disposerDefaultMethod = new TestCaseBuilder().parent(DefaultMethodParent.class) + .child(DefaultMethodChild.class).disposesFoo(false); + static TestCaseBuilder disposerMethodPat = disposerMethod.pat(); + static TestCaseBuilder disposerDefaultMethodPat = disposerDefaultMethod.pat(); + + public static class MethodTest extends AbstractTest { + public MethodTest() { + super(disposerMethod); + } + + @Deployment + public static Archive deploy() { + return disposerMethod.deploy(MethodTest.class); + } + } + + public static class DefaultMethodTest extends AbstractTest { + public DefaultMethodTest() { + super(disposerDefaultMethod); + } + + @Deployment + public static Archive deploy() { + return disposerDefaultMethod.deploy(DefaultMethodTest.class); + } + } + + public static class MethodPatTest extends AbstractTest { + public MethodPatTest() { + super(disposerMethodPat); + } + + @Deployment + public static Archive deploy() { + return disposerMethodPat.deploy(MethodPatTest.class); + } + } + + public static class DefaultMethodPatTest extends AbstractTest { + public DefaultMethodPatTest() { + super(disposerDefaultMethodPat); + } + + @Deployment + public static Archive deploy() { + return disposerDefaultMethodPat.deploy(DefaultMethodPatTest.class); + } + } + +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/ProducerInheritanceTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/ProducerInheritanceTest.java new file mode 100644 index 0000000000..137e762cbc --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/inheritance/producer/ProducerInheritanceTest.java @@ -0,0 +1,316 @@ +package org.jboss.weld.tests.inheritance.producer; + +import java.util.function.Consumer; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Produces; +import jakarta.enterprise.inject.spi.Extension; +import jakarta.enterprise.inject.spi.ProcessAnnotatedType; + +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.shrinkwrap.api.spec.JavaArchive; +import org.jboss.weld.test.util.Utils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @see https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#member_level_inheritance + */ +public class ProducerInheritanceTest { + + interface Foo { + } + + interface Parent { + } + + interface Child { + } + + @Dependent + static class FieldParent implements Parent { + @Produces + Foo foo = new Foo() { + }; + } + + @Dependent + static class FieldChild extends FieldParent implements Child { + } + + @Dependent + static class MethodParent implements Parent { + @Produces + Foo foo() { + return new Foo() { + }; + } + } + + @Dependent + static class MethodChild extends MethodParent implements Child { + } + + interface DefaultMethodParent extends Parent { + @Produces + default Foo foo() { + return new Foo() { + }; + } + } + + @Dependent + static class DefaultMethodChild implements DefaultMethodParent, Child { + } + + public static class ProcessAnnotatedTypeExtension implements Extension { + void processAnnotatedType(@Observes ProcessAnnotatedType processAnnotatedType) { + // calling configureAnnotatedType() appears to be sufficient for the AnnotatedType pat.getAnnotatedType() + // to get replaced after this method processAnnotatedType has returned with (zero or more) changes applied. + processAnnotatedType.configureAnnotatedType(); + } + } + + static final Consumer assertNotNull = Assert::assertNotNull; + static final Consumer assertNull = Assert::assertNull; + + static class TestCaseBuilder implements Cloneable { + Class testClass; + Class parentClass; + Class childClass; + boolean deployProcessAnnotatedTypeObserver; + Consumer assertion = assertNotNull; + + protected TestCaseBuilder clone() { + try { + return (TestCaseBuilder) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + TestCaseBuilder noParent() { + TestCaseBuilder builder = clone(); + builder.parentClass = null; + return builder; + } + + TestCaseBuilder parent(Class parentClass) { + TestCaseBuilder builder = clone(); + builder.parentClass = parentClass; + return builder; + } + + TestCaseBuilder child(Class childClass) { + TestCaseBuilder builder = clone(); + builder.childClass = childClass; + return builder; + } + + TestCaseBuilder pat() { + TestCaseBuilder builder = clone(); + builder.deployProcessAnnotatedTypeObserver = true; + return builder; + } + + TestCaseBuilder resolvesFoo(boolean resolves) { + TestCaseBuilder builder = clone(); + builder.assertion = resolves ? assertNotNull : assertNull; + return builder; + } + + JavaArchive deploy(Class testClass) { + this.testClass = testClass; + JavaArchive archive = ShrinkWrap + .create(BeanArchive.class, Utils.getDeploymentNameAsHash(testClass)) + .addClass(testClass); + if (parentClass != null) { + archive = archive.addClass(parentClass); + } + archive = archive.addClass(childClass); + if (deployProcessAnnotatedTypeObserver) { + archive = archive.addClass(ProcessAnnotatedTypeExtension.class); + } + return archive; + } + } + + @RunWith(Arquillian.class) + abstract static class AbstractTest { + final TestCaseBuilder testCaseBuilder; + + AbstractTest(TestCaseBuilder testCaseBuilder) { + this.testCaseBuilder = testCaseBuilder; + } + + @Before + public void assertSomeAssumptionAboutTheTestItself() { + Assert.assertEquals(getClass(), testCaseBuilder.testClass); + } + + @Test + public void testProducer(Foo foo) { + testCaseBuilder.assertion.accept(foo); + } + } + + static TestCaseBuilder producerField = new TestCaseBuilder().parent(FieldParent.class).child(FieldChild.class); + static TestCaseBuilder producerMethod = new TestCaseBuilder().parent(MethodParent.class).child(MethodChild.class); + + /** + * {@code foo} cannot be resolved because neither {@link Parent} nor {@link Child} produce {@link Foo}. + * Both {@link Parent} and {@link Child}'s producer methods are considered inherited and therefore both + * don't actually produce. + */ + static TestCaseBuilder producerDefaultMethod = new TestCaseBuilder().parent(DefaultMethodParent.class) + .child(DefaultMethodChild.class).resolvesFoo(false); + static TestCaseBuilder producerFieldNoParent = producerField.noParent().resolvesFoo(false); + static TestCaseBuilder producerMethodNoParent = producerMethod.noParent().resolvesFoo(false); + static TestCaseBuilder producerDefaultMethodNoParent = producerDefaultMethod.noParent().resolvesFoo(false); + static TestCaseBuilder producerFieldPat = producerField.pat(); + static TestCaseBuilder producerMethodPat = producerMethod.pat(); + static TestCaseBuilder producerDefaultMethodPat = producerDefaultMethod.pat(); + static TestCaseBuilder producerFieldNoParentPat = producerFieldNoParent.pat(); + static TestCaseBuilder producerMethodNoParentPat = producerMethodNoParent.pat(); + static TestCaseBuilder producerDefaultMethodNoParentPat = producerDefaultMethodNoParent.pat(); + + public static class FieldTest extends AbstractTest { + public FieldTest() { + super(producerField); + } + + @Deployment + public static Archive deploy() { + return producerField.deploy(FieldTest.class); + } + } + + public static class MethodTest extends AbstractTest { + public MethodTest() { + super(producerMethod); + } + + @Deployment + public static Archive deploy() { + return producerMethod.deploy(MethodTest.class); + } + } + + public static class DefaultMethodTest extends AbstractTest { + public DefaultMethodTest() { + super(producerDefaultMethod); + } + + @Deployment + public static Archive deploy() { + return producerDefaultMethod.deploy(DefaultMethodTest.class); + } + } + + public static class FieldNoParentTest extends AbstractTest { + public FieldNoParentTest() { + super(producerFieldNoParent); + } + + @Deployment + public static Archive deploy() { + return producerFieldNoParent.deploy(FieldNoParentTest.class); + } + } + + public static class MethodNoParentTest extends AbstractTest { + public MethodNoParentTest() { + super(producerMethodNoParent); + } + + @Deployment + public static Archive deploy() { + return producerMethodNoParent.deploy(MethodNoParentTest.class); + } + } + + public static class DefaultMethodNoParentTest extends AbstractTest { + public DefaultMethodNoParentTest() { + super(producerDefaultMethodNoParent); + } + + @Deployment + public static Archive deploy() { + return producerDefaultMethodNoParent.deploy(DefaultMethodNoParentTest.class); + } + } + + public static class FieldPatTest extends AbstractTest { + public FieldPatTest() { + super(producerFieldPat); + } + + @Deployment + public static Archive deploy() { + return producerFieldPat.deploy(FieldPatTest.class); + } + } + + public static class MethodPatTest extends AbstractTest { + public MethodPatTest() { + super(producerMethodPat); + } + + @Deployment + public static Archive deploy() { + return producerMethodPat.deploy(MethodPatTest.class); + } + } + + public static class DefaultMethodPatTest extends AbstractTest { + public DefaultMethodPatTest() { + super(producerDefaultMethodPat); + } + + @Deployment + public static Archive deploy() { + return producerDefaultMethodPat.deploy(DefaultMethodPatTest.class); + } + } + + public static class FieldNoParentPatTest extends AbstractTest { + public FieldNoParentPatTest() { + super(producerFieldNoParentPat); + } + + @Deployment + public static Archive deploy() { + return producerFieldNoParentPat.deploy(FieldNoParentPatTest.class); + } + } + + public static class MethodNoParentPatTest extends AbstractTest { + public MethodNoParentPatTest() { + super(producerMethodNoParentPat); + } + + @Deployment + public static Archive deploy() { + return producerMethodNoParentPat.deploy(MethodNoParentPatTest.class); + } + } + + public static class DefaultMethodNoParentPatTest extends AbstractTest { + public DefaultMethodNoParentPatTest() { + super(producerDefaultMethodNoParentPat); + } + + @Deployment + public static Archive deploy() { + return producerDefaultMethodNoParentPat.deploy(DefaultMethodNoParentPatTest.class); + } + } + +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/injectionPoint/CowShed.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/injectionPoint/CowShed.java index 9c00e1016b..8704ec5f37 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/injectionPoint/CowShed.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/injectionPoint/CowShed.java @@ -29,7 +29,7 @@ public class CowShed { @Produces public Cow get(InjectionPoint ip) { assert ip.getAnnotated() instanceof AnnotatedField; - assert Reflections.> cast(ip.getAnnotated()).getDeclaringType().getJavaClass().equals(Field.class); + assert Reflections.> cast(ip.getAnnotated()).getJavaMember().getDeclaringClass().equals(Field.class); return new Cow("daisy"); }