将通用事件传递给 Guava EventBus?
Passing generic event to Guava EventBus?
我非常喜欢 Google Gauva 的 EventBus,以至于我想将它包含在我的一个 Swing GridBagBuilder API 中。目标是获取一个 Swing 组件并在任意事件中用它做一些事情,并将其订阅到 EventBus。问题是我认为 EventBus 完成的反射操作不喜欢我对任意事件类型的泛型。
本质上,该方法接受一个 BiConsumer,其中 C 是一个 Swing 组件,E 是订阅 EventBus 的任意事件类型。
public <E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) {
eventBus.register(new Object() {
@Subscribe
public void processEvent(E event) {
try {
consumer.accept(comp, event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
事件总线似乎正常工作,但我不断收到奇怪的 ClassCastException
错误。有什么办法可以使这项工作吗?还是我正在努力实现失败的原因?
更新:这是一个 SSCCE。当存在多种事件类型时,它会中断,并且在某个地方泛型和内部反射机制变得混乱,无法区分一种事件类型和另一种事件类型。
import java.awt.Component;
import java.util.function.BiConsumer;
import javax.swing.JButton;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
public class EventBusTest<C extends Component> {
private final C comp;
public static void main(String[] args) {
final EventBus eventBus = new EventBus();
EventBusTest<JButton> test = new EventBusTest<>(new JButton("Hello"));
test.subscribe(eventBus, (JButton c, SomeEvent e) -> System.out.println("Hello"));
test.subscribe(eventBus, (JButton c, SomeOtherEvent e) -> System.out.println("World"));
eventBus.post(new SomeEvent());
}
private EventBusTest(C comp) {
this.comp = comp;
}
public<E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) {
eventBus.register(new Object() {
@Subscribe
public void processEvent(E event) {
try {
consumer.accept(comp, event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private static final class SomeEvent {}
private static final class SomeOtherEvent {}
}
这是控制台打印...
java.lang.ClassCastException: com.swa.rm.pricing.EventBusTest$SomeEvent cannot be cast to com.swa.rm.pricing.EventBusTest$SomeOtherEvent
at com.swa.rm.pricing.EventBusTest$$Lambda/28594521.accept(Unknown Source)
at com.swa.rm.pricing.EventBusTest.processEvent(EventBusTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at com.swa.rm.pricing.EventBusTest.main(EventBusTest.java:21)
Hello
subscribe()
中的匿名 Object
子类中的类型参数 E
将始终被删除,因为没有具体类型来具体化它。 E
的擦除只是 Object
,所以没有什么能阻止你的 processEvent()
方法被任何类型调用。
要解决此问题,您需要传递一个类型标记(Class<E>
可能就足够了)并在调用 [=18] 之前用它来检查运行时类型实际上是 E
=]回调。
我非常喜欢 Google Gauva 的 EventBus,以至于我想将它包含在我的一个 Swing GridBagBuilder API 中。目标是获取一个 Swing 组件并在任意事件中用它做一些事情,并将其订阅到 EventBus。问题是我认为 EventBus 完成的反射操作不喜欢我对任意事件类型的泛型。
本质上,该方法接受一个 BiConsumer,其中 C 是一个 Swing 组件,E 是订阅 EventBus 的任意事件类型。
public <E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) {
eventBus.register(new Object() {
@Subscribe
public void processEvent(E event) {
try {
consumer.accept(comp, event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
事件总线似乎正常工作,但我不断收到奇怪的 ClassCastException
错误。有什么办法可以使这项工作吗?还是我正在努力实现失败的原因?
更新:这是一个 SSCCE。当存在多种事件类型时,它会中断,并且在某个地方泛型和内部反射机制变得混乱,无法区分一种事件类型和另一种事件类型。
import java.awt.Component;
import java.util.function.BiConsumer;
import javax.swing.JButton;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
public class EventBusTest<C extends Component> {
private final C comp;
public static void main(String[] args) {
final EventBus eventBus = new EventBus();
EventBusTest<JButton> test = new EventBusTest<>(new JButton("Hello"));
test.subscribe(eventBus, (JButton c, SomeEvent e) -> System.out.println("Hello"));
test.subscribe(eventBus, (JButton c, SomeOtherEvent e) -> System.out.println("World"));
eventBus.post(new SomeEvent());
}
private EventBusTest(C comp) {
this.comp = comp;
}
public<E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) {
eventBus.register(new Object() {
@Subscribe
public void processEvent(E event) {
try {
consumer.accept(comp, event);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private static final class SomeEvent {}
private static final class SomeOtherEvent {}
}
这是控制台打印...
java.lang.ClassCastException: com.swa.rm.pricing.EventBusTest$SomeEvent cannot be cast to com.swa.rm.pricing.EventBusTest$SomeOtherEvent
at com.swa.rm.pricing.EventBusTest$$Lambda/28594521.accept(Unknown Source)
at com.swa.rm.pricing.EventBusTest.processEvent(EventBusTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at com.swa.rm.pricing.EventBusTest.main(EventBusTest.java:21)
Hello
subscribe()
中的匿名 Object
子类中的类型参数 E
将始终被删除,因为没有具体类型来具体化它。 E
的擦除只是 Object
,所以没有什么能阻止你的 processEvent()
方法被任何类型调用。
要解决此问题,您需要传递一个类型标记(Class<E>
可能就足够了)并在调用 [=18] 之前用它来检查运行时类型实际上是 E
=]回调。