javacdiquarkusjboss-weldcdi-events

Is it possible to create a CDI Event factory?


On my quarkus app i have a application scope service with a lot of cdi event injections

@ApplicationScoped
public class SomeService {

    @Inject
    Event<EventA> eventAEmitter;
    
    @Inject
    Event<EventB> eventBEmitter;
    
    ...


    public void someFunction() {
        eventAEmitter.fire(new EventA(X, Y));
        ...
        eventBEmitter.fire(new EventB(Z, W));
    }
}

@ApplicationScoped
public class Observer {

    private static final Logger LOGGER = Logger.getLogger(Observer.class);


    public void onEventA(@Observes(during = TransactionPhase.AFTER_SUCCESS) EventA event) {

        LOGGER.info("observer: EventA: " + event);
    }

    public void onEventB(@Observes(during = TransactionPhase.AFTER_SUCCESS) EventB event) {

        LOGGER.info("observer: EventB: " + event);
    }
}


public class EventA {

    public String x;
    public SomeObjectA y;
   
}
    
public class EventB {

    public Long z;
    public SomeObjectB w;
   
}
// note that EventA and EventB has different members

i'm looking for a way to create factory that given a class or a string key it will retrieve the wanted event
something like this:

@ApplicationScoped
public class SomeService {

    @Inject
    EventFactory eventfactory;


    public void someFunction() {

        Event<EventA> eventAEmitter = eventfactory.getEvent("key-that-represent-event-a");
        eventAEmitter.fire(new EventA(X, Y));

        Event<EventB> eventBEmitter = eventfactory.getEvent(EventB.class);
        eventBEmitter.fire(new EventB(Z, W));
    }
}

i'm quite new to CDI, is there a way to create this mechanism?

i thought of creating an application scoped class and inject all the events over there but i'm not sure how to access these injected beans, and im not aware of the advantages/disadvantages of injecting the events eagerly
something like that:

@ApplicationScoped
public class EventFactory {

    @Inject
    Event<EventA> eventAEmitter;
    
    @Inject
    Event<EventB> eventBEmitter;
    
    ...


    public void getEvent(Class<?> clazz) {
        ...
    }
}

Solution

  • ok so i found a way to implement it and get the behavior i'm looking for

    i still don't know the advantages/disadvantages or the existence of any caveats.

    i've created a Singleton scoped bean and Injected Event<Object> and wrapped the functionality of the Event api, specifically the select method with a default a qualifier.

    @Singleton
    public class EventFactory {
    
        @Inject
        Event<Object> eventEmitter;
    
        public <U extends Object> Event<U> select(Class<U> subtype) {
            return objEventEmitter.select(subtype, new AnnotationLiteral<InternalEventQualifier>(){});
        }
    }
    
    
    @ApplicationScoped
    public class SomeService {
    
        @Inject
        EventFactory eventFactory;
    
        public void someMethod(...) {
            ...
            var emitter = eventFactory.select(EventA.class);
            
            emitter.fire(new EventA(...));
        }
    }