diff --git a/impl/src/main/java/org/jboss/weld/bean/builtin/AbstractFacade.java b/impl/src/main/java/org/jboss/weld/bean/builtin/AbstractFacade.java index e80c34009e5..7bfbd11ec72 100644 --- a/impl/src/main/java/org/jboss/weld/bean/builtin/AbstractFacade.java +++ b/impl/src/main/java/org/jboss/weld/bean/builtin/AbstractFacade.java @@ -20,6 +20,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import java.util.Set; import jakarta.enterprise.context.spi.CreationalContext; @@ -40,12 +41,23 @@ public abstract class AbstractFacade { protected static Type getFacadeType(InjectionPoint injectionPoint) { Type genericType = injectionPoint.getType(); if (genericType instanceof ParameterizedType) { - return ((ParameterizedType) genericType).getActualTypeArguments()[0]; + Type typeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0]; + if (typeArgument instanceof WildcardType) { + return getWildcardBound((WildcardType) typeArgument); + } + return typeArgument; } else { throw new IllegalStateException(BeanLogger.LOG.typeParameterMustBeConcrete(injectionPoint)); } } + private static Type getWildcardBound(WildcardType wildcard) { + if (wildcard.getLowerBounds().length > 0) { + return wildcard.getLowerBounds()[0]; + } + return wildcard.getUpperBounds()[0]; + } + private final BeanManagerImpl beanManager; private final InjectionPoint injectionPoint; // The CreationalContext used to create the facade which was injected. diff --git a/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java b/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java index 607eadc0c4a..cc00200118a 100644 --- a/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java +++ b/impl/src/main/java/org/jboss/weld/bean/builtin/InstanceImpl.java @@ -24,7 +24,9 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.ref.WeakReference; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import java.util.Comparator; import java.util.Iterator; import java.util.Set; @@ -89,6 +91,7 @@ public static Instance of(InjectionPoint injectionPoint, CreationalContex private InstanceImpl(InjectionPoint injectionPoint, CreationalContext creationalContext, BeanManagerImpl beanManager) { super(injectionPoint, creationalContext, beanManager); + checkInstanceTypeArgument(injectionPoint); if (injectionPoint.getQualifiers().isEmpty() && Object.class.equals(getType())) { // Do not prefetch the beans for Instance with no qualifiers @@ -111,6 +114,16 @@ private InstanceImpl(InjectionPoint injectionPoint, CreationalContext this.ejbSupport = beanManager.getServices().get(EjbSupport.class); } + private static void checkInstanceTypeArgument(InjectionPoint injectionPoint) { + Type type = injectionPoint.getType(); + if (type instanceof ParameterizedType) { + Type typeArg = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (typeArg instanceof WildcardType && ((WildcardType) typeArg).getLowerBounds().length > 0) { + throw BeanLogger.LOG.instanceTypeArgumentWithLowerBound(injectionPoint); + } + } + } + public T get() { checkBeanResolved(); return getBeanInstance(bean); diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/Validator.java b/impl/src/main/java/org/jboss/weld/bootstrap/Validator.java index e00c1b25049..a50859a088b 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/Validator.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/Validator.java @@ -886,15 +886,23 @@ private static void checkFacadeInjectionPoint(InjectionPoint injectionPoint, Cla Formats.formatAsStackTraceElement(injectionPoint)); } if (parameterizedType.getActualTypeArguments()[0] instanceof WildcardType) { - throw ValidatorLogger.LOG.injectionPointHasWildcard(injectionPoint, - Formats.formatAsStackTraceElement(injectionPoint)); + WildcardType wildcard = (WildcardType) parameterizedType.getActualTypeArguments()[0]; + if (!isAllowedWildcard(wildcard, type)) { + throw ValidatorLogger.LOG.injectionPointHasWildcard(injectionPoint, + Formats.formatAsStackTraceElement(injectionPoint)); + } } } else if (type.equals(Event.class) && parameterizedType.getRawType().equals(Instance.class)) { - // check for wildcard in Event injected via Instance -> @Inject Instance> + // Instance or Instance where X is an invalid Event type is a definition error Type instanceTypeArgument = parameterizedType.getActualTypeArguments()[0]; - if (instanceTypeArgument instanceof ParameterizedType - && ((ParameterizedType) instanceTypeArgument).getRawType().equals(Event.class) - && ((ParameterizedType) instanceTypeArgument).getActualTypeArguments()[0] instanceof WildcardType) { + Type resolvedType = instanceTypeArgument; + if (instanceTypeArgument instanceof WildcardType) { + WildcardType wildcard = (WildcardType) instanceTypeArgument; + if (wildcard.getUpperBounds().length > 0) { + resolvedType = wildcard.getUpperBounds()[0]; + } + } + if (isInvalidEventType(resolvedType)) { throw ValidatorLogger.LOG.injectionPointHasWildcard(injectionPoint, Formats.formatAsStackTraceElement(injectionPoint)); } @@ -902,6 +910,34 @@ private static void checkFacadeInjectionPoint(InjectionPoint injectionPoint, Cla } } + private static boolean isAllowedWildcard(WildcardType wildcard, Class facadeType) { + if (facadeType.equals(Event.class)) { + // Event is allowed, Event and Event are not + return wildcard.getLowerBounds().length > 0; + } + if (facadeType.equals(Instance.class)) { + // Instance and Instance are allowed, Instance is not + return wildcard.getLowerBounds().length == 0; + } + return false; + } + + private static boolean isInvalidEventType(Type type) { + if (type instanceof Class && Event.class.equals(type)) { + return true; + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + if (Event.class.equals(pt.getRawType())) { + Type typeArg = pt.getActualTypeArguments()[0]; + if (typeArg instanceof WildcardType) { + return ((WildcardType) typeArg).getLowerBounds().length == 0; + } + } + } + return false; + } + public static void checkBeanMetadataInjectionPoint(Object bean, InjectionPoint ip, Type expectedTypeArgument) { if (!(ip.getType() instanceof ParameterizedType)) { throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, diff --git a/impl/src/main/java/org/jboss/weld/event/EventImpl.java b/impl/src/main/java/org/jboss/weld/event/EventImpl.java index d7c2357c649..fc45e233a07 100644 --- a/impl/src/main/java/org/jboss/weld/event/EventImpl.java +++ b/impl/src/main/java/org/jboss/weld/event/EventImpl.java @@ -22,7 +22,9 @@ import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import java.util.Map; import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; @@ -74,10 +76,21 @@ public static EventImpl of(InjectionPoint injectionPoint, BeanManagerImpl private EventImpl(InjectionPoint injectionPoint, BeanManagerImpl beanManager) { super(injectionPoint, null, beanManager); + checkEventTypeArgument(injectionPoint); this.injectionPointTypeHierarchy = new HierarchyDiscovery(getType()); this.cachedObservers = new ConcurrentHashMap, CachedObservers>(DEFAULT_CACHE_CAPACITY); } + private static void checkEventTypeArgument(InjectionPoint injectionPoint) { + Type type = injectionPoint.getType(); + if (type instanceof ParameterizedType) { + Type typeArg = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (typeArg instanceof WildcardType && ((WildcardType) typeArg).getLowerBounds().length == 0) { + throw EventLogger.LOG.eventTypeArgumentWithoutLowerBound(injectionPoint); + } + } + } + /** * Gets a string representation * diff --git a/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java b/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java index 6ba2f96a198..c5a1e14da6c 100644 --- a/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java +++ b/impl/src/main/java/org/jboss/weld/logging/BeanLogger.java @@ -561,4 +561,7 @@ IllegalProductException unserializableProductInjectionError(Object producer, Obj @LogMessage(level = Level.ERROR) @Message(id = 1581, value = "Error invoking AutoCloseable.close() on an instance {0} of {1}", format = Format.MESSAGE_FORMAT) void errorAutoClosing(Object param1, Object param2); + + @Message(id = 1582, value = "Instance type argument must not be a wildcard with lower bound: {0}", format = Format.MESSAGE_FORMAT) + IllegalArgumentException instanceTypeArgumentWithLowerBound(Object injectionPoint); } diff --git a/impl/src/main/java/org/jboss/weld/logging/EventLogger.java b/impl/src/main/java/org/jboss/weld/logging/EventLogger.java index 33c859c9e92..8af307ccd5f 100644 --- a/impl/src/main/java/org/jboss/weld/logging/EventLogger.java +++ b/impl/src/main/java/org/jboss/weld/logging/EventLogger.java @@ -115,4 +115,7 @@ public interface EventLogger extends WeldLogger { @Message(id = 422, value = "WeldEvent.select(Type subtype, Annotation... qualifiers) can be invoked only on an instance of WeldEvent.", format = Format.MESSAGE_FORMAT) IllegalStateException selectByTypeOnlyWorksOnObject(); + + @Message(id = 423, value = "Event type argument must not be a wildcard without lower bound: {0}", format = Format.MESSAGE_FORMAT) + IllegalArgumentException eventTypeArgumentWithoutLowerBound(Object injectionPoint); } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithContravariantEvent.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithContravariantEvent.java new file mode 100644 index 00000000000..d1759cedebe --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithContravariantEvent.java @@ -0,0 +1,16 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithContravariantEvent { + + @Inject + Event> lifecycleEvents; + + public void fireEvent(LifecycleEvent event) { + lifecycleEvents.fire(event); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithSimpleContravariantEvent.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithSimpleContravariantEvent.java new file mode 100644 index 00000000000..0f8d99aa8f5 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/BeanWithSimpleContravariantEvent.java @@ -0,0 +1,16 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithSimpleContravariantEvent { + + @Inject + Event widgetEvents; + + public void fireWidget(Widget widget) { + widgetEvents.fire(widget); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/EventContravariantWildcardTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/EventContravariantWildcardTest.java new file mode 100644 index 00000000000..ec2421ad5d0 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/EventContravariantWildcardTest.java @@ -0,0 +1,47 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +import static org.junit.Assert.assertTrue; + +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.junit.Test; +import org.junit.runner.RunWith; + +/** + * Verifies that {@code Event} injection points are valid and functional. + * {@code Event} is naturally contravariant — you fire subtypes into it — so a + * lower-bounded wildcard is a legitimate use case. + *

