From 903752d23ae884e1a74e51079016bafbd414d0c6 Mon Sep 17 00:00:00 2001 From: Andreas Troelsen Date: Thu, 1 Jul 2021 21:30:00 +0200 Subject: [PATCH] Add support for registering subcommands by instance. This commit introduces a new `register()` method on the CommandHandler class to allow registering pre-instantiated subcommands. This means that subcommands are no longer restricted in terms of instantiation, so they can have their dependencies injected at creation, rather than having to resort to Singleton anti-pattern means. Also refactors the existing internal MobArena command registration to use the new method to "drink our own champagne" and to reuse the code. Fixes #675 --- changelog.md | 3 ++ .../MobArena/commands/CommandHandler.java | 34 +++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index bca9995..abf44c7 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,9 @@ These changes will (most likely) be included in the next version. ## [Unreleased] +### Added +- (API) MobArena's internal command handler now supports registering pre-instantiated subcommand instances. This should make it easier for extensions to avoid the Singleton anti-pattern for command dependencies. + ### Changed - The regex pattern for the player list command is now less greedy, so it will only match on `/ma players`, `/ma playerlist`, and `/ma player-list`. The previous pattern matched on anything that starts with `player`, which rendered the `/ma player-stats` command in MobArenaStats impossible to invoke. diff --git a/src/main/java/com/garbagemule/MobArena/commands/CommandHandler.java b/src/main/java/com/garbagemule/MobArena/commands/CommandHandler.java index f05e885..7ff06b4 100644 --- a/src/main/java/com/garbagemule/MobArena/commands/CommandHandler.java +++ b/src/main/java/com/garbagemule/MobArena/commands/CommandHandler.java @@ -349,14 +349,34 @@ public class CommandHandler implements CommandExecutor, TabCompleter * @param c a Command */ public void register(Class c) { - CommandInfo info = c.getAnnotation(CommandInfo.class); - if (info == null) return; - try { - commands.put(info.pattern(), c.newInstance()); - } - catch (Exception e) { - e.printStackTrace(); + Command command = c.newInstance(); + register(command); + } catch (ReflectiveOperationException e) { + throw new IllegalArgumentException("Failed to instantiate Command class: " + c.getName(), e); } } + + /** + * Register a command instance. + *

+ * Adds the given command to MobArena's internal command handler as a + * subcommand, overwriting any existing subcommand mappings. This means + * that the method is safe to call on reloads as long as a reload does + * not change the pattern of a registered command. + * + * @param command the Command instance to register + * @throws IllegalArgumentException if the CommandInfo annotation is + * missing from the class of the Command instance + */ + public void register(Command command) { + Class cls = command.getClass(); + CommandInfo info = cls.getAnnotation(CommandInfo.class); + if (info == null) { + throw new IllegalArgumentException("Missing CommandInfo annotation on class " + cls.getName()); + } + + commands.put(info.pattern(), command); + } + }