我想在CDI中触发一个事件,其类型我只能在运行时确定。例如,假设有一些实现类A
和AA
的接口AB
。我有两个观察员:
public void observeAA(@Observes AA aa) {
}
public void observeAA(@Observes AB ab) {
}
然后是一些事件制作人:
@Inject @Any
private Event<A> event;
public A getPayload();
public void fire() {
this.event.fire(getPayload());
}
这不起作用,因为A
既不是AA
或AB
的子类型(反之亦然)。我注意到有一个select
方法需要一个子类型:
public <U extends T> Event<U> select(Class<U> subtype, Annotation... qualifiers);
但是,它需要一个正确参数化的Class
对象,(如果我错了,请更正),我无法在运行时构建。
是否有任何解决方案或我是否必须使用限定符(可能是使用Class<?>
方法的注释)?
答案 0 :(得分:1)
我最终使用了Class<?>
成员的限定符。
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface EventType {
Class<?> value();
}
public class Dispatcher {
@Inject @Any
private Event<A> event;
public void fireEvent(A a) {
this.event.select(
getTypeAnnotation(
a.getClass())).fire(a);
}
public static EventType getTypeAnnotation(
final Class<?> type) {
return (EventType) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[]{EventType.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (method.equals(
EventType.class.getMethod("value"))) {
return type;
} else if (method.equals(Annotation.class.getMethod(
"annotationType"))) {
return EventType.class;
} else if (method.getName().equals("hashCode")) {
return 127 * "value".hashCode() ^ type.hashCode();
} else if (method.getName().equals("equals")) {
return (args[0] instanceof EventType &&
((EventType)args[0]).value()
.equals(type));
}
return null;
}
});
}
}
public class X {
public void observeA(
@Observes @EventType(AA.class) A a) {
...
修改强>
这是一种实例化注释的简单方法:
public abstract static class ConfigTypeAnnotation
extends AnnotationLiteral<ConfigType>
implements ConfigType { }
public static ConfigType getConfigTypeAnnotation(final Class<?> type) {
return new ConfigTypeAnnotation() {
@Override
public Class<?> value() {
return type;
}
};
}
答案 1 :(得分:0)
为什么不使用
public void observeA(@Observes A a) {
}
根据“a”实现类决定要做什么?
public void observeA(@Observes A a) {
if (a instanceof AA)
{
...
}
else
...
}
答案 2 :(得分:0)
我有类似的要求,最后注入了BeanManager来解雇事件。