Можете ли вы запускать события CDI 2.0 типа AbstractClass<? Что-то расширяет>?

(Для справки я прочитал. Вы думаете, что знаете все о событиях CDI... Подумайте еще раз!, Так что я, по крайней мере, в основном знаком со многими крайними случаями в событиях CDI.)

Я использую Weld 3.0.4.Final как реализацию CDI 2.0.

у меня есть AbstractFoo<? extends T> экземпляр, который я хочу запустить как событие CDI. Мы назовем это полезной нагрузкой. Это все, что я знаю о полезной нагрузке.

T определяется как T extends MetaData, MetaData это интерфейс.

По различным неважным причинам я должен запускать полезную нагрузку программно, поэтому я делаю это:

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;

Очевидно здесь broadcaster теперь настроен на запуск моей полезной нагрузки. Я хочу, чтобы эти события были доставлены наблюдателям, ищущим AbstractFooэкземпляры -или-подклассы, параметризованные любым расширяемым типом MetaData,

Но, когда я делаю broadcaster.fire(payload)Я заметил, что методы наблюдателя, как этот:

private final void onFoo(@ObservesAsync @MatchingQualifier final Foo<? extends MetaDataSubclass> event) {}

… Не звони. (The ? extends MetaDataSubclass кажется виновником; если наблюдаемый параметр просто, скажем, Object тогда, очевидно, метод уведомляется.)

В частности, при условии, что:

  • MatchingQualifier буквальный присутствует в someQualifiers, а также
  • MetaDataSubclass это класс, который расширяется MetaData, а также
  • Foo это класс, который расширяется AbstractFoo

... почему этот метод наблюдателя не вызывается?

Чтобы быть ясным, я уверен, что это не ошибка, но чего-то не хватает в моем понимании. Я хотел бы узнать, что мне не хватает.

(Перемещено на https://developer.jboss.org/message/983438.)

Прецедент

Вот тестовый пример с использованием более простых конструкций.

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);
  }
}

Только первый метод наблюдателя вызывается. Я хотел бы понять, что мешает запуску второго. Я понимаю, что неизвестный тип, который естьNumber нельзя присвоить неизвестному типу, который естьInteger, но я бы хотел как-то выбрать "правильный" метод наблюдателя для полезной нагрузки.

1 ответ

Это определено в спецификации в 10.3.1. Назначаемость типов переменных, необработанных и параметризованных типов. Чтобы быть более конкретным, глядя на ваш тестовый пример, вы наталкиваетесь на это предложение спецификации:

  • параметр наблюдаемого типа события является фактическим типом с необработанным типом, идентичным параметру типа события, и, если тип параметризован, параметр типа события назначается параметру наблюдаемого типа события в соответствии с этими правилами, или

Параметр типа события (? extends Number) не присваивается параметру наблюдаемого типа события (? extends Integer в вашем тестовом случае). Ситуация такая же для вашего третьего наблюдателя (Collection<Integer>).

Последний случай с Collection<Number> может выглядеть немного загадочно, но следует тому же правилу. Вы не можете назначить <? extends Number> в <Number> потому что в таком случае вы можете эффективно пытаться назначить Collection<Integer> или же Collection<Double> или же Collection<Number> (<? extends Number> может быть любым из них).

На сайте Oracle есть хороший пример обобщения. Это показывает, что даны два типа, Box<A> а также Box<B> Вы не можете предполагать присваиваемость, основанную на отношении "внутренних" типов (A а также B).

Другие вопросы по тегам