diff --git a/README.md b/README.md
index 3345abb..1844da4 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,15 @@ public class SimpleEventListener implements EventListener {
In this case, an event bus is created and used locally.
In a more sophisticated example the class would acquire an external event bus that is used by multiple classes.
+## Event handlers for subtypes
+
+On certain occasions its practical for an event handler to accept both events of the specified type, as well as subclasses of that event.
+To include subtypes for an event handler, use the `includeSubtypes` parameter as follows:
+
+```java
+@Event(includeSubtypes = true)
+```
+
## Parameter-less event handlers
In some cases an event handler is not interested in the dispatched event instance.
@@ -82,7 +91,7 @@ To include it inside your project, just add the Maven repository and the depende
dev.kske
event-bus
- 0.0.3
+ 0.0.4
```
diff --git a/pom.xml b/pom.xml
index 116c3c6..7e54c52 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
dev.kske
event-bus
- 0.0.3
+ 0.0.4
Event Bus
An event handling framework for Java utilizing annotations.
diff --git a/src/main/java/dev/kske/eventbus/Event.java b/src/main/java/dev/kske/eventbus/Event.java
index dc208af..ebfb0b9 100644
--- a/src/main/java/dev/kske/eventbus/Event.java
+++ b/src/main/java/dev/kske/eventbus/Event.java
@@ -36,6 +36,13 @@ public @interface Event {
*/
int priority() default 100;
+ /**
+ * Defines whether instances of subtypes of the event type are dispatched to the event handler.
+ *
+ * @since 0.0.4
+ */
+ boolean includeSubtypes() default false;
+
/**
* Defines the event type the handler listens to. If this value is set, the handler is not
* allowed to declare parameters.
diff --git a/src/main/java/dev/kske/eventbus/EventBus.java b/src/main/java/dev/kske/eventbus/EventBus.java
index cdb93af..a069e00 100644
--- a/src/main/java/dev/kske/eventbus/EventBus.java
+++ b/src/main/java/dev/kske/eventbus/EventBus.java
@@ -31,7 +31,7 @@ public final class EventBus {
return singletonInstance;
}
- private final Map, Collection> bindings
+ private final Map, TreeSet> bindings
= new ConcurrentHashMap<>();
private final Set registeredListeners = ConcurrentHashMap.newKeySet();
@@ -55,8 +55,20 @@ public final class EventBus {
* @since 0.0.1
*/
private List getHandlersFor(Class extends IEvent> eventClass) {
- return bindings.containsKey(eventClass) ? new ArrayList<>(bindings.get(eventClass))
- : new ArrayList<>();
+
+ // Get handlers defined for the event class
+ Set handlers
+ = bindings.containsKey(eventClass) ? bindings.get(eventClass)
+ : new TreeSet<>();
+
+ // Get subtype handlers
+ for (var binding : bindings.entrySet())
+ if (binding.getKey().isAssignableFrom(eventClass))
+ for (var handler : binding.getValue())
+ if (handler.includeSubtypes())
+ handlers.add(handler);
+
+ return new ArrayList<>(handlers);
}
/**
diff --git a/src/main/java/dev/kske/eventbus/EventHandler.java b/src/main/java/dev/kske/eventbus/EventHandler.java
index f4aa355..2dfb257 100644
--- a/src/main/java/dev/kske/eventbus/EventHandler.java
+++ b/src/main/java/dev/kske/eventbus/EventHandler.java
@@ -117,6 +117,12 @@ final class EventHandler implements Comparable {
*/
int getPriority() { return annotation.priority(); }
+ /**
+ * @return whether this handler includes subtypes
+ * @since 0.0.4
+ */
+ boolean includeSubtypes() { return annotation.includeSubtypes(); }
+
/**
* @return the event type this handler listens to
* @since 0.0.3
diff --git a/src/test/java/dev/kske/eventbus/EventBusTest.java b/src/test/java/dev/kske/eventbus/EventBusTest.java
index adb2d57..c754bb9 100644
--- a/src/test/java/dev/kske/eventbus/EventBusTest.java
+++ b/src/test/java/dev/kske/eventbus/EventBusTest.java
@@ -1,6 +1,6 @@
package dev.kske.eventbus;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.*;
@@ -21,18 +21,29 @@ class EventBusTest implements EventListener {
@Test
void testDispatch() {
+ EventBus.getInstance().dispatch(new SimpleEventSub());
EventBus.getInstance().dispatch(new SimpleEvent());
}
- @Event(priority = 50)
- private void onSimpleEventSecond(SimpleEvent event) {
+ @Event(
+ eventType = SimpleEvent.class,
+ includeSubtypes = true,
+ priority = 200
+ )
+ private void onSimpleEventFirst() {
++hits;
- assertEquals(2, hits);
+ assertTrue(hits == 1 || hits == 2);
}
@Event(eventType = SimpleEvent.class, priority = 150)
- private void onSimpleEventFirst() {
+ private void onSimpleEventSecond() {
++hits;
- assertEquals(1, hits);
+ assertEquals(3, hits);
+ }
+
+ @Event(priority = 50)
+ private void onSimpleEventThird(SimpleEvent event) {
+ ++hits;
+ assertEquals(4, hits);
}
}
diff --git a/src/test/java/dev/kske/eventbus/SimpleEventSub.java b/src/test/java/dev/kske/eventbus/SimpleEventSub.java
new file mode 100644
index 0000000..3030eaf
--- /dev/null
+++ b/src/test/java/dev/kske/eventbus/SimpleEventSub.java
@@ -0,0 +1,9 @@
+package dev.kske.eventbus;
+
+/**
+ * Subclass of {@link SimpleEvent} for testing purposes.
+ *
+ * @author Kai S. K. Engelbart
+ * @since 0.0.4
+ */
+public class SimpleEventSub extends SimpleEvent {}