Replace priority with @Priority

The new @Priority annotation serves the exact same purpose as
@Event(priority = ...), but should be easier to read in complex handler
declarations. It has to be used in conjunction with the @Event
annotation, not instead of it.
This commit is contained in:
Kai S. K. Engelbart 2021-02-15 12:06:33 +01:00
parent 3a6ebe9a19
commit 9b1c708514
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
7 changed files with 75 additions and 43 deletions

View File

@ -73,20 +73,18 @@ private void onSimpleEvent(SimpleEvent event) { ... }
## Event Handler Execution Order
Sometimes when using multiple handlers for one event, it might be useful to know in which order they will be executed.
Event Bus provides a mechanism to ensure the correct propagation of events: the `priority`.
Sometimes when using multiple handlers for one event, it might be useful to define in which order they will be executed.
Event Bus assigns a priority to every handler, which is `100` by default, but can be explicitly set using the `@Priority` annotation in addition to `@Event`:
Priority can be set on the `@Event` annotation like that:
```java
@Event(priority=100)
@Event
@Priority(250)
private void onSimpleEvent(SimpleEvent event) { ... }
```
The default priority for events is `100`.
**Important:**
Events are dispatched top-down, meaning the event handler with the highest priority will be executed first.
If no priority is set or multiple handlers have the same priority, the order of execution is undefined.
Events are dispatched to handlers in descending order of their priority.
The execution order is undefined for handlers with the same priority.
## Parameter-Less Event Handlers
@ -108,12 +106,14 @@ In some cases it might be useful to stop the propagation of an event.
Event Bus makes this possible with event consumption:
```java
@Event(eventType = SimpleEvent.class, priority=100)
@Event(eventType = SimpleEvent.class)
@Priority(100)
private void onSimpleEvent() {
EventBus.getInstance().cancel();
}
@Event(eventType = SimpleEvent.class, priority=50)
@Event(eventType = SimpleEvent.class)
@Priority(50)
private void onSimpleEvent2() {
System.out.println("Will not be printed!");
}

View File

@ -80,7 +80,7 @@ public class EventProcessor extends AbstractProcessor {
if (declaredElement.getKind() == ElementKind.INTERFACE
|| declaredElement.getModifiers().contains(Modifier.ABSTRACT))
warning(paramElement,
"Parameter should be instantiable or handler should include subtypes");
"Parameter should be instantiable or handler should use @Polymorphic");
}
// Check listener for interface implementation

View File

@ -22,23 +22,13 @@ import java.lang.annotation.*;
* @author Kai S. K. Engelbart
* @since 0.0.1
* @see Polymorphic
* @see Priority
*/
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Event {
/**
* Defines the priority of the event handler. Handlers are executed in descending order of their
* priority.
* <p>
* The execution order of handlers with the same priority is undefined.
*
* @return the priority of the event handler
* @since 0.0.1
*/
int priority() default 100;
/**
* Defines the event type the handler listens to. If this value is set, the handler is not
* allowed to declare parameters.

View File

@ -13,11 +13,20 @@ import dev.kske.eventbus.core.Event.USE_PARAMETER;
*/
final class EventHandler implements Comparable<EventHandler> {
/**
* The priority assigned to every event handler without an explicitly defined priority.
*
* @since 1.0.0
* @see Priority
*/
public static final int DEFAULT_PRIORITY = 100;
private final EventListener listener;
private final Method method;
private final Event annotation;
private final Class<? extends IEvent> eventType;
private final boolean polymorphic;
private final int priority;
/**
* Constructs an event handler.
@ -58,14 +67,17 @@ final class EventHandler implements Comparable<EventHandler> {
}
this.eventType = eventType;
polymorphic = method.isAnnotationPresent(Polymorphic.class);
priority = method.isAnnotationPresent(Priority.class)
? method.getAnnotation(Priority.class).value()
: DEFAULT_PRIORITY;
// Allow access if the method is non-public
method.setAccessible(true);
}
/**
* Compares this to another event handler based on {@link Event#priority()}. In case of equal
* priority a non-zero value based on hash codes is returned.
* Compares this to another event handler based on priority. In case of equal priority a
* non-zero value based on hash codes is returned.
* <p>
* This is used to retrieve event handlers in order of descending priority from a tree set.
*
@ -73,7 +85,7 @@ final class EventHandler implements Comparable<EventHandler> {
*/
@Override
public int compareTo(EventHandler other) {
int priority = other.annotation.priority() - annotation.priority();
int priority = other.priority - this.priority;
if (priority == 0)
priority = listener.hashCode() - other.listener.hashCode();
return priority == 0 ? hashCode() - other.hashCode() : priority;
@ -81,7 +93,8 @@ final class EventHandler implements Comparable<EventHandler> {
@Override
public String toString() {
return String.format("EventHandler[method=%s, annotation=%s]", method, annotation);
return String.format("EventHandler[method=%s, eventType=%s, polymorphic=%b, priority=%d]",
method, annotation.eventType(), polymorphic, priority);
}
/**
@ -109,16 +122,17 @@ final class EventHandler implements Comparable<EventHandler> {
EventListener getListener() { return listener; }
/**
* @return the event annotation
* @since 0.0.1
* @return the event type this handler listens to
* @since 0.0.3
*/
Event getAnnotation() { return annotation; }
Class<? extends IEvent> getEventType() { return eventType; }
/**
* @return the priority of the event annotation
* @return the priority of this handler
* @since 0.0.1
* @see Priority
*/
int getPriority() { return annotation.priority(); }
int getPriority() { return priority; }
/**
* @return whether this handler is polymorphic
@ -126,10 +140,4 @@ final class EventHandler implements Comparable<EventHandler> {
* @see Polymorphic
*/
boolean isPolymorphic() { return polymorphic; }
/**
* @return the event type this handler listens to
* @since 0.0.3
*/
Class<? extends IEvent> getEventType() { return eventType; }
}

View File

@ -0,0 +1,30 @@
package dev.kske.eventbus.core;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* Defines the priority of an event handler. Handlers are executed in descending order of their
* priority.
* <p>
* Handlers without this annotation have the default priority of 100.
* <p>
* The execution order of handlers with the same priority is undefined.
*
* @author Kai S. K. Engelbart
* @since 1.0.0
* @see Event
*/
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Priority {
/**
* @return the priority of the event handler
* @since 1.0.0
*/
int value();
}

View File

@ -39,13 +39,15 @@ class CancelTest implements EventListener {
assertEquals(1, hits);
}
@Event(eventType = SimpleEvent.class, priority = 100)
@Event(eventType = SimpleEvent.class)
@Priority(100)
void onSimpleFirst() {
++hits;
bus.cancel();
}
@Event(eventType = SimpleEvent.class, priority = 50)
@Event(eventType = SimpleEvent.class)
@Priority(50)
void onSimpleSecond() {
++hits;
}

View File

@ -38,20 +38,22 @@ class DispatchTest implements EventListener {
bus.dispatch(new SimpleEvent());
}
@Event(eventType = SimpleEvent.class, priority = 200)
@Event(eventType = SimpleEvent.class)
@Priority(200)
@Polymorphic
void onSimpleEventFirst() {
++hits;
assertTrue(hits == 1 || hits == 2);
}
@Event(eventType = SimpleEvent.class, priority = 150)
@Event(eventType = SimpleEvent.class)
@Priority(150)
static void onSimpleEventSecond() {
++hits;
assertEquals(3, hits);
}
@Event(priority = 100)
@Event
void onSimpleEventThird(SimpleEvent event) {
++hits;
assertEquals(4, hits);