Как использовать наследование и списки событий CDI?

Можно ли использовать дисперсию типов в событиях CDI? вот случай:

  • Предположим, у меня есть корневой тип события MyEvent и подкласс DummyEvent.
  • Моя цель - обработать список событий, полученных из удаленного источника List<? extends MyEvent>, содержащий DummyEvent экземпляров

Как я могу это сделать?

Если я перебираю коллекцию, вызывая fire() для каждого события, она будет вызывать @Observes MyEvent evt, но не @Observes DummyEvent evt методов.

** Обновить **

Создал пример кода, чтобы прояснить проблему:

https://github.com/jfaerman/jfaerman/blob/master/test-cdi/src/main/java/jfaerman/App.java

Я хотел бы, чтобы событие запускалось дважды, один раз индивидуально и один раз из списка.


person Julio Faerman    schedule 28.01.2012    source источник
comment
Какую реализацию CDI вы используете?   -  person John Ament    schedule 30.01.2012


Ответы (2)


Он работает, вводя BeanManager вместо Event, как это проверено этим сервлетом:

https://github.com/jfaerman/cdi-tests/blob/master/src/main/java/jfaerman/TestEventsServlet.java

Ответил Йозеф Хартингер в этой ветке на форуме Weld:

https://community.jboss.org/message/716185

person Julio Faerman    schedule 13.02.2012
comment
очень приятно +1 за то, что поделились с нами - person dcernahoschi; 14.02.2012

Ммм, я не понимаю... как выглядит ваш фактический код перед запуском события? ASFAIK вы вводите интерфейс javax.enterprise.event.Event и передаете экземпляр его методу огня, который тем самым объявляет вызываемый наблюдатель. И если задействовано наследование, как в вашем случае, оба наблюдателя будут вызываться, если вы запускаете DummyEvent. Если вы хотите дополнительно указать события, вы должны использовать квалификаторы.

@Inject @Any Event<DummyEvent> dummyEvent;
...
dummyEvent.fire(list.get(i));

/* изменить */

«Проблема» заключается в следующей строке кода:

weld.event().select(MyEvent.class).fire(evt);

Как только вы укажете тип события (MyEvent.class), фактический тип экземпляра события (evt) больше не имеет значения. Одна из возможностей — расширить иерархию классов с помощью квалификаций. Например:

@ChildEvent.Child
public class ChildEvent extends BaseEvent{

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
    public @interface Child{
    }

    public void eventAction() {
        System.out.println("child");
    }    
}

После этого дополнительно укажите Наблюдателя:

public void observerChild(@Observes @ChildEvent.Child BaseEvent child){
        System.out.println("child with annotation event");
}

Наконец, когда у вас есть только доступ к базовым классам, как в вашем примере, где вы перебираете список, вы можете указать точный тип/квалификатор перед запуском такого события:

for (BaseEvent e : list){
    childEvent.select(e.getClass().getAnnotations()[0]).fire(e);
}

Как упоминалось выше, если у вас есть общий наблюдатель (показан ниже), он будет вызываться для каждого события.

public void observerBase(@Observes  BaseEvent base){
    System.out.println("base event");
}
person Roland Tiefenbrunner    schedule 30.01.2012
comment
Пожалуйста, посмотрите пример кода, который я только что добавил, надеюсь, проблема станет немного понятнее. - person Julio Faerman; 07.02.2012
comment
Отредактировал ответ, может быть, это поможет. - person Roland Tiefenbrunner; 10.02.2012
comment
Это помогает, но есть решение, использующее только типы... спасибо за публикацию, научился этому трюку :) - person Julio Faerman; 13.02.2012