Add subtype inclusion for event handlers

This commit is contained in:
Kai S. K. Engelbart 2020-09-20 12:20:29 +02:00
parent 7a3debe444
commit ba06b49368
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
7 changed files with 65 additions and 11 deletions

View File

@ -51,6 +51,15 @@ public class SimpleEventListener implements EventListener {
In this case, an event bus is created and used locally. 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. 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 ## Parameter-less event handlers
In some cases an event handler is not interested in the dispatched event instance. 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
<dependency> <dependency>
<groupId>dev.kske</groupId> <groupId>dev.kske</groupId>
<artifactId>event-bus</artifactId> <artifactId>event-bus</artifactId>
<version>0.0.3</version> <version>0.0.4</version>
</dependency> </dependency>
</dependencies> </dependencies>
``` ```

View File

@ -5,7 +5,7 @@
<groupId>dev.kske</groupId> <groupId>dev.kske</groupId>
<artifactId>event-bus</artifactId> <artifactId>event-bus</artifactId>
<version>0.0.3</version> <version>0.0.4</version>
<name>Event Bus</name> <name>Event Bus</name>
<description>An event handling framework for Java utilizing annotations.</description> <description>An event handling framework for Java utilizing annotations.</description>

View File

@ -36,6 +36,13 @@ public @interface Event {
*/ */
int priority() default 100; 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 * Defines the event type the handler listens to. If this value is set, the handler is not
* allowed to declare parameters. * allowed to declare parameters.

View File

@ -31,7 +31,7 @@ public final class EventBus {
return singletonInstance; return singletonInstance;
} }
private final Map<Class<? extends IEvent>, Collection<EventHandler>> bindings private final Map<Class<? extends IEvent>, TreeSet<EventHandler>> bindings
= new ConcurrentHashMap<>(); = new ConcurrentHashMap<>();
private final Set<EventListener> registeredListeners = ConcurrentHashMap.newKeySet(); private final Set<EventListener> registeredListeners = ConcurrentHashMap.newKeySet();
@ -55,8 +55,20 @@ public final class EventBus {
* @since 0.0.1 * @since 0.0.1
*/ */
private List<EventHandler> getHandlersFor(Class<? extends IEvent> eventClass) { private List<EventHandler> getHandlersFor(Class<? extends IEvent> eventClass) {
return bindings.containsKey(eventClass) ? new ArrayList<>(bindings.get(eventClass))
: new ArrayList<>(); // Get handlers defined for the event class
Set<EventHandler> 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);
} }
/** /**

View File

@ -117,6 +117,12 @@ final class EventHandler implements Comparable<EventHandler> {
*/ */
int getPriority() { return annotation.priority(); } 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 * @return the event type this handler listens to
* @since 0.0.3 * @since 0.0.3

View File

@ -1,6 +1,6 @@
package dev.kske.eventbus; package dev.kske.eventbus;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
@ -21,18 +21,29 @@ class EventBusTest implements EventListener {
@Test @Test
void testDispatch() { void testDispatch() {
EventBus.getInstance().dispatch(new SimpleEventSub());
EventBus.getInstance().dispatch(new SimpleEvent()); EventBus.getInstance().dispatch(new SimpleEvent());
} }
@Event(priority = 50) @Event(
private void onSimpleEventSecond(SimpleEvent event) { eventType = SimpleEvent.class,
includeSubtypes = true,
priority = 200
)
private void onSimpleEventFirst() {
++hits; ++hits;
assertEquals(2, hits); assertTrue(hits == 1 || hits == 2);
} }
@Event(eventType = SimpleEvent.class, priority = 150) @Event(eventType = SimpleEvent.class, priority = 150)
private void onSimpleEventFirst() { private void onSimpleEventSecond() {
++hits; ++hits;
assertEquals(1, hits); assertEquals(3, hits);
}
@Event(priority = 50)
private void onSimpleEventThird(SimpleEvent event) {
++hits;
assertEquals(4, hits);
} }
} }

View File

@ -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 {}