java - 将通用事件传递给 Guava EventBus?

标签 java swing generics reflection guava

我已经非常喜欢 Google Gauva 的 EventBus,以至于我想将它包含在我的一个 Swing 中 GridBagBuilder蜜蜂。目标是获取一个 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$14/28594521.accept(Unknown Source)
    at com.swa.rm.pricing.EventBusTest$1.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

最佳答案

类型参数E在你的匿名Object subscribe() 中的子类将始终被删除,因为没有具体的类型来具体化它。删除 E只是Object , 所以没有什么能阻止你的 processEvent()方法不会被任何类型调用。

要解决此问题,您需要传递一个类型标记(Class<E> 可能就足够了)并使用它来检查运行时类型实际上是 E在调用 BiConsumer 之前回调。

关于java - 将通用事件传递给 Guava EventBus?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28229374/

相关文章:

java - 在父类(super class)中调用父类(super class)方法

java - 使用泛型获取 java.lang.Class

java - 如何将 JLabel 添加到另一个类的 JFrame 中?

java - 表格单元格自动右对齐

c# - 方法的类型参数与其外部类型相同

java - 尝试在 Java 中实现 Iterable 时使用泛型时出错

java - 将数据存储在集合中

java - 从 StringBuilder 获取字符串

java - cvc-数据类型-valid.1.2.1 : 'mylns:xsi' is not a valid value for 'NCName'

java - 使用背景图像分层 JPanel