Compare commits
20 Commits
1.1.0
...
5ddef71c26
Author | SHA1 | Date | |
---|---|---|---|
5ddef71c26
![]() |
|||
85b2da391a
![]() |
|||
46a358da97
|
|||
6bf9e1097a
|
|||
e67b64678b
![]() |
|||
c614beb063
|
|||
d3abb0aca3
|
|||
ee688929fd
|
|||
897d794b86
![]() |
|||
40d48cb959
![]() |
|||
b760c58298
|
|||
872b395374
|
|||
82c66c45ec
|
|||
866a547114
![]() |
|||
33ebf0302b
|
|||
b915a5c490
![]() |
|||
205a183db7
|
|||
74447dea59
|
|||
6eebd3c121
|
|||
b758f4cef1
|
@ -45,9 +45,6 @@ public class SimpleEventListener {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Note that creating static event handlers like this
|
Note that creating static event handlers like this
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<version>5.6.2</version>
|
<version>5.8.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -26,5 +26,14 @@
|
|||||||
<!-- Disable resource folder -->
|
<!-- Disable resource folder -->
|
||||||
<resources />
|
<resources />
|
||||||
|
|
||||||
|
<!-- Run unit tests -->
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M5</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
@ -22,7 +22,7 @@ import java.lang.annotation.*;
|
|||||||
public @interface Event {
|
public @interface Event {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the event type the handler listens to. If this value is set, the handler is not
|
* Defines the event type the handler listens for. If this value is set, the handler is not
|
||||||
* allowed to declare parameters.
|
* allowed to declare parameters.
|
||||||
* <p>
|
* <p>
|
||||||
* This is useful when the event handler does not utilize the event instance.
|
* This is useful when the event handler does not utilize the event instance.
|
||||||
|
@ -5,6 +5,9 @@ import java.lang.System.Logger.Level;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import dev.kske.eventbus.core.handler.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event listeners can be registered at an event bus to be notified when an event is dispatched.
|
* Event listeners can be registered at an event bus to be notified when an event is dispatched.
|
||||||
@ -27,7 +30,21 @@ public final class EventBus {
|
|||||||
*/
|
*/
|
||||||
private static final class DispatchState {
|
private static final class DispatchState {
|
||||||
|
|
||||||
boolean isDispatching, isCancelled;
|
/**
|
||||||
|
* Indicates that the last event handler invoked has called {@link EventBus#cancel}. In that
|
||||||
|
* case, the event is not dispatched further.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
boolean isCancelled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is incremented when {@link EventBus#dispatch(Object)} is invoked and decremented when it
|
||||||
|
* finishes. This allows keeping track of nested dispatches.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
int nestingCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,33 +55,55 @@ public final class EventBus {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_PRIORITY = 100;
|
public static final int DEFAULT_PRIORITY = 100;
|
||||||
|
|
||||||
private static volatile EventBus singletonInstance;
|
private static final EventBus singletonInstance = new EventBus();
|
||||||
|
|
||||||
private static final Logger logger = System.getLogger(EventBus.class.getName());
|
private static final Logger logger = System.getLogger(EventBus.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a singleton instance of the event bus. It is lazily initialized on the first call.
|
* Compares event handlers based on priority, but uses hash codes for equal priorities.
|
||||||
*
|
*
|
||||||
* @return a singleton instance of the event bus.
|
* @implNote As the priority comparator by itself is not consistent with equals (two handlers
|
||||||
|
* with the same priority are not necessarily equal, but would have a comparison
|
||||||
|
* result of 0), the hash code is used for the fallback comparison. This way,
|
||||||
|
* consistency with equals is restored.
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
private static final Comparator<EventHandler> byPriority =
|
||||||
|
Comparator.comparingInt(EventHandler::getPriority).reversed()
|
||||||
|
.thenComparingInt(EventHandler::hashCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default event bus, which is a statically initialized singleton instance.
|
||||||
|
*
|
||||||
|
* @return the default event bus
|
||||||
* @since 0.0.2
|
* @since 0.0.2
|
||||||
*/
|
*/
|
||||||
public static EventBus getInstance() {
|
public static EventBus getInstance() {
|
||||||
EventBus instance = singletonInstance;
|
return singletonInstance;
|
||||||
if (instance == null)
|
|
||||||
synchronized (EventBus.class) {
|
|
||||||
if ((instance = singletonInstance) == null) {
|
|
||||||
logger.log(Level.DEBUG, "Initializing singleton event bus instance");
|
|
||||||
instance = singletonInstance = new EventBus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<Class<?>, TreeSet<EventHandler>> bindings =
|
/**
|
||||||
new ConcurrentHashMap<>();
|
* Event handler bindings (target class to handlers registered for that class), does not contain
|
||||||
private final Set<Object> registeredListeners =
|
* other (polymorphic) handlers.
|
||||||
ConcurrentHashMap.newKeySet();
|
*
|
||||||
private final ThreadLocal<DispatchState> dispatchState =
|
* @since 0.0.1
|
||||||
|
*/
|
||||||
|
private final Map<Class<?>, TreeSet<EventHandler>> bindings = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores all registered event listeners (which declare event handlers) and prevents them from
|
||||||
|
* being garbage collected.
|
||||||
|
*
|
||||||
|
* @since 0.0.1
|
||||||
|
*/
|
||||||
|
private final Set<Object> registeredListeners = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current event dispatching state, local to each thread.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
private final ThreadLocal<DispatchState> dispatchState =
|
||||||
ThreadLocal.withInitial(DispatchState::new);
|
ThreadLocal.withInitial(DispatchState::new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,18 +111,21 @@ public final class EventBus {
|
|||||||
* priority.
|
* priority.
|
||||||
*
|
*
|
||||||
* @param event the event to dispatch
|
* @param event the event to dispatch
|
||||||
* @throws EventBusException if an event handler isn't accessible or has an invalid signature
|
* @throws EventBusException if an event handler isn't accessible or has an invalid signature
|
||||||
|
* @throws NullPointerException if the specified event is {@code null}
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public void dispatch(Object event) throws EventBusException {
|
public void dispatch(Object event) throws EventBusException {
|
||||||
Objects.requireNonNull(event);
|
Objects.requireNonNull(event);
|
||||||
logger.log(Level.INFO, "Dispatching event {0}", event);
|
logger.log(Level.INFO, "Dispatching event {0}", event);
|
||||||
|
|
||||||
// Set dispatch state
|
// Look up dispatch state
|
||||||
var state = dispatchState.get();
|
var state = dispatchState.get();
|
||||||
state.isDispatching = true;
|
|
||||||
|
|
||||||
Iterator<EventHandler> handlers = getHandlersFor(event.getClass());
|
// Increment nesting count (becomes > 1 during nested dispatches)
|
||||||
|
++state.nestingCount;
|
||||||
|
|
||||||
|
Iterator<EventHandler> handlers = getHandlersFor(event.getClass()).iterator();
|
||||||
if (handlers.hasNext()) {
|
if (handlers.hasNext()) {
|
||||||
while (handlers.hasNext())
|
while (handlers.hasNext())
|
||||||
if (state.isCancelled) {
|
if (state.isCancelled) {
|
||||||
@ -94,14 +136,14 @@ public final class EventBus {
|
|||||||
try {
|
try {
|
||||||
handlers.next().execute(event);
|
handlers.next().execute(event);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (event instanceof DeadEvent || event instanceof ExceptionEvent)
|
if (e.getCause() instanceof Error)
|
||||||
|
|
||||||
// Warn about system event not being handled
|
|
||||||
logger.log(Level.WARNING, event + " not handled due to exception", e);
|
|
||||||
else if (e.getCause() instanceof Error)
|
|
||||||
|
|
||||||
// Transparently pass error to the caller
|
// Transparently pass error to the caller
|
||||||
throw (Error) e.getCause();
|
throw (Error) e.getCause();
|
||||||
|
else if (event instanceof DeadEvent || event instanceof ExceptionEvent)
|
||||||
|
|
||||||
|
// Warn about system event not being handled
|
||||||
|
logger.log(Level.WARNING, event + " not handled due to exception", e);
|
||||||
else
|
else
|
||||||
|
|
||||||
// Dispatch exception event
|
// Dispatch exception event
|
||||||
@ -118,8 +160,8 @@ public final class EventBus {
|
|||||||
dispatch(new DeadEvent(this, event));
|
dispatch(new DeadEvent(this, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset dispatch state
|
// Decrement nesting count (becomes 0 when all dispatches on the thread are finished)
|
||||||
state.isDispatching = false;
|
--state.nestingCount;
|
||||||
|
|
||||||
logger.log(Level.DEBUG, "Finished dispatching event {0}", event);
|
logger.log(Level.DEBUG, "Finished dispatching event {0}", event);
|
||||||
}
|
}
|
||||||
@ -128,23 +170,24 @@ public final class EventBus {
|
|||||||
* Searches for the event handlers bound to an event class. This includes polymorphic handlers
|
* Searches for the event handlers bound to an event class. This includes polymorphic handlers
|
||||||
* that are bound to a supertype of the event class.
|
* that are bound to a supertype of the event class.
|
||||||
*
|
*
|
||||||
* @param eventClass the event class to use for the search
|
* @param eventType the event type to use for the search
|
||||||
* @return an iterator over the applicable handlers in descending order of priority
|
* @return a navigable set containing the applicable handlers in descending order of priority
|
||||||
* @since 0.0.1
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
private Iterator<EventHandler> getHandlersFor(Class<?> eventClass) {
|
private NavigableSet<EventHandler> getHandlersFor(Class<?> eventType) {
|
||||||
|
|
||||||
// Get handlers defined for the event class
|
// Get handlers defined for the event class
|
||||||
TreeSet<EventHandler> handlers = bindings.getOrDefault(eventClass, new TreeSet<>());
|
TreeSet<EventHandler> handlers =
|
||||||
|
bindings.getOrDefault(eventType, new TreeSet<>(byPriority));
|
||||||
|
|
||||||
// Get polymorphic handlers
|
// Get polymorphic handlers
|
||||||
for (var binding : bindings.entrySet())
|
for (var binding : bindings.entrySet())
|
||||||
if (binding.getKey().isAssignableFrom(eventClass))
|
if (binding.getKey().isAssignableFrom(eventType))
|
||||||
for (var handler : binding.getValue())
|
for (var handler : binding.getValue())
|
||||||
if (handler.isPolymorphic())
|
if (handler.isPolymorphic())
|
||||||
handlers.add(handler);
|
handlers.add(handler);
|
||||||
|
|
||||||
return handlers.iterator();
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,7 +198,7 @@ public final class EventBus {
|
|||||||
*/
|
*/
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
var state = dispatchState.get();
|
var state = dispatchState.get();
|
||||||
if (state.isDispatching && !state.isCancelled)
|
if (state.nestingCount > 0 && !state.isCancelled)
|
||||||
state.isCancelled = true;
|
state.isCancelled = true;
|
||||||
else
|
else
|
||||||
throw new EventBusException("Calling thread not an active dispatching thread!");
|
throw new EventBusException("Calling thread not an active dispatching thread!");
|
||||||
@ -165,8 +208,9 @@ public final class EventBus {
|
|||||||
* Registers an event listener at this event bus.
|
* Registers an event listener at this event bus.
|
||||||
*
|
*
|
||||||
* @param listener the listener to register
|
* @param listener the listener to register
|
||||||
* @throws EventBusException if the listener is already registered or a declared event handler
|
* @throws EventBusException if the listener is already registered or a declared event
|
||||||
* does not comply with the specification
|
* handler does not comply with the specification
|
||||||
|
* @throws NullPointerException if the specified listener is {@code null}
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
* @see Event
|
* @see Event
|
||||||
*/
|
*/
|
||||||
@ -196,11 +240,8 @@ public final class EventBus {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Initialize and bind the handler
|
// Initialize and bind the handler
|
||||||
var handler = new EventHandler(listener, method, annotation, polymorphic, priority);
|
bindHandler(
|
||||||
bindings.putIfAbsent(handler.getEventType(), new TreeSet<>());
|
new ReflectiveEventHandler(listener, method, annotation, polymorphic, priority));
|
||||||
logger.log(Level.DEBUG, "Binding event handler {0}", handler);
|
|
||||||
bindings.get(handler.getEventType())
|
|
||||||
.add(handler);
|
|
||||||
handlerBound = true;
|
handlerBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +252,86 @@ public final class EventBus {
|
|||||||
listener.getClass().getName());
|
listener.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback listener, which is a consumer that is invoked when an event occurs. The
|
||||||
|
* listener is not polymorphic and has the {@link #DEFAULT_PRIORITY}.
|
||||||
|
*
|
||||||
|
* @param <E> the event type the listener listens for
|
||||||
|
* @param eventType the event type the listener listens for
|
||||||
|
* @param eventListener the callback that is invoked when an event occurs
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see #registerListener(Class, Consumer, boolean, int)
|
||||||
|
*/
|
||||||
|
public <E> void registerListener(Class<E> eventType, Consumer<E> eventListener) {
|
||||||
|
registerListener(eventType, eventListener, false, DEFAULT_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback listener, which is a consumer that is invoked when an event occurs. The
|
||||||
|
* listener has the {@link #DEFAULT_PRIORITY}.
|
||||||
|
*
|
||||||
|
* @param <E> the event type the listener listens for
|
||||||
|
* @param eventType the event type the listener listens for
|
||||||
|
* @param eventListener the callback that is invoked when an event occurs
|
||||||
|
* @param polymorphic whether the listener is also invoked for subtypes of the event type
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see #registerListener(Class, Consumer, boolean, int)
|
||||||
|
*/
|
||||||
|
public <E> void registerListener(Class<E> eventType, Consumer<E> eventListener,
|
||||||
|
boolean polymorphic) {
|
||||||
|
registerListener(eventType, eventListener, polymorphic, DEFAULT_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback listener, which is a consumer that is invoked when an event occurs. The
|
||||||
|
* listener is not polymorphic.
|
||||||
|
*
|
||||||
|
* @param <E> the event type the listener listens for
|
||||||
|
* @param eventType the event type the listener listens for
|
||||||
|
* @param eventListener the callback that is invoked when an event occurs
|
||||||
|
* @param priority the priority to assign to the listener
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see #registerListener(Class, Consumer, boolean, int)
|
||||||
|
*/
|
||||||
|
public <E> void registerListener(Class<E> eventType, Consumer<E> eventListener, int priority) {
|
||||||
|
registerListener(eventType, eventListener, false, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback listener, which is a consumer that is invoked when an event occurs.
|
||||||
|
*
|
||||||
|
* @param <E> the event type the listener listens for
|
||||||
|
* @param eventType the event type the listener listens for
|
||||||
|
* @param eventListener the callback that is invoked when an event occurs
|
||||||
|
* @param polymorphic whether the listener is also invoked for subtypes of the event type
|
||||||
|
* @param priority the priority to assign to the listener
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public <E> void registerListener(Class<E> eventType, Consumer<E> eventListener,
|
||||||
|
boolean polymorphic,
|
||||||
|
int priority) {
|
||||||
|
Objects.requireNonNull(eventListener);
|
||||||
|
if (registeredListeners.contains(eventListener))
|
||||||
|
throw new EventBusException(eventListener + " already registered!");
|
||||||
|
logger.log(Level.INFO, "Registering callback event listener {0}",
|
||||||
|
eventListener.getClass().getName());
|
||||||
|
|
||||||
|
registeredListeners.add(eventListener);
|
||||||
|
bindHandler(new CallbackEventHandler(eventType, eventListener, polymorphic, priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new handler into the {@link #bindings} map.
|
||||||
|
*
|
||||||
|
* @param handler the handler to bind
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
private void bindHandler(EventHandler handler) {
|
||||||
|
bindings.putIfAbsent(handler.getEventType(), new TreeSet<>(byPriority));
|
||||||
|
logger.log(Level.DEBUG, "Binding event handler {0}", handler);
|
||||||
|
bindings.get(handler.getEventType()).add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a specific listener from this event bus.
|
* Removes a specific listener from this event bus.
|
||||||
*
|
*
|
||||||
@ -221,6 +342,7 @@ public final class EventBus {
|
|||||||
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());
|
||||||
|
|
||||||
|
// Remove bindings from binding map
|
||||||
for (var binding : bindings.values()) {
|
for (var binding : bindings.values()) {
|
||||||
var it = binding.iterator();
|
var it = binding.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
@ -231,6 +353,8 @@ public final class EventBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the listener itself
|
||||||
registeredListeners.remove(listener);
|
registeredListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +369,39 @@ public final class EventBus {
|
|||||||
registeredListeners.clear();
|
registeredListeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a string describing the event handlers that would be executed for a specific event
|
||||||
|
* type, in order and without actually executing them.
|
||||||
|
*
|
||||||
|
* @apiNote Using this method is only recommended for debugging purposes, as the output depends
|
||||||
|
* on implementation internals which may be subject to change.
|
||||||
|
* @implNote Nested dispatches are not accounted for, as this would require actually executing
|
||||||
|
* the handlers.
|
||||||
|
* @param eventType the event type to generate the execution order for
|
||||||
|
* @return a human-readable event handler list suitable for debugging purposes
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public String printExecutionOrder(Class<?> eventType) {
|
||||||
|
var handlers = getHandlersFor(eventType);
|
||||||
|
var sj = new StringJoiner("\n");
|
||||||
|
|
||||||
|
// Output header line
|
||||||
|
sj.add(String.format("Event handler execution order for %s (%d handler(s)):", eventType,
|
||||||
|
handlers.size()));
|
||||||
|
sj.add(
|
||||||
|
"==========================================================================================");
|
||||||
|
|
||||||
|
// Individual handlers
|
||||||
|
for (var handler : handlers)
|
||||||
|
sj.add(handler.toString());
|
||||||
|
|
||||||
|
// Bottom line
|
||||||
|
sj.add(
|
||||||
|
"==========================================================================================");
|
||||||
|
|
||||||
|
return sj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an unmodifiable view of the event listeners registered at this event bus.
|
* Provides an unmodifiable view of the event listeners registered at this event bus.
|
||||||
*
|
*
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package dev.kske.eventbus.core;
|
package dev.kske.eventbus.core;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This runtime exception is thrown when an event bus error occurs. This can
|
* This unchecked exception is specific to the event bus and can be thrown under the following
|
||||||
* either occur while registering event listeners with invalid handlers, or when
|
* circumstances:
|
||||||
* an event handler throws an exception.
|
* <ul>
|
||||||
|
* <li>An event handler throws an exception (which is stored as the cause)</li>
|
||||||
|
* <li>An event listener with an invalid event handler is registered</li>
|
||||||
|
* <li>{@link EventBus#cancel()} is invoked from outside an active dispatch thread</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
public class EventBusException extends RuntimeException {
|
public final class EventBusException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package dev.kske.eventbus.core.handler;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event handler wrapping a callback method.
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public final class CallbackEventHandler implements EventHandler {
|
||||||
|
|
||||||
|
private final Class<?> eventType;
|
||||||
|
private final Consumer<Object> callback;
|
||||||
|
private final boolean polymorphic;
|
||||||
|
private final int priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a callback event handler.
|
||||||
|
*
|
||||||
|
* @param <E> the event type of the handler
|
||||||
|
* @param eventType the event type of the handler
|
||||||
|
* @param callback the callback method to execute when the handler is invoked
|
||||||
|
* @param polymorphic whether the handler is polymorphic
|
||||||
|
* @param priority the priority of the handler
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <E> CallbackEventHandler(Class<E> eventType, Consumer<E> callback, boolean polymorphic,
|
||||||
|
int priority) {
|
||||||
|
this.eventType = eventType;
|
||||||
|
this.callback = (Consumer<Object>) callback;
|
||||||
|
this.polymorphic = polymorphic;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Object event) throws InvocationTargetException {
|
||||||
|
try {
|
||||||
|
callback.accept(event);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
throw new InvocationTargetException(e, "Callback event handler failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"CallbackEventHandler[eventType=%s, polymorphic=%b, priority=%d]",
|
||||||
|
eventType, polymorphic, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Consumer<?> getListener() {
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getEventType() {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPolymorphic() {
|
||||||
|
return polymorphic;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package dev.kske.eventbus.core.handler;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import dev.kske.eventbus.core.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal representation of an event handling method.
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see EventBus
|
||||||
|
*/
|
||||||
|
public interface EventHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the event handler.
|
||||||
|
*
|
||||||
|
* @param event the event used as the method parameter
|
||||||
|
* @throws EventBusException if the event handler isn't accessible or has an invalid
|
||||||
|
* signature
|
||||||
|
* @throws InvocationTargetException if the handler throws an exception
|
||||||
|
* @throws EventBusException if the handler has the wrong signature or is inaccessible
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
void execute(Object event) throws EventBusException, InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the listener containing this handler
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
Object getListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the event type this handler listens for
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
Class<?> getEventType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the priority of this handler
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see Priority
|
||||||
|
*/
|
||||||
|
int getPriority();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether this handler also accepts subtypes of the event type
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see Polymorphic
|
||||||
|
*/
|
||||||
|
boolean isPolymorphic();
|
||||||
|
}
|
@ -1,17 +1,18 @@
|
|||||||
package dev.kske.eventbus.core;
|
package dev.kske.eventbus.core.handler;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
|
import dev.kske.eventbus.core.*;
|
||||||
import dev.kske.eventbus.core.Event.USE_PARAMETER;
|
import dev.kske.eventbus.core.Event.USE_PARAMETER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal representation of an event handling method.
|
* An event handler wrapping a method annotated with {@link Event} and executing it using
|
||||||
|
* reflection.
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 0.0.1
|
* @since 1.2.0
|
||||||
* @see EventBus
|
|
||||||
*/
|
*/
|
||||||
final class EventHandler implements Comparable<EventHandler> {
|
public final class ReflectiveEventHandler implements EventHandler {
|
||||||
|
|
||||||
private final Object listener;
|
private final Object listener;
|
||||||
private final Method method;
|
private final Method method;
|
||||||
@ -21,7 +22,7 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
private final int priority;
|
private final int priority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an event handler.
|
* Constructs a reflective event handler.
|
||||||
*
|
*
|
||||||
* @param listener the listener containing the handler
|
* @param listener the listener containing the handler
|
||||||
* @param method the handler method
|
* @param method the handler method
|
||||||
@ -30,10 +31,10 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
* @param defPriority the predefined priority (default or listener-level)
|
* @param defPriority the predefined priority (default or listener-level)
|
||||||
* @throws EventBusException if the method or the annotation do not comply with the
|
* @throws EventBusException if the method or the annotation do not comply with the
|
||||||
* specification
|
* specification
|
||||||
* @since 0.0.1
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
EventHandler(Object listener, Method method, Event annotation, boolean defPolymorphism,
|
public ReflectiveEventHandler(Object listener, Method method, Event annotation,
|
||||||
int defPriority) throws EventBusException {
|
boolean defPolymorphism, int defPriority) 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;
|
||||||
@ -61,45 +62,13 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 descending order of priority from a tree set.
|
|
||||||
*
|
|
||||||
* @since 0.0.1
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(EventHandler other) {
|
public void execute(Object event) throws EventBusException, InvocationTargetException {
|
||||||
int priority = other.priority - this.priority;
|
|
||||||
if (priority == 0)
|
|
||||||
priority = listener.hashCode() - other.listener.hashCode();
|
|
||||||
return priority == 0 ? hashCode() - other.hashCode() : priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format(
|
|
||||||
"EventHandler[method=%s, eventType=%s, useParameter=%b, polymorphic=%b, priority=%d]",
|
|
||||||
method, eventType, useParameter, polymorphic, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the event handler.
|
|
||||||
*
|
|
||||||
* @param event the event used as the method parameter
|
|
||||||
* @throws EventBusException if the event handler isn't accessible or has an invalid
|
|
||||||
* signature
|
|
||||||
* @throws InvocationTargetException if the handler throws an exception
|
|
||||||
* @throws EventBusException if the handler has the wrong signature or is inaccessible
|
|
||||||
* @since 0.0.1
|
|
||||||
*/
|
|
||||||
void execute(Object event) throws EventBusException, InvocationTargetException {
|
|
||||||
try {
|
try {
|
||||||
if (useParameter)
|
if (useParameter)
|
||||||
method.invoke(listener, event);
|
method.invoke(getListener(), event);
|
||||||
else
|
else
|
||||||
method.invoke(listener);
|
method.invoke(getListener());
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new EventBusException("Event handler rejected target / argument!", e);
|
throw new EventBusException("Event handler rejected target / argument!", e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@ -107,29 +76,30 @@ final class EventHandler implements Comparable<EventHandler> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the listener containing this handler
|
public String toString() {
|
||||||
* @since 0.0.1
|
return String.format(
|
||||||
*/
|
"ReflectiveEventHandler[eventType=%s, polymorphic=%b, priority=%d, method=%s, useParameter=%b]",
|
||||||
Object getListener() { return listener; }
|
eventType, polymorphic, priority, method, useParameter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the event type this handler listens for
|
public Object getListener() {
|
||||||
* @since 0.0.3
|
return listener;
|
||||||
*/
|
}
|
||||||
Class<?> getEventType() { return eventType; }
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the priority of this handler
|
public Class<?> getEventType() {
|
||||||
* @since 0.0.1
|
return eventType;
|
||||||
* @see Priority
|
}
|
||||||
*/
|
|
||||||
int getPriority() { return priority; }
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return whether this handler is polymorphic
|
public int getPriority() {
|
||||||
* @since 1.0.0
|
return priority;
|
||||||
* @see Polymorphic
|
}
|
||||||
*/
|
|
||||||
boolean isPolymorphic() { return polymorphic; }
|
@Override
|
||||||
|
public boolean isPolymorphic() {
|
||||||
|
return polymorphic;
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Contains the internal representation of event handling methods.
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see dev.kske.eventbus.core.handler.EventHandler
|
||||||
|
*/
|
||||||
|
package dev.kske.eventbus.core.handler;
|
@ -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 {
|
public class CancelTest {
|
||||||
|
|
||||||
EventBus bus;
|
EventBus bus;
|
||||||
int hits;
|
int hits;
|
||||||
@ -22,7 +22,7 @@ class CancelTest {
|
|||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void registerListener() {
|
public void registerListener() {
|
||||||
bus = new EventBus();
|
bus = new EventBus();
|
||||||
bus.registerListener(this);
|
bus.registerListener(this);
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ class CancelTest {
|
|||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testCancellation() {
|
public void testCancellation() {
|
||||||
bus.dispatch(new SimpleEvent());
|
bus.dispatch(new SimpleEvent());
|
||||||
assertEquals(1, hits);
|
assertEquals(1, hits);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
class DeadTest {
|
public class DeadTest {
|
||||||
|
|
||||||
EventBus bus = new EventBus();
|
EventBus bus = new EventBus();
|
||||||
String event = "This event has no handler";
|
String event = "This event has no handler";
|
||||||
@ -18,11 +18,11 @@ class DeadTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests dead event delivery.
|
* Tests dead event delivery.
|
||||||
*
|
*
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testDeadEvent() {
|
public void testDeadEvent() {
|
||||||
bus.registerListener(this);
|
bus.registerListener(this);
|
||||||
bus.dispatch(event);
|
bus.dispatch(event);
|
||||||
assertTrue(deadEventHandled);
|
assertTrue(deadEventHandled);
|
||||||
@ -32,11 +32,11 @@ class DeadTest {
|
|||||||
/**
|
/**
|
||||||
* Tests how the event bus reacts to an unhandled dead event. This should not lead to an
|
* Tests how the event bus reacts to an unhandled dead event. This should not lead to an
|
||||||
* exception or an endless recursion and should be logged instead.
|
* exception or an endless recursion and should be logged instead.
|
||||||
*
|
*
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testUnhandledDeadEvent() {
|
public void testUnhandledDeadEvent() {
|
||||||
bus.dispatch(event);
|
bus.dispatch(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import org.junit.jupiter.api.*;
|
|||||||
*/
|
*/
|
||||||
@Polymorphic
|
@Polymorphic
|
||||||
@Priority(150)
|
@Priority(150)
|
||||||
class DispatchTest {
|
public class DispatchTest {
|
||||||
|
|
||||||
EventBus bus;
|
EventBus bus;
|
||||||
static int hits;
|
static int hits;
|
||||||
@ -23,9 +23,13 @@ class DispatchTest {
|
|||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void registerListener() {
|
public void registerListener() {
|
||||||
bus = new EventBus();
|
bus = new EventBus();
|
||||||
bus.registerListener(this);
|
bus.registerListener(this);
|
||||||
|
bus.registerListener(SimpleEvent.class, e -> {
|
||||||
|
++hits;
|
||||||
|
assertEquals(4, hits);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,11 +39,30 @@ class DispatchTest {
|
|||||||
* @since 0.0.1
|
* @since 0.0.1
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testDispatch() {
|
public void testDispatch() {
|
||||||
bus.dispatch(new SimpleEventSub());
|
bus.dispatch(new SimpleEventSub());
|
||||||
bus.dispatch(new SimpleEvent());
|
bus.dispatch(new SimpleEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link EventBus#printExecutionOrder(Class)} based on the currently registered handlers.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrintExecutionOrder() {
|
||||||
|
String executionOrder = bus.printExecutionOrder(SimpleEvent.class);
|
||||||
|
System.out.println(executionOrder);
|
||||||
|
assertEquals(
|
||||||
|
"Event handler execution order for class dev.kske.eventbus.core.SimpleEvent (3 handler(s)):\n"
|
||||||
|
+ "==========================================================================================\n"
|
||||||
|
+ "ReflectiveEventHandler[eventType=class dev.kske.eventbus.core.SimpleEvent, polymorphic=true, priority=200, method=void dev.kske.eventbus.core.DispatchTest.onSimpleEventFirst(), useParameter=false]\n"
|
||||||
|
+ "ReflectiveEventHandler[eventType=class dev.kske.eventbus.core.SimpleEvent, polymorphic=false, priority=150, method=static void dev.kske.eventbus.core.DispatchTest.onSimpleEventSecond(), useParameter=false]\n"
|
||||||
|
+ "CallbackEventHandler[eventType=class dev.kske.eventbus.core.SimpleEvent, polymorphic=false, priority=100]\n"
|
||||||
|
+ "==========================================================================================",
|
||||||
|
executionOrder);
|
||||||
|
}
|
||||||
|
|
||||||
@Event(SimpleEvent.class)
|
@Event(SimpleEvent.class)
|
||||||
@Priority(200)
|
@Priority(200)
|
||||||
void onSimpleEventFirst() {
|
void onSimpleEventFirst() {
|
||||||
@ -53,12 +76,4 @@ class DispatchTest {
|
|||||||
++hits;
|
++hits;
|
||||||
assertEquals(3, hits);
|
assertEquals(3, hits);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Event
|
|
||||||
@Polymorphic(false)
|
|
||||||
@Priority(100)
|
|
||||||
void onSimpleEventThird(SimpleEvent event) {
|
|
||||||
++hits;
|
|
||||||
assertEquals(4, hits);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the dispatching of an exception event if an event handler threw an exception.
|
* Tests the dispatching of an exception event if an event handler threw an exception.
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
class ExceptionTest {
|
public class ExceptionTest {
|
||||||
|
|
||||||
EventBus bus = new EventBus();
|
EventBus bus = new EventBus();
|
||||||
String event = "This event will cause an exception";
|
String event = "This event will cause an exception";
|
||||||
@ -19,11 +19,11 @@ class ExceptionTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests exception event delivery.
|
* Tests exception event delivery.
|
||||||
*
|
*
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testExceptionEvent() {
|
public void testExceptionEvent() {
|
||||||
bus.registerListener(this);
|
bus.registerListener(this);
|
||||||
bus.registerListener(new ExceptionListener());
|
bus.registerListener(new ExceptionListener());
|
||||||
bus.dispatch(event);
|
bus.dispatch(event);
|
||||||
@ -34,11 +34,11 @@ class ExceptionTest {
|
|||||||
/**
|
/**
|
||||||
* Tests how the event bus reacts to an unhandled exception event. This should not lead to an
|
* Tests how the event bus reacts to an unhandled exception event. This should not lead to an
|
||||||
* exception or an endless recursion and should be logged instead.
|
* exception or an endless recursion and should be logged instead.
|
||||||
*
|
*
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testUnhandledExceptionEvent() {
|
public void testUnhandledExceptionEvent() {
|
||||||
bus.registerListener(this);
|
bus.registerListener(this);
|
||||||
bus.dispatch(event);
|
bus.dispatch(event);
|
||||||
bus.removeListener(this);
|
bus.removeListener(this);
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package dev.kske.eventbus.core;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests nested event dispatches.
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
public class NestedTest {
|
||||||
|
|
||||||
|
EventBus bus;
|
||||||
|
boolean nestedHit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an event bus and registers this test instance as an event listener.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@BeforeEach
|
||||||
|
public void registerListener() {
|
||||||
|
bus = new EventBus();
|
||||||
|
bus.registerListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches a simple event, which should in turn cause a string to be dispatched as a nested
|
||||||
|
* event. If the corresponding handler sets {@link #nestedHit} to {@code true}, the test is
|
||||||
|
* successful.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNestedDispatch() {
|
||||||
|
bus.dispatch(new SimpleEvent());
|
||||||
|
assertTrue(nestedHit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches a string as a nested event and cancels the current dispatch afterwards.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Event(SimpleEvent.class)
|
||||||
|
void onSimpleEvent() {
|
||||||
|
bus.dispatch("Nested event");
|
||||||
|
bus.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets {@link #nestedHit} to {@code true} indicating that nested dispatches work.
|
||||||
|
*
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Event(String.class)
|
||||||
|
void onString() {
|
||||||
|
nestedHit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fails the test if an exception is caused during the dispatch.
|
||||||
|
*
|
||||||
|
* @param e the event containing the exception
|
||||||
|
* @since 1.2.0
|
||||||
|
*/
|
||||||
|
@Event
|
||||||
|
void onException(ExceptionEvent e) {
|
||||||
|
fail("Exception during dispatch", e.getCause());
|
||||||
|
}
|
||||||
|
}
|
24
pom.xml
24
pom.xml
@ -9,7 +9,7 @@
|
|||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Event Bus</name>
|
<name>Event Bus</name>
|
||||||
<description>An event handling framework for Java utilizing annotations.</description>
|
<description>An event handling library for Java utilizing annotations.</description>
|
||||||
<url>https://git.kske.dev/kske/event-bus</url>
|
<url>https://git.kske.dev/kske/event-bus</url>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
@ -120,6 +120,28 @@
|
|||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
||||||
|
<!-- Support JDK-style Javadoc tags -->
|
||||||
|
<configuration>
|
||||||
|
<tags>
|
||||||
|
<tag>
|
||||||
|
<name>apiNote</name>
|
||||||
|
<placement>a</placement>
|
||||||
|
<head>API Note:</head>
|
||||||
|
</tag>
|
||||||
|
<tag>
|
||||||
|
<name>implSpec</name>
|
||||||
|
<placement>a</placement>
|
||||||
|
<head>Implementation Requirements:</head>
|
||||||
|
</tag>
|
||||||
|
<tag>
|
||||||
|
<name>implNote</name>
|
||||||
|
<placement>a</placement>
|
||||||
|
<head>Implementation Note:</head>
|
||||||
|
</tag>
|
||||||
|
</tags>
|
||||||
|
</configuration>
|
||||||
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<!-- GPG sign JAR -->
|
<!-- GPG sign JAR -->
|
||||||
|
Reference in New Issue
Block a user