diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java index 8c078be2..b0d868e7 100644 --- a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java +++ b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java @@ -12,245 +12,268 @@ *
* Implement an EventInterface into your class, then implement the function.
*
- * In your initializer method, register the instance of the class with {@link EventListenerRegistry#register(EventBase)} - *
+ * In your initializer method, register the instance of the class with + * {@link EventListenerRegistry#register(EventBase)}
* Example: + * *
- *     public class ClassWithListener implements EventInit {
+ * public class ClassWithListener implements EventInit {
  *
- *          @ Override
- *          public void onEventInit() {
- *              // Implement event specific code
- *          }
- *     }
+ * 	@Override
+ * 	public void onEventInit() {
+ * 		// Implement event specific code
+ * 	}
+ * }
  * 
+ * *
* To create and fire your own events, check {@link EventBase}
*/ public class EventListenerRegistry { - /** - * Base interface for events.
- *
- * To create a new event, create an interface and extend EventBase.
- * Only 1 method is accepted in an event, so it's best to add {@link FunctionalInterface} to the interface.
- *
- * Example: - *
-     *     @ FunctionalInterface
-     *     public interface EventInit extends EventBase {
-     *         public void onEventInit();
-     *     }
-     *
-     *     @ FunctionalInterface
-     *     public interface EventAdd extends EventBase {
-     *         public int onEventAdd(int a, int b); // Accepts parameters and return types
-     *     }
-     * 
- * - * To fire your event, use {@link EventListenerRegistry#fireEvent(Class)} with the parameter being the event class.
- * - *
-     *     EventListenerRegistry.fireEvent(EventInit.class);
-     * 
- * - * To fire an event with parameters and return types: - *
-     *     int eventResult = (int) EventListenerRegistry.fireEvent(EventAdd.class, a, b);
-     * 
- * When using parameters, the type and the amount of parameters has to match! - */ - public interface EventBase { - } + /** + * Base interface for events.
+ *
+ * To create a new event, create an interface and extend EventBase.
+ * Only 1 method is accepted in an event, so it's best to add + * {@link FunctionalInterface} to the interface.
+ *
+ * Example: + * + *
+	 * @FunctionalInterface
+	 * public interface EventInit extends EventBase {
+	 * 	public void onEventInit();
+	 * }
+	 *
+	 * @FunctionalInterface
+	 * public interface EventAdd extends EventBase {
+	 * 	public int onEventAdd(int a, int b); // Accepts parameters and return types
+	 * }
+	 * 
+ * + * To fire your event, use {@link EventListenerRegistry#fireEvent(Class)} with + * the parameter being the event class.
+ * + *
+	 * EventListenerRegistry.fireEvent(EventInit.class);
+	 * 
+ * + * To fire an event with parameters and return types: + * + *
+	 * int eventResult = (int) EventListenerRegistry.fireEvent(EventAdd.class, a, b);
+	 * 
+ * + * When using parameters, the type and the amount of parameters has to match! + */ + public interface EventBase { + } + + /** + * Stores the event listener objects and calls their event methods during + * {@link EventListenerRegistry#fireEvent(Class, Object...)}
+ *
+ * Consists of multiple lists seperated by event types.
+ * If it were a single ArrayList, firing an event means that you'd have to + * unnecessarily iterate over the entire list,
+ * to find the correct events.
+ *
+ * With multiple lists like this, you iterate only over the objects, that have + * the correct event applied. + */ + private static final HashMap, ArrayList> EVENTLISTENER_REGISTRY = new HashMap<>(); + + /** + * Registers an object to be an event listener. The object must implement an + * event extending {@link EventBase} + * + * @param eventListener The event listener to register + */ + public static void register(EventBase eventListener) { + if (eventListener == null) { + throw new NullPointerException("Tried to register a packethandler with value null"); + } + for (Class type : eventListener.getClass().getInterfaces()) { + if (EventBase.class.isAssignableFrom(type)) { - /** - * Stores the event listener objects and calls their event methods during {@link EventListenerRegistry#fireEvent(Class, Object...)}
- *
- * Consists of multiple lists seperated by event types.
- * If it were a single ArrayList, firing an event means that you'd have to unnecessarily iterate over the entire list,
- * to find the correct events.
- *
- * With multiple lists like this, you iterate only over the objects, that have the correct event applied. - */ - private static final HashMap, ArrayList> EVENTLISTENER_REGISTRY = new HashMap<>(); + // If a new event type is being registered, add a new arraylist + ArrayList registryList = EVENTLISTENER_REGISTRY.putIfAbsent(type, new ArrayList<>()); + if (registryList == null) { + registryList = EVENTLISTENER_REGISTRY.get(type); + } + registryList.add(eventListener); + } + } + } - /** - * Registers an object to be an event listener. The object must implement an event extending {@link EventBase} - * @param eventListener The event listener to register - */ - public static void register(EventBase eventListener) { - if (eventListener == null) { - throw new NullPointerException("Tried to register a packethandler with value null"); - } - for (Class type : eventListener.getClass().getInterfaces()) { - if (EventBase.class.isAssignableFrom(type)) { + /** + * Unregisters an object from being an event listener. + * + * @param eventListener The event listener to unregister + */ + public static void unregister(EventBase eventListener) { + if (eventListener == null) { + throw new NullPointerException("Tried to unregister a packethandler with value null"); + } + for (Class type : eventListener.getClass().getInterfaces()) { + if (EventBase.class.isAssignableFrom(type)) { + ArrayList registryList = EVENTLISTENER_REGISTRY.get(type); + if (registryList != null) { + registryList.remove(eventListener); - // If a new event type is being registered, add a new arraylist - ArrayList registryList = EVENTLISTENER_REGISTRY.putIfAbsent(type, new ArrayList<>()); - if (registryList == null) { - registryList = EVENTLISTENER_REGISTRY.get(type); - } - registryList.add(eventListener); - } - } - } + if (registryList.isEmpty()) { + EVENTLISTENER_REGISTRY.remove(type); + } + } + } + } + } - /** - * Unregisters an object from being an event listener. - * @param eventListener The event listener to unregister - */ - public static void unregister(EventBase eventListener) { - if (eventListener == null) { - throw new NullPointerException("Tried to unregister a packethandler with value null"); - } - for (Class type : eventListener.getClass().getInterfaces()) { - if (EventBase.class.isAssignableFrom(type)) { - ArrayList registryList = EVENTLISTENER_REGISTRY.get(type); - if (registryList != null) { - registryList.remove(eventListener); + /** + * Fires an event without parameters + * + * @param eventClass The event class to fire e.g. EventClientInit.class + * @return The result of the event, might be null if the event returns nothing + */ + public static Object fireEvent(Class eventClass) { + return fireEvent(eventClass, new Object[] {}); + } - if (registryList.isEmpty()) { - EVENTLISTENER_REGISTRY.remove(type); - } - } - } - } - } + /** + * Fires an event with parameters + * + * @param eventClass The event class to fire e.g. EventClientInit.class + * @param eventParams List of parameters for the event. Number of arguments and + * types have to match. + * @return The result of the event, might be null if the event returns nothing + */ + public static Object fireEvent(Class eventClass, Object... eventParams) { + ArrayList listenerList = EVENTLISTENER_REGISTRY.get(eventClass); + if (listenerList == null) { + return null; + } - /** - * Fires an event without parameters - * - * @param eventClass The event class to fire e.g. EventClientInit.class - * @return The result of the event, might be null if the event returns nothing - */ - public static Object fireEvent(Class eventClass) { - return fireEvent(eventClass, new Object[]{}); - } + // Exception to be thrown at the end of the method. If null then no exception is + // thrown + EventException toThrow = null; - /** - * Fires an event with parameters - * - * @param eventClass The event class to fire e.g. EventClientInit.class - * @param eventParams List of parameters for the event. Number of arguments and types have to match. - * @return The result of the event, might be null if the event returns nothing - */ - public static Object fireEvent(Class eventClass, Object... eventParams) { - ArrayList listenerList = EVENTLISTENER_REGISTRY.get(eventClass); - if (listenerList == null) { - throw new EventException("The event has not been registered yet", eventClass); - } + // Get the method from the event that we are looking for in the event listeners + Method methodToFind = getEventMethod(eventClass); - // Exception to be thrown at the end of the method. If null then no exception is thrown - EventException toThrow = null; + // Variable for the return value. The last registered listener will return its + // value + Object returnValue = null; - // Get the method from the event that we are looking for in the event listeners - Method methodToFind = getEventMethod(eventClass); + // Iterate through the list of eventListeners + for (EventBase eventListener : listenerList) { + // Get all methods in this event listener + Method[] methodsInListener = eventListener.getClass().getDeclaredMethods(); - // Variable for the return value. The last registered listener will return its value - Object returnValue = null; + // Iterate through all methods + for (Method method : methodsInListener) { - // Iterate through the list of eventListeners - for (EventBase eventListener : listenerList) { - // Get all methods in this event listener - Method[] methodsInListener = eventListener.getClass().getDeclaredMethods(); + // Check if the current method has the same name as the method we are looking + // for + if (!checkName(method, methodToFind.getName())) { + continue; + } - // Iterate through all methods - for (Method method : methodsInListener) { + // Check if the length is the same before we check for types + if (!checkLength(method, eventParams)) { + toThrow = new EventException(String.format("Event fired with the wrong number of parameters. Expected: %s, Actual: %s", method.getParameterCount(), eventParams.length), eventClass); + continue; + } - // Check if the current method has the same name as the method we are looking for - if (!checkName(method, methodToFind.getName())) { - continue; - } + // Check the types of the method + if (checkTypes(method, eventParams)) { + toThrow = null; // Reset toThrow as the correct method was found + method.setAccessible(true); + try { + returnValue = method.invoke(eventListener, eventParams); // Call the method + } catch (IllegalAccessException | InvocationTargetException e) { + throw new EventException(eventClass, e); + } catch (IllegalArgumentException e) { + throw new EventException(String.format("Event fired with the wrong number of parameters. Expected: %s, Actual: %s", method.getParameterCount(), eventParams.length), eventClass, e); + } + } else { + toThrow = new EventException("Event seems to be fired with the wrong parameter types or in the wrong order", eventClass); + } + } + } - // Check if the length is the same before we check for types - if (!checkLength(method, eventParams)) { - toThrow = new EventException(String.format("Event fired with the wrong number of parameters. Expected: %s, Actual: %s", method.getParameterCount(), eventParams.length), eventClass); - continue; - } + // Throw the exception + if (toThrow != null) { + throw toThrow; + } - // Check the types of the method - if (checkTypes(method, eventParams)) { - toThrow = null; // Reset toThrow as the correct method was found - method.setAccessible(true); - try { - returnValue = method.invoke(eventListener, eventParams); // Call the method - } catch (IllegalAccessException | InvocationTargetException e) { - throw new EventException(eventClass, e); - } catch (IllegalArgumentException e) { - throw new EventException(String.format("Event fired with the wrong number of parameters. Expected: %s, Actual: %s", method.getParameterCount(), eventParams.length), eventClass, e); - } - } else { - toThrow = new EventException("Event seems to be fired with the wrong parameter types or in the wrong order", eventClass); - } - } - } + return returnValue; + } - // Throw the exception - if (toThrow != null) { - throw toThrow; - } + private static Method getEventMethod(Class eventClass) { + Method[] test = eventClass.getDeclaredMethods(); + if (test.length != 1) { + throw new EventException("The event method is not properly defined. Only one method is allowed inside of an event", eventClass); + } - return returnValue; - } + return test[0]; + } - private static Method getEventMethod(Class eventClass) { - Method[] test = eventClass.getDeclaredMethods(); - if (test.length != 1) { - throw new EventException("The event method is not properly defined. Only one method is allowed inside of an event", eventClass); - } + /** + * @param method The method to check + * @param name The name to check + * @return If method.getName equals name + */ + private static boolean checkName(Method method, String name) { + return method.getName().equals(name); + } - return test[0]; - } + /** + * @param method The method to check + * @param parameters The list of parameters + * @return True, if length of the method parameters is equal to the length of + * the object parameters + */ + private static boolean checkLength(Method method, Object... parameters) { + return method.getParameterCount() == parameters.length; + } - /** - * @param method The method to check - * @param name The name to check - * @return If method.getName equals name - */ - private static boolean checkName(Method method, String name) { - return method.getName().equals(name); - } + /** + * @param method The method to check + * @param parameters The list of parameters + * @return True, if the types of the parameters equal the object parameters + */ + private static boolean checkTypes(Method method, Object... parameters) { + Class[] methodParameterTypes = ClassUtils.primitivesToWrappers(method.getParameterTypes()); + Class[] eventParameterTypes = getParameterTypes(parameters); - /** - * @param method The method to check - * @param parameters The list of parameters - * @return True, if length of the method parameters is equal to the length of the object parameters - */ - private static boolean checkLength(Method method, Object... parameters) { - return method.getParameterCount() == parameters.length; - } + for (int i = 0; i < methodParameterTypes.length; i++) { + Class paramName = methodParameterTypes[i]; + Class eventName = eventParameterTypes[i]; - /** - * @param method The method to check - * @param parameters The list of parameters - * @return True, if the types of the parameters equal the object parameters - */ - private static boolean checkTypes(Method method, Object... parameters) { - Class[] methodParameterTypes = ClassUtils.primitivesToWrappers(method.getParameterTypes()); - Class[] eventParameterTypes = getParameterTypes(parameters); + if (paramName == null || eventName == null) { + continue; + } - for (int i = 0; i < methodParameterTypes.length; i++) { - Class paramName = methodParameterTypes[i]; - Class eventName = eventParameterTypes[i]; - if (!paramName.equals(eventName)) { - return false; - } - } - return true; - } + if (!paramName.equals(eventName) && !paramName.isAssignableFrom(eventName)) { + return false; + } + } + return true; + } - private static Class[] getParameterTypes(Object... parameters) { - Class[] out = new Class[parameters.length]; - for (int i = 0; i < parameters.length; i++) { - out[i] = parameters[i].getClass(); - } - return out; - } + private static Class[] getParameterTypes(Object... parameters) { + Class[] out = new Class[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + out[i] = parameters[i] == null ? null : parameters[i].getClass(); + } + return out; + } - /** - * Removes all registry entries - */ - public static void clear() { - EVENTLISTENER_REGISTRY.clear(); - } + /** + * Removes all registry entries + */ + public static void clear() { + EVENTLISTENER_REGISTRY.clear(); + } } diff --git a/src/test/java/mctcommon/event/EventTest.java b/src/test/java/mctcommon/event/EventTest.java index d1b98727..cf1bdd3a 100644 --- a/src/test/java/mctcommon/event/EventTest.java +++ b/src/test/java/mctcommon/event/EventTest.java @@ -164,9 +164,6 @@ void testUnregister() { EventListenerRegistry.unregister(event); - Exception exception = assertThrows(EventException.class, () -> EventListenerRegistry.fireEvent(TestEvent.class)); - - String expected = "mctcommon.event.EventTest$TestEvent: The event has not been registered yet"; - assertEquals(expected, exception.getMessage()); + assertNull(EventListenerRegistry.fireEvent(TestEvent.class)); } }