Remove EventListener and IEvent marker interfaces
This allows Event Bus to interface with existing classes without modification.
This commit is contained in:
parent
cd2e7ad023
commit
002180ed3b
13
README.md
13
README.md
@ -3,7 +3,7 @@
|
|||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
This library allows passing events between different objects without them having a direct reference to each other.
|
This library allows passing events between different objects without them having a direct reference to each other.
|
||||||
Any class can be made an event by implementing the `IEvent` interface.
|
Any object can serve as an event.
|
||||||
|
|
||||||
Using an instance of the `EventBus` class, an instant of the event class can be dispatched.
|
Using an instance of the `EventBus` class, an instant of the event class can be dispatched.
|
||||||
This means that it will be forwarded to all listeners registered for it at the event bus.
|
This means that it will be forwarded to all listeners registered for it at the event bus.
|
||||||
@ -13,16 +13,13 @@ In addition, a singleton instance of the event bus is provided by the `EventBus#
|
|||||||
To listen to events, register event handling methods using the `Event` annotation.
|
To listen to events, register event handling methods using the `Event` annotation.
|
||||||
For this to work, the method must have a return type of `void` and declare a single parameter of the desired event type.
|
For this to work, the method must have a return type of `void` and declare a single parameter of the desired event type.
|
||||||
Alternatively, a parameter-less event handler can be declared as shown [below](#parameter-less-event-handlers).
|
Alternatively, a parameter-less event handler can be declared as shown [below](#parameter-less-event-handlers).
|
||||||
Additionally, the class containing the method must implement the `EventListener` interface.
|
|
||||||
|
|
||||||
## A Simple Example
|
## A Simple Example
|
||||||
|
|
||||||
Lets look at a simple example: we declare the empty class `SimpleEvent` that implements `IEvent` and can thus be used as an event.
|
Lets look at a simple example: we declare the empty class `SimpleEvent` whose objects can be used as events.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import dev.kske.eventbus.core.IEvent;
|
public class SimpleEvent {}
|
||||||
|
|
||||||
public class SimpleEvent implements IEvent {}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, an event listener for the `SimpleEvent` is declared:
|
Next, an event listener for the `SimpleEvent` is declared:
|
||||||
@ -30,7 +27,7 @@ Next, an event listener for the `SimpleEvent` is declared:
|
|||||||
```java
|
```java
|
||||||
import dev.kske.eventbus.core.*;
|
import dev.kske.eventbus.core.*;
|
||||||
|
|
||||||
public class SimpleEventListener implements EventListener {
|
public class SimpleEventListener {
|
||||||
|
|
||||||
public SimpleEventListener() {
|
public SimpleEventListener() {
|
||||||
|
|
||||||
@ -165,7 +162,7 @@ opens my.module to dev.kske.eventbus.core;
|
|||||||
To assist you with writing event listeners, the Event Bus AP (Annotation Processor) module enforces correct usage of the `@Event` annotation during compile time.
|
To assist you with writing event listeners, the Event Bus AP (Annotation Processor) module enforces correct usage of the `@Event` annotation during compile time.
|
||||||
This reduces difficult-to-debug bugs that occur during runtime to compile-time errors which can be easily fixed.
|
This reduces difficult-to-debug bugs that occur during runtime to compile-time errors which can be easily fixed.
|
||||||
|
|
||||||
The event annotation processor detects invalid event handlers, missing `EventListener` implementations, event type issues with more to come in future versions.
|
The event annotation processor detects invalid event handlers and event type issues with more to come in future versions.
|
||||||
|
|
||||||
When using Maven, it can be registered using the Maven Compiler Plugin:
|
When using Maven, it can be registered using the Maven Compiler Plugin:
|
||||||
|
|
||||||
|
@ -34,8 +34,7 @@ public class EventProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
private void processRound(Set<ExecutableElement> eventHandlers) {
|
private void processRound(Set<ExecutableElement> eventHandlers) {
|
||||||
for (ExecutableElement eventHandler : eventHandlers) {
|
for (ExecutableElement eventHandler : eventHandlers) {
|
||||||
TypeElement eventListener = (TypeElement) eventHandler.getEnclosingElement();
|
Event eventAnnotation = eventHandler.getAnnotation(Event.class);
|
||||||
Event eventAnnotation = eventHandler.getAnnotation(Event.class);
|
|
||||||
|
|
||||||
// Determine how the event type is defined
|
// Determine how the event type is defined
|
||||||
boolean useParameter;
|
boolean useParameter;
|
||||||
@ -68,11 +67,6 @@ public class EventProcessor extends AbstractProcessor {
|
|||||||
var paramElement = eventHandler.getParameters().get(0);
|
var paramElement = eventHandler.getParameters().get(0);
|
||||||
var paramType = paramElement.asType();
|
var paramType = paramElement.asType();
|
||||||
|
|
||||||
// Check for valid event type
|
|
||||||
if (useParameter && !processingEnv.getTypeUtils().isAssignable(paramType,
|
|
||||||
getTypeMirror(IEvent.class)))
|
|
||||||
error(paramElement, "Parameter must implement IEvent");
|
|
||||||
|
|
||||||
// Check for handlers for abstract types that aren't polymorphic
|
// Check for handlers for abstract types that aren't polymorphic
|
||||||
if (eventHandler.getAnnotation(Polymorphic.class) == null
|
if (eventHandler.getAnnotation(Polymorphic.class) == null
|
||||||
&& paramType.getKind() == TypeKind.DECLARED) {
|
&& paramType.getKind() == TypeKind.DECLARED) {
|
||||||
@ -82,11 +76,6 @@ public class EventProcessor extends AbstractProcessor {
|
|||||||
warning(paramElement,
|
warning(paramElement,
|
||||||
"Parameter should be instantiable or handler should use @Polymorphic");
|
"Parameter should be instantiable or handler should use @Polymorphic");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check listener for interface implementation
|
|
||||||
if (!eventListener.getInterfaces().contains(getTypeMirror(EventListener.class)))
|
|
||||||
warning(eventHandler.getEnclosingElement(),
|
|
||||||
"Class should implement EventListener interface");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,10 +9,9 @@ import java.lang.annotation.*;
|
|||||||
* Indicates that a method is an event handler. To be successfully used as such, the method has to
|
* Indicates that a method is an event handler. To be successfully used as such, the method has to
|
||||||
* comply with the following specifications:
|
* comply with the following specifications:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Declared inside a class that implements {@link EventListener}</li>
|
|
||||||
* <li>Specifying an event type by either
|
* <li>Specifying an event type by either
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Declaring one parameter of a type that implements {@link IEvent}</li>
|
* <li>Declaring one object parameter</li>
|
||||||
* <li>Defining the class of the event using the annotation value</li>
|
* <li>Defining the class of the event using the annotation value</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
* </li>
|
||||||
@ -38,7 +37,7 @@ public @interface Event {
|
|||||||
* @return the event type accepted by the handler
|
* @return the event type accepted by the handler
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
Class<? extends IEvent> value() default USE_PARAMETER.class;
|
Class<?> value() default USE_PARAMETER.class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signifies that the event type the handler listens to is determined by the type of its only
|
* Signifies that the event type the handler listens to is determined by the type of its only
|
||||||
@ -46,5 +45,5 @@ public @interface Event {
|
|||||||
*
|
*
|
||||||
* @since 0.0.3
|
* @since 0.0.3
|
||||||
*/
|
*/
|
||||||
static final class USE_PARAMETER implements IEvent {}
|
static final class USE_PARAMETER {}
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,11 @@ public final class EventBus {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<Class<? extends IEvent>, TreeSet<EventHandler>> bindings =
|
private final Map<Class<?>, TreeSet<EventHandler>> bindings =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
private final Set<EventListener> registeredListeners =
|
private final Set<Object> registeredListeners =
|
||||||
ConcurrentHashMap.newKeySet();
|
ConcurrentHashMap.newKeySet();
|
||||||
private final ThreadLocal<DispatchState> dispatchState =
|
private final ThreadLocal<DispatchState> dispatchState =
|
||||||
ThreadLocal.withInitial(DispatchState::new);
|
ThreadLocal.withInitial(DispatchState::new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +65,7 @@ public final class EventBus {
|
|||||||
* @param event the event to dispatch
|
* @param event the event to dispatch
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public void dispatch(IEvent event) {
|
public void dispatch(Object event) {
|
||||||
Objects.requireNonNull(event);
|
Objects.requireNonNull(event);
|
||||||
logger.log(Level.INFO, "Dispatching event {0}", event);
|
logger.log(Level.INFO, "Dispatching event {0}", event);
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ public final class EventBus {
|
|||||||
* @return all event handlers registered for the event class
|
* @return all event handlers registered for the event class
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
private List<EventHandler> getHandlersFor(Class<? extends IEvent> eventClass) {
|
private List<EventHandler> getHandlersFor(Class<?> eventClass) {
|
||||||
|
|
||||||
// Get handlers defined for the event class
|
// Get handlers defined for the event class
|
||||||
Set<EventHandler> handlers = bindings.getOrDefault(eventClass, new TreeSet<>());
|
Set<EventHandler> handlers = bindings.getOrDefault(eventClass, new TreeSet<>());
|
||||||
@ -133,7 +133,7 @@ public final class EventBus {
|
|||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
* @see Event
|
* @see Event
|
||||||
*/
|
*/
|
||||||
public void registerListener(EventListener listener) throws EventBusException {
|
public void registerListener(Object listener) throws EventBusException {
|
||||||
Objects.requireNonNull(listener);
|
Objects.requireNonNull(listener);
|
||||||
if (registeredListeners.contains(listener))
|
if (registeredListeners.contains(listener))
|
||||||
throw new EventBusException(listener + " already registered!");
|
throw new EventBusException(listener + " already registered!");
|
||||||
@ -170,7 +170,7 @@ public final class EventBus {
|
|||||||
* @param listener the listener to remove
|
* @param listener the listener to remove
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public void removeListener(EventListener listener) {
|
public void removeListener(Object listener) {
|
||||||
Objects.requireNonNull(listener);
|
Objects.requireNonNull(listener);
|
||||||
logger.log(Level.INFO, "Removing event listener {0}", listener.getClass().getName());
|
logger.log(Level.INFO, "Removing event listener {0}", listener.getClass().getName());
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ public final class EventBus {
|
|||||||
* @return all registered event listeners
|
* @return all registered event listeners
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public Set<EventListener> getRegisteredListeners() {
|
public Set<Object> getRegisteredListeners() {
|
||||||
return Collections.unmodifiableSet(registeredListeners);
|
return Collections.unmodifiableSet(registeredListeners);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,12 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_PRIORITY = 100;
|
public static final int DEFAULT_PRIORITY = 100;
|
||||||
|
|
||||||
private final EventListener listener;
|
private final Object listener;
|
||||||
private final Method method;
|
private final Method method;
|
||||||
private final Class<? extends IEvent> eventType;
|
private final Class<?> eventType;
|
||||||
private final boolean useParameter;
|
private final boolean useParameter;
|
||||||
private final boolean polymorphic;
|
private final boolean polymorphic;
|
||||||
private final int priority;
|
private final int priority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an event handler.
|
* Constructs an event handler.
|
||||||
@ -38,8 +38,7 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
* specification
|
* specification
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
EventHandler(Object listener, Method method, Event annotation) throws EventBusException {
|
||||||
EventHandler(EventListener listener, Method method, Event annotation) throws EventBusException {
|
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
useParameter = annotation.value() == USE_PARAMETER.class;
|
useParameter = annotation.value() == USE_PARAMETER.class;
|
||||||
@ -57,17 +56,8 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
if (!method.getReturnType().equals(void.class))
|
if (!method.getReturnType().equals(void.class))
|
||||||
throw new EventBusException(method + " does not have a return type of void!");
|
throw new EventBusException(method + " does not have a return type of void!");
|
||||||
|
|
||||||
// Determine the event type
|
// Determine handler properties
|
||||||
if (useParameter) {
|
eventType = useParameter ? method.getParameterTypes()[0] : annotation.value();
|
||||||
var param = method.getParameterTypes()[0];
|
|
||||||
if (!IEvent.class.isAssignableFrom(param))
|
|
||||||
throw new EventBusException(param + " is not of type IEvent!");
|
|
||||||
eventType = (Class<? extends IEvent>) param;
|
|
||||||
} else {
|
|
||||||
eventType = annotation.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine additional handler properties
|
|
||||||
polymorphic = method.isAnnotationPresent(Polymorphic.class);
|
polymorphic = method.isAnnotationPresent(Polymorphic.class);
|
||||||
priority = method.isAnnotationPresent(Priority.class)
|
priority = method.isAnnotationPresent(Priority.class)
|
||||||
? method.getAnnotation(Priority.class).value()
|
? method.getAnnotation(Priority.class).value()
|
||||||
@ -107,7 +97,7 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
* @throws EventBusException if the handler throws an exception
|
* @throws EventBusException if the handler throws an exception
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
void execute(IEvent event) throws EventBusException {
|
void execute(Object event) throws EventBusException {
|
||||||
try {
|
try {
|
||||||
if (useParameter)
|
if (useParameter)
|
||||||
method.invoke(listener, event);
|
method.invoke(listener, event);
|
||||||
@ -122,13 +112,13 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
* @return the listener containing this handler
|
* @return the listener containing this handler
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
EventListener getListener() { return listener; }
|
Object getListener() { return listener; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the event type this handler listens for
|
* @return the event type this handler listens for
|
||||||
* @since 0.0.3
|
* @since 0.0.3
|
||||||
*/
|
*/
|
||||||
Class<? extends IEvent> getEventType() { return eventType; }
|
Class<?> getEventType() { return eventType; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the priority of this handler
|
* @return the priority of this handler
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package dev.kske.eventbus.core;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker interface for event listeners. Event listeners can contain event handling methods to which
|
|
||||||
* events can be dispatched.
|
|
||||||
*
|
|
||||||
* @author Kai S. K. Engelbart
|
|
||||||
* @since 0.0.1
|
|
||||||
* @see Event
|
|
||||||
* @see EventBus
|
|
||||||
*/
|
|
||||||
public interface EventListener {}
|
|
@ -1,12 +0,0 @@
|
|||||||
package dev.kske.eventbus.core;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marker interface for event objects. Event objects can be used as event handler parameters and
|
|
||||||
* thus can be dispatched to the event bus.
|
|
||||||
*
|
|
||||||
* @author Kai S. K. Engelbart
|
|
||||||
* @since 0.0.1
|
|
||||||
* @see Event
|
|
||||||
* @see EventBus
|
|
||||||
*/
|
|
||||||
public interface IEvent {}
|
|
@ -11,7 +11,7 @@ import org.junit.jupiter.api.*;
|
|||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
class CancelTest implements EventListener {
|
class CancelTest {
|
||||||
|
|
||||||
EventBus bus;
|
EventBus bus;
|
||||||
int hits;
|
int hits;
|
||||||
|
@ -10,7 +10,7 @@ import org.junit.jupiter.api.*;
|
|||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
class DispatchTest implements EventListener {
|
class DispatchTest {
|
||||||
|
|
||||||
EventBus bus;
|
EventBus bus;
|
||||||
static int hits;
|
static int hits;
|
||||||
@ -27,7 +27,7 @@ class DispatchTest implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link EventBus#dispatch(IEvent)} with multiple handler priorities, a subtype handler
|
* Tests {@link EventBus#dispatch(Object)} with multiple handler priorities, a subtype handler
|
||||||
* and a static handler.
|
* and a static handler.
|
||||||
*
|
*
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
|
@ -6,4 +6,4 @@ package dev.kske.eventbus.core;
|
|||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public class SimpleEvent implements IEvent {}
|
public class SimpleEvent {}
|
||||||
|
Loading…
Reference in New Issue
Block a user