Replace includeSubtypes with @Polymorphic

The new @Polymorphic annotation serves the exact same purpose as
@Event(includeSubtypes = true), 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:
2021-02-15 10:55:30 +01:00
parent e040f6ab1b
commit 3a6ebe9a19
7 changed files with 54 additions and 38 deletions

View File

@ -21,6 +21,7 @@ import java.lang.annotation.*;
*
* @author Kai S. K. Engelbart
* @since 0.0.1
* @see Polymorphic
*/
@Documented
@Retention(RUNTIME)
@ -38,14 +39,6 @@ public @interface Event {
*/
int priority() default 100;
/**
* Defines whether instances of subtypes of the event type are dispatched to the event handler.
*
* @return whether the event handler includes subtypes
* @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.

View File

@ -104,7 +104,7 @@ public final class EventBus {
for (var binding : bindings.entrySet())
if (binding.getKey().isAssignableFrom(eventClass))
for (var handler : binding.getValue())
if (handler.includeSubtypes())
if (handler.isPolymorphic())
handlers.add(handler);
return new ArrayList<>(handlers);

View File

@ -13,10 +13,11 @@ import dev.kske.eventbus.core.Event.USE_PARAMETER;
*/
final class EventHandler implements Comparable<EventHandler> {
private final EventListener listener;
private final Method method;
private final Event annotation;
private final Class<? extends IEvent> eventType;
private final EventListener listener;
private final Method method;
private final Event annotation;
private final Class<? extends IEvent> eventType;
private final boolean polymorphic;
/**
* Constructs an event handler.
@ -30,9 +31,9 @@ final class EventHandler implements Comparable<EventHandler> {
*/
@SuppressWarnings("unchecked")
EventHandler(EventListener listener, Method method, Event annotation) throws EventBusException {
this.listener = listener;
this.method = method;
this.annotation = annotation;
this.listener = listener;
this.method = method;
this.annotation = annotation;
// Check for correct method signature and return type
if (method.getParameterCount() == 0 && annotation.eventType().equals(USE_PARAMETER.class))
@ -55,7 +56,8 @@ final class EventHandler implements Comparable<EventHandler> {
throw new EventBusException(param + " is not of type IEvent!");
eventType = (Class<? extends IEvent>) param;
}
this.eventType = eventType;
this.eventType = eventType;
polymorphic = method.isAnnotationPresent(Polymorphic.class);
// Allow access if the method is non-public
method.setAccessible(true);
@ -65,7 +67,7 @@ final class EventHandler implements Comparable<EventHandler> {
* 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.
* <p>
* This is used to retrieve event handlers in the correct order from a tree set.
* This is used to retrieve event handlers in order of descending priority from a tree set.
*
* @since 0.0.1
*/
@ -91,15 +93,11 @@ final class EventHandler implements Comparable<EventHandler> {
*/
void execute(IEvent event) throws EventBusException {
try {
if (annotation.eventType().equals(USE_PARAMETER.class))
if (annotation.eventType() == USE_PARAMETER.class)
method.invoke(listener, event);
else
method.invoke(listener);
} catch (
IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e
) {
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new EventBusException("Failed to invoke event handler!", e);
}
}
@ -123,10 +121,11 @@ final class EventHandler implements Comparable<EventHandler> {
int getPriority() { return annotation.priority(); }
/**
* @return whether this handler includes subtypes
* @since 0.0.4
* @return whether this handler is polymorphic
* @since 1.0.0
* @see Polymorphic
*/
boolean includeSubtypes() { return annotation.includeSubtypes(); }
boolean isPolymorphic() { return polymorphic; }
/**
* @return the event type this handler listens to

View File

@ -0,0 +1,20 @@
package dev.kske.eventbus.core;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* Allows an event handler to receive events that are subtypes of the declared event type.
* <p>
* This is useful when defining an event handler for an interface or an abstract class.
*
* @author Kai S. K. Engelbart
* @since 1.0.0
* @see Event
*/
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface Polymorphic {}

View File

@ -38,7 +38,8 @@ class DispatchTest implements EventListener {
bus.dispatch(new SimpleEvent());
}
@Event(eventType = SimpleEvent.class, includeSubtypes = true, priority = 200)
@Event(eventType = SimpleEvent.class, priority = 200)
@Polymorphic
void onSimpleEventFirst() {
++hits;
assertTrue(hits == 1 || hits == 2);