Как использовать наследование и списки событий CDI? - PullRequest
8 голосов
/ 28 января 2012

Можно ли использовать дисперсию типа в событиях 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

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

Ответы [ 2 ]

3 голосов
/ 13 февраля 2012

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

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

Ответ Jozef Hartinger в этой теме на форуме Weld:

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

1 голос
/ 31 января 2012

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

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

/ * edit * /

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

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

После этого дополнительно укажите Observer:

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

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

...