JavaEE CDI in Weld: Generic Events?

狂风中的少年 提交于 2019-12-22 10:02:52

问题


I have an idea for a specific event handling based on generics, but seems like Weld can't handle them. I asked google but couldn't find an alternative CDI extension for this.

Question: is there a CDI extension, that can handle event propagation of generic-typed events?

In the following the explicit problem I have.

I have three general events, EntityCreated, EntityChanged and EntityDeleted. The base class for them is defined like this:

public abstract class DatabaseEvent<TargetType> {

    public TargetType target;

    public DatabaseEvent(TargetType target) {
        this.target = target;
    }
}

The events then are simple inherited classes:

public class EntityCreatedEvent<TargetType> extends DatabaseEvent<TargetType> {

    public EntityCreatedEvent(TargetType target) {
        super(target);
    }
}

I fire them like this:

public abstract class MyHome<EntityType> {

    private EntityType entity;

    @Inject
    Event<EntityCreatedEvent<EntityType>> entityCreatedEvent;

    public void fireCreatedEvent() {
        EntityCreatedEvent<EntityType> payload = new EntityCreatedEvent<EntityType>(entity);
        entityCreatedEvent.fire(payload);
    }
}

I want to observe them like this:

public void handleProjectCreated(@Observes EntityCreatedEvent<Project> event) { ... }

When launching the server Weld tells me it can't handle generic-typed events. The CDI-way of doing things would be to use additional qualifiers instead of the generics to distiguish them, e.g.:

public void handleProjectCreated(@Observes @ProjectEvent EntityCreatedEvent event) { ... }

However, I fire the events from that MyHome base class, where I can't just fire with the @ProjectEvent: it might not be a project but another type.

My solution up to now is to skip that typing altogether and handle them like this:

public void handleProjectCreated(@Observes EntityCreatedEvent event) { 
    if(event.target instanceof Project) { ... }
}

This solution is okay, but not perfect.


回答1:


I guess you can do this with dinamically binding qualifier members. This is what your code would look like:

public abstract class MyHome {

    private EntityType entity;

    @Inject
    Event<EntityCreatedEvent> entityCreatedEvent;

    public void fireCreatedEvent() {
        entityCreatedEvent.select(getTypeBinding()).fire(new EntityCreatedEvent(entity));
    }

    private TypeBinding getTypeBinding() {
        return new TypeBinding() {
        public Class<? extends EntityType> value() {return entity.getClass();}
    };
}

@Qualifier
@Target({ PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface EntityTypeQualifier {
    Class<? extends EntityType> value();
}

public abstract class TypeBinding extends AnnotationLiteral<EntityTypeQualifier> implements EntityTypeQualifier {}

//Observers
public void handleEntityType1Created(@Observes @EntityTypeQualifier(EntityType1.class) EntityCreatedEvent event) {}
public void handleEntityType2Created(@Observes @EntityTypeQualifier(EntityType2.class) EntityCreatedEvent event) {}



回答2:


As this CDI issue points it is not possible to fire an without having the type of T at runtime.

But, if you have the type of T (i.e. you have an instance) you can use the Event as an Instance, and select the event to be fired using a dynamic type literal.



来源:https://stackoverflow.com/questions/19135157/javaee-cdi-in-weld-generic-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!