(For background, I've read You think you know everything about CDI events… Think again!, so I'm at least mostly familiar with many edge cases in CDI events.)
I'm using Weld 3.0.4.Final as an implementation of CDI 2.0.
I have an AbstractFoo<? extends T>
instance that I want to fire as a CDI event. We'll call this the payload. This is all that I know about the payload.
T
is defined as T extends MetaData
. MetaData
is an interface.
For various unimportant reasons I have to fire the payload programmatically, so I do this:
final Event<Object> cdiEventMachinery = beanManager.getEvent();
assert cdiEventMachinery != null;
final TypeLiteral<AbstractFoo<? extends T>> eventTypeLiteral = new TypeLiteral<AbstractFoo<? extends T>>() {
private static final long serialVersionUID = 1L;
};
final Event<AbstractFoo<? extends T>> broadcaster =
cdiEventMachinery.select(eventTypeLiteral, someQualifiers);
assert broadcaster != null;
Obviously here broadcaster
is now set up to fire my payload. My intention is that these events should be delivered to observers looking for AbstractFoo
-or-its-subclasses instances parameterized by any type that extends MetaData
.
But when I do broadcaster.fire(payload)
, I've noticed that observer methods like this one:
private final void onFoo(@ObservesAsync @MatchingQualifier final Foo<? extends MetaDataSubclass> event) {}
…do not get called. (The ? extends MetaDataSubclass
seems to be the culprit; if the observed parameter is simply, say, Object
then obviously the method is notified.)
Specifically, assuming that:
- a
MatchingQualifier
literal is present insomeQualifiers
, and MetaDataSubclass
is a class that extendsMetaData
, andFoo
is a class that extendsAbstractFoo
…why doesn't that observer method get called?
To be clear, I'm sure this isn't a bug but is something missing in my understanding. I'd like to find out what I'm missing.
(Crossposted to developer.jboss.org.)
Test Case
Here is a test case using simpler constructs.
private final void collectionExtendsNumber(@Observes final Collection<? extends Number> payload) {
System.out.println("*** collection extends Number");
}
private final void collectionExtendsInteger(@Observes final Collection<? extends Integer> payload) {
System.out.println("*** collection extends Integer");
}
private final void collectionInteger(@Observes final Collection<Integer> payload) {
System.out.println("*** collection Integer");
}
private final void collectionNumber(@Observes final Collection<Number> payload) {
System.out.println("*** collection Number");
}
@Test
public void testContainerStartup() {
final SeContainerInitializer initializer = SeContainerInitializer.newInstance();
initializer.disableDiscovery();
initializer.addBeanClasses(this.getClass());
try (final SeContainer container = initializer.initialize()) {
assertNotNull(container);
final BeanManager beanManager = container.getBeanManager();
assertNotNull(beanManager);
final TypeLiteral<Collection<? extends Number>> literal = new TypeLiteral<Collection<? extends Number>>() {
private static final long serialVersionUID = 1L;
};
final Event<Collection<? extends Number>> broadcaster = beanManager.getEvent().select(literal);
assertNotNull(broadcaster);
final Collection<? extends Number> payload = Collections.singleton(Integer.valueOf(1));
broadcaster.fire(payload);
}
}
Only the first observer method is invoked. I'd like to understand what is preventing the second from being invoked. I understand that an-unknown-type-that-is-a-Number
cannot be assignable to an-unknown-type-that-is-a-Integer
, but I'd like some way to pick the "right" observer method for the payload.