Reputation: 143
I am trying to implement an Annotation based Event System for my OpenGL Game Engine. I apply the @EventListener Annotation on the method which I want to be called like this:
@EventListener(type = Type.COLLISION)
public void OnCollision(CollisionEvent data)
{
System.out.println("HI");
}
The class in which this method sits implements an Empty Interface:
public class Sprite implements EventHandler
The EventDispatcher class:
public class EventDispatcher
{
private static List<EventHandler> registered = new ArrayList<EventHandler>();
public static void register(EventHandler EventHandler)
{
if (!registered.contains(EventHandler))
{
registered.add(EventHandler);
}
}
public static void unregister(EventHandler EventHandler)
{
if (registered.contains(EventHandler))
{
registered.remove(EventHandler);
}
}
public static List<EventHandler> getRegistered()
{
return registered;
}
public static void dispatch(final Event event)
{
new Thread()
{
@Override
public void run()
{
call(event);
}
}.start();
}
private static void call(final Event event)
{
for (EventHandler registered : getRegistered())
{
Method[] methods = registered.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
{
System.out.println("Annotation Being Checked");
if (methods[i].isAnnotationPresent(EventListener.class))
{
System.out.println("Has Annotation");
Class<?>[] methodParams = methods[i].getParameterTypes();
if (methodParams.length < 1)
{
continue;
}
if (!event.getClass().getSimpleName().equals(methodParams[0].getSimpleName()))
{
continue;
}
try
{
methods[i].invoke(registered.getClass().newInstance(), event);
} catch (Exception exception)
{
System.err.println(exception);
}
} else System.out.println("No Annotation");
}
}
}
}
But when I run the program, It always prints out
Annotation Being Checked
No Annotation
multiple Times.
Can someone help? If more information is needed, please ask and I will edit the Question.
Upvotes: 1
Views: 439
Reputation: 10964
I setup a project based on your example and it's working fine. You will however see some "No Annotation" messages as your code evaluates all methods of the Sprite
event handler. Even if you don't implement any additional methods other than OnCollision
each class will inherit default methods from Object such as equals
, hashCode
or toString
.
Test class:
public class SpriteTest {
public static void main(String[] args) {
EventDispatcher.register(new Sprite());
CollisionEvent collisionEvent = new CollisionEvent();
EventDispatcher.dispatch(collisionEvent);
}
}
Apart from that there are some obvious flaws in your code:
EventHandler
but only use the class information and create a new instance on the fly - why not register the class instead of an instance directlyClass.isAssignableFrom
EventHandler
there could be a CollisionEventHandler
and so on...Rough implementation idea
public interface CollisionEventHandler extends EventHandler {
void onCollision(CollisionEvent event);
}
public class Sprite implements CollisionEventHandler {
public void onCollision(CollisionEvent data) {
System.out.println("HI");
}
}
public class EventDispatcher {
...
static void call(final CollisionEvent event) {
getRegistered().stream()
.filter(handler -> handler instanceof CollisionEventHandler)
.map(handler -> (CollisionEventHandler) handler)
.forEach(handler -> handler.onCollision(event));
}
}
To handle different types of events you will need different call/dispatch methods. Maybe you can use the Visitor pattern (though I'm not a fan of it).
Upvotes: 1