+ * This reproduces the scenario reported by Gavin King where Jakarta Data injects + * {@code Event>}. + * + * @see CDI #888 + */ +@RunWith(Arquillian.class) +public class EventContravariantWildcardTest { + + @Deployment + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(EventContravariantWildcardTest.class)) + .addClasses(BeanWithContravariantEvent.class, LifecycleEvent.class, LifecycleEventObserver.class, + BeanWithSimpleContravariantEvent.class, Widget.class, WidgetObserver.class); + } + + @Test + public void testParameterizedContravariantEventWildcard(BeanWithContravariantEvent bean, + LifecycleEventObserver observer) { + bean.fireEvent(new LifecycleEvent<>("test")); + assertTrue("LifecycleEvent should have been observed", observer.isObserved()); + } + + @Test + public void testSimpleContravariantEventWildcard(BeanWithSimpleContravariantEvent bean, + WidgetObserver observer) { + bean.fireWidget(new Widget("test")); + assertTrue("Widget event should have been observed", observer.isObserved()); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEvent.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEvent.java new file mode 100644 index 00000000000..28ba4ced46d --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEvent.java @@ -0,0 +1,14 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +public class LifecycleEvent { + + private final T payload; + + public LifecycleEvent(T payload) { + this.payload = payload; + } + + public T getPayload() { + return payload; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEventObserver.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEventObserver.java new file mode 100644 index 00000000000..a2bf518eef1 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/LifecycleEventObserver.java @@ -0,0 +1,18 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +@ApplicationScoped +public class LifecycleEventObserver { + + private boolean observed = false; + + public void onLifecycleEvent(@Observes LifecycleEvent event) { + observed = true; + } + + public boolean isObserved() { + return observed; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/Widget.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/Widget.java new file mode 100644 index 00000000000..f5aaa5fe1bc --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/Widget.java @@ -0,0 +1,14 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +public class Widget { + + private final String name; + + public Widget(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/WidgetObserver.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/WidgetObserver.java new file mode 100644 index 00000000000..3c9c3bf600e --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/contravariant/WidgetObserver.java @@ -0,0 +1,18 @@ +package org.jboss.weld.tests.event.wildcard.contravariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +@ApplicationScoped +public class WidgetObserver { + + private boolean observed = false; + + public void onWidget(@Observes Widget event) { + observed = true; + } + + public boolean isObserved() { + return observed; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/BeanWithCovariantEvent.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/BeanWithCovariantEvent.java new file mode 100644 index 00000000000..05cbdfd967b --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/BeanWithCovariantEvent.java @@ -0,0 +1,12 @@ +package org.jboss.weld.tests.event.wildcard.covariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithCovariantEvent { + + @Inject + Event covariantEvent; +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/EventCovariantWildcardTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/EventCovariantWildcardTest.java new file mode 100644 index 00000000000..784363b585b --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/EventCovariantWildcardTest.java @@ -0,0 +1,35 @@ +package org.jboss.weld.tests.event.wildcard.covariant; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.ShouldThrowException; +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.junit.Test; +import org.junit.runner.RunWith; + +/** + * Verifies that {@code Event} injection points are rejected. + * Covariant wildcards on Event are useless because you cannot call + * {@code fire()} on them. + * + * @see CDI #888 + */ +@RunWith(Arquillian.class) +public class EventCovariantWildcardTest { + + @Deployment + @ShouldThrowException(DefinitionException.class) + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(EventCovariantWildcardTest.class)) + .addClasses(BeanWithCovariantEvent.class, Widget.class); + } + + @Test + public void testCovariantEventWildcardRejected() { + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/Widget.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/Widget.java new file mode 100644 index 00000000000..2505d19bfd6 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/wildcard/covariant/Widget.java @@ -0,0 +1,4 @@ +package org.jboss.weld.tests.event.wildcard.covariant; + +public class Widget { +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithCovariantEventInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithCovariantEventInstance.java new file mode 100644 index 00000000000..110f23cebd4 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithCovariantEventInstance.java @@ -0,0 +1,12 @@ +package org.jboss.weld.tests.instance.wildcard; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithCovariantEventInstance { + @Inject + Instance> covariantEventInstance; +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithRawEventInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithRawEventInstance.java new file mode 100644 index 00000000000..4edfc645c64 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithRawEventInstance.java @@ -0,0 +1,13 @@ +package org.jboss.weld.tests.instance.wildcard; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithRawEventInstance { + @Inject + @SuppressWarnings("rawtypes") + Instance rawEventInstance; +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardInstance.java index e0e6a84cf15..4607725c068 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardInstance.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardInstance.java @@ -8,4 +8,8 @@ public class BeanWithWildcardInstance { @Inject Instance wildInstance; + + public Instance getWildInstance() { + return wildInstance; + } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardRawEventInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardRawEventInstance.java new file mode 100644 index 00000000000..b3625c4ed11 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/BeanWithWildcardRawEventInstance.java @@ -0,0 +1,13 @@ +package org.jboss.weld.tests.instance.wildcard; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Event; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithWildcardRawEventInstance { + @Inject + @SuppressWarnings("rawtypes") + Instance wildcardRawEventInstance; +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithCovariantEventTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithCovariantEventTest.java new file mode 100644 index 00000000000..4d6e5f5d6f7 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithCovariantEventTest.java @@ -0,0 +1,30 @@ +package org.jboss.weld.tests.instance.wildcard; + +import static org.junit.Assert.assertNotNull; + +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.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instance> should be allowed since Event is a valid Event injection point. + */ +@RunWith(Arquillian.class) +public class InstanceWithCovariantEventTest { + + @Deployment + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(InstanceWithCovariantEventTest.class)) + .addClass(BeanWithCovariantEventInstance.class); + } + + @Test + public void testInstanceWithCovariantEvent(BeanWithCovariantEventInstance bean) { + assertNotNull(bean); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithRawEventTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithRawEventTest.java new file mode 100644 index 00000000000..774ebe645fa --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithRawEventTest.java @@ -0,0 +1,29 @@ +package org.jboss.weld.tests.instance.wildcard; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.ShouldThrowException; +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.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class InstanceWithRawEventTest { + + @Deployment + @ShouldThrowException(DefinitionException.class) + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(InstanceWithRawEventTest.class)) + .addClass(BeanWithRawEventInstance.class); + } + + @Test + public void testInstanceWithRawEvent() { + // should throw definition exception + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardRawEventTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardRawEventTest.java new file mode 100644 index 00000000000..ea31cc3f913 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardRawEventTest.java @@ -0,0 +1,29 @@ +package org.jboss.weld.tests.instance.wildcard; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.ShouldThrowException; +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.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class InstanceWithWildcardRawEventTest { + + @Deployment + @ShouldThrowException(DefinitionException.class) + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(InstanceWithWildcardRawEventTest.class)) + .addClass(BeanWithWildcardRawEventInstance.class); + } + + @Test + public void testInstanceWithWildcardRawEvent() { + // should throw definition exception + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardTest.java index 5be98fd8b97..f34ab8794dd 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/InstanceWithWildcardTest.java @@ -1,9 +1,10 @@ package org.jboss.weld.tests.instance.wildcard; -import jakarta.enterprise.inject.spi.DefinitionException; +import static org.junit.Assert.assertNotNull; + +import jakarta.inject.Inject; import org.jboss.arquillian.container.test.api.Deployment; -import org.jboss.arquillian.container.test.api.ShouldThrowException; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.BeanArchive; @@ -16,14 +17,17 @@ public class InstanceWithWildcardTest { @Deployment - @ShouldThrowException(DefinitionException.class) public static Archive getDeployment() { return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(InstanceWithWildcardTest.class)) .addClass(BeanWithWildcardInstance.class); } + @Inject + BeanWithWildcardInstance bean; + @Test public void testInstanceWithWildcard() { - // should throw definition exception + assertNotNull(bean); + assertNotNull(bean.getWildInstance()); } } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/BeanWithContravariantInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/BeanWithContravariantInstance.java new file mode 100644 index 00000000000..1de2b0a0370 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/BeanWithContravariantInstance.java @@ -0,0 +1,12 @@ +package org.jboss.weld.tests.instance.wildcard.contravariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithContravariantInstance { + + @Inject + Instance contravariantInstance; +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/InstanceContravariantWildcardTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/InstanceContravariantWildcardTest.java new file mode 100644 index 00000000000..3f3bf4cc2ff --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/InstanceContravariantWildcardTest.java @@ -0,0 +1,36 @@ +package org.jboss.weld.tests.instance.wildcard.contravariant; + +import jakarta.enterprise.inject.spi.DefinitionException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.ShouldThrowException; +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.junit.Test; +import org.junit.runner.RunWith; + +/** + * Verifies that {@code Instance} injection points are rejected. + * Contravariant wildcards on Instance are useless because Instance is + * naturally covariant. + * + * @see CDI #888 + */ +@RunWith(Arquillian.class) +public class InstanceContravariantWildcardTest { + + @Deployment + @ShouldThrowException(DefinitionException.class) + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, + Utils.getDeploymentNameAsHash(InstanceContravariantWildcardTest.class)) + .addClasses(BeanWithContravariantInstance.class, Widget.class); + } + + @Test + public void testContravariantInstanceWildcardRejected() { + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/Widget.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/Widget.java new file mode 100644 index 00000000000..47fdef3f3a6 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/contravariant/Widget.java @@ -0,0 +1,4 @@ +package org.jboss.weld.tests.instance.wildcard.contravariant; + +public class Widget { +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/BeanWithCovariantInstance.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/BeanWithCovariantInstance.java new file mode 100644 index 00000000000..4bb5ead9b31 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/BeanWithCovariantInstance.java @@ -0,0 +1,20 @@ +package org.jboss.weld.tests.instance.wildcard.covariant; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +@ApplicationScoped +public class BeanWithCovariantInstance { + + @Inject + Instance covariantInstance; + + public boolean isResolvable() { + return covariantInstance.isResolvable(); + } + + public Widget get() { + return covariantInstance.get(); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/InstanceCovariantWildcardTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/InstanceCovariantWildcardTest.java new file mode 100644 index 00000000000..8a55ecceb1c --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/InstanceCovariantWildcardTest.java @@ -0,0 +1,37 @@ +package org.jboss.weld.tests.instance.wildcard.covariant; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +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.junit.Test; +import org.junit.runner.RunWith; + +/** + * Verifies that {@code Instance} injection points are valid and + * functional. Instance is naturally covariant so an upper-bounded wildcard is + * a legitimate use case. + * + * @see CDI #888 + */ +@RunWith(Arquillian.class) +public class InstanceCovariantWildcardTest { + + @Deployment + public static Archive getDeployment() { + return ShrinkWrap.create(BeanArchive.class, Utils.getDeploymentNameAsHash(InstanceCovariantWildcardTest.class)) + .addClasses(BeanWithCovariantInstance.class, Widget.class); + } + + @Test + public void testCovariantInstanceWildcardDeploys(BeanWithCovariantInstance bean) { + assertTrue("Instance should be resolvable", bean.isResolvable()); + Widget widget = bean.get(); + assertNotNull("Instance.get() should return a Widget", widget); + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/Widget.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/Widget.java new file mode 100644 index 00000000000..7d82c4f1325 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/instance/wildcard/covariant/Widget.java @@ -0,0 +1,17 @@ +package org.jboss.weld.tests.instance.wildcard.covariant; + +import jakarta.enterprise.context.Dependent; + +@Dependent +public class Widget { + + private final String name; + + public Widget() { + this.name = "default"; + } + + public String getName() { + return name; + } +}