Resource Automatically register all events/listeners at once

Discussion in 'Spigot Plugin Development' started by iUseRod, Sep 5, 2021.

  1. Dependencies:

    Reflections util:
    https://github.com/ronmamo/reflections

    Code (Text):
    <dependency>
                <groupId>org.reflections</groupId>
                <artifactId>reflections</artifactId>
                <version>0.9.12</version>
    </dependency>

    Method:

    Code (Java):
    import org.reflections.Reflections;

    void registerEvents() {
            String packageName = getClass().getPackage().getName();

            for (Class<?> clazz : new Reflections(packageName + ".listener").getSubTypesOf(Listener.class)) {
                try {
                    Listener listener = (Listener) clazz.getDeclaredConstructor().newInstance();
                    getServer().getPluginManager().registerEvents(listener, this);
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }

        }

    NOTE: the Listener classes must be under "
    me.author.plugin.listener" package or you can change it on the code as you like.
     
  2. SteelPhoenix

    Moderator

    Is this really just a dependency extra because people are too lazy to register listeners themselves?
     
    • Agree Agree x 10
  3. I wouldn't recommend using Reflections for stuff like this. Just register the listener normally. I've had Reflections not read classes correctly or throw unexpected errors using a very similar setup to this.
     
    • Like Like x 1
  4. no... i made this because it'll make the code look much cleaner, other than +7 lines of the same code with different names.
     
    • Optimistic Optimistic x 1
  5. there gotta be a reason for the error, it can't just "randomly" gets thrown in lol?
     
    • Agree Agree x 1
  6. So you include a whole reflection library for just 2 lines of code?
    The plugin would be more clean and lightweight without usless libraries.
    There are a lot of useful libraries for java around here, but that doesn't mean that we need to include all of them, just because we cloud write "cleaner code".
    (Having 1kb of your code and 40kb of shaded libraries in the final jar is not good).

    And there is an API for registering an event only having its class (without using EventHandler annotation).

    As my professor always says: "Don't use a bazooka to kill a mosquito"
     
    #6 SignorPollito, Sep 5, 2021
    Last edited: Sep 5, 2021
    • Winner Winner x 6
  7. I mean, it's not really random. It was caused by casting but only happened on some runs. I wouldn't consider this stable at all.
     
  8. I wouldn't recomend people use this. This is a huge instance of, using using a bazooka to kill a mosquito.

    Reasoning

    - Readability: this is far less readable than just registering the events, it's hard to tell what's going on here with the reflective access compared to just registering them.

    -I would only have a register loop for listeners if I had some kind of tree data structure where each listener was a node in the structure

    - Flexibility: now you can't put parameters into your listener classes such as the plugin instance

    - Performance: What if for the readability of my project I have listeners elsewhere, now it has to loop through all those packages even though most of them don't have listeners in them.
     
    #8 DeltaOrion, Sep 6, 2021
    Last edited: Sep 6, 2021
    • Agree Agree x 4
  9. I usually try to avoid tons of lines of registerEvents calls myself, but why not just create a Collection with all your listener classes and just loop through that and register them?
     
  10. Why dont u just dump that library and use:
    Code (Java):

    import com.google.common.reflect.ClassPath;
    import com.google.common.reflect.ClassPath.ClassInfo;

    for (ClassInfo classInfo : cp.getTopLevelClassesRecursive("net.ur.package")) {
        Class<?> c = Class.forName(classInfo.getName());
        if (Listener.class.isAssignableFrom(c)) {
            Bukkit.getServer().getPluginManager().registerEvents((Listener) c.getDeclaredConstructor().newInstance(), pl);
        }
    }
     
    Probably could be made even more cleaner if u wanted
     
    • Like Like x 1
  11. I agree with some stuff u said but classes can have multiple constructors so flexibility isnt problem
    and
    it can be extremely usefull lets say if u have package with 200x commands or listeners
    instead of 200x lines you can make it automatic, so it depends on the situation a lot and how you use it
     
  12. The real question here is how you have 200x commands and havent managed to form a better command data-structure causing you to need to use reflection to register them all. If you have so many commands and you are using reflection to register them all then that is bad code and you should not patch it with a band-aid solution. You should instead create a proper data structure to handle this. If you only have a couple of commands then you should just register them manually. I still dont see a good reason to use this as it is a messy and hard to read solution
     
    • Agree Agree x 2
  13. I mean ye probably bad example that one but I mean I dont see it being such a problem, like I said depends how you use it and on the situation.
     
  14. This is where a dependency injection framework comes in handy :)
     
    • Agree Agree x 1
  15. there are tons of ways to do this, but i've chosen the way that i use, and i respect all your opinions & disagrees, but this resource will come in handy for others.
     
    • Optimistic Optimistic x 1
  16. Eth

    Eth

    Not trying to bash on this resource even more, but two reasons (that haven't been mentioned) not to use this are for debugging and for modularity.
    If I need to make quick changes while I am coding and need to unregister a specific listener to inspect another aspect of my program, this doesn't let me.
    The other thing is that if you do indeed have a project with dozens (or maybe even hundreds) of listener classes where this might apply, the classes should definitely be arranged to each have a parent module that registers its own listeners. This is good practice for a multitude of reasons, but one of them is that it allows you to disable modules that should each be self contained.
     
    • Agree Agree x 1
    • Useful Useful x 1
  17. gotta admit.. that's a good reason tbh, overall, this is a util, i didn't say "use it" i gave a resource to those who will need it in there own cases
     
    • Informative Informative x 1