Hello, I am currently working on creating a custom listener class but I have run into some issues. When the inherited class is initialized in main I get an error. AbstractListener Class Code (Java): public abstract class AbstractListener<E extends Event> implements Listener { @EventHandler public void onEvent(E event) { if (event instanceof PlayerEvent) { callEvent(event); } } public void initialise(Plugin plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } public abstract void callEvent(E event); } InheritedAbstractListener Class Code (Java): public class InheritedAbstractListener<PlayerJoinEvent> { @Override public void callEvent(PlayerJoinEvent event) { } } Error Code (Text): org.bukkit.plugin.IllegalPluginAccessException: Unable to find handler list for event org.bukkit.event.Event. Static getHandlerList method required!
I'd guess using a generic type breaks Bukkit's event handler because it can't guarantee there's a static #getHandlerList method in that case.
Generics in java are kind of just "syntactic sugar" in the sense that they do not exist at runtime. They are basically just a help for the compiler to assume objects to be of certain type at runtime so it knows things won't break. This is mostly due to backwards compatibility with older java programs since they didn't have generics at all. This is what's called type erasure. Basically, it will go down to the lowest possible type, which in this case is Event, since you've specified that as the lower bound of the generic parameter. If you want to check for yourself, startup jshell (if you have it) and call "InheritedAbstractListener.class.getMethods()" which will return - among others - the onEvent methods with one parameter of type Event. Simplest solution I would come up with is to create a protected method that receives the base event type and contains all the logic but does not have the event handler annotation. And then in each subtype you create a method that is basically just there to be an entry point for bukkit (so has EventHandler annotation and a concrete event type) as it just calls that protected method. (P.S.: If you notice the .getMethods() returns two callEvent methods; one with Event as a parameter type and one with the concrete PlayerJoinEvent type. Same rules apply here, which is why the base method still exists with the Event type, but since you overwrite it, you create an actual new method which has the concrete type. For java, this isn't the same method.)
Why are you using E here Code (Text): public void onEvent(E event) { Just to check if it's a PlayerEvent afterwards? What you could listen for is Event event. Your abstract class can than ask for Class<E> as q constructor parameter. Now you can replace your instance of call to a Code (Text): theClassFromConstructor.isInstance(event)