From 0be34242dbf04a10ea09113ff76b2d1870c92cc1 Mon Sep 17 00:00:00 2001 From: Proximyst Date: Thu, 31 May 2018 19:10:23 -0400 Subject: [PATCH] Updated JavaDocs from PR #116 --- .../java/co/aikar/commands/ACFPatterns.java | 12 + .../co/aikar/commands/AnnotationLookups.java | 111 ++++++- .../java/co/aikar/commands/Annotations.java | 4 +- .../java/co/aikar/commands/BaseCommand.java | 304 +++++++++++++++++- .../commands/annotation/CommandAlias.java | 8 + .../annotation/CommandPermission.java | 5 + .../co/aikar/commands/annotation/Default.java | 4 + .../aikar/commands/annotation/Dependency.java | 4 + .../commands/annotation/Description.java | 4 + .../aikar/commands/annotation/Optional.java | 7 + .../aikar/commands/annotation/PreCommand.java | 3 + .../co/aikar/commands/annotation/Split.java | 4 + .../co/aikar/commands/annotation/Syntax.java | 9 + .../commands/contexts/ContextResolver.java | 19 ++ .../contexts/OptionalContextResolver.java | 7 +- 15 files changed, 484 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/co/aikar/commands/ACFPatterns.java b/core/src/main/java/co/aikar/commands/ACFPatterns.java index ee4e9b42..fc4765bb 100644 --- a/core/src/main/java/co/aikar/commands/ACFPatterns.java +++ b/core/src/main/java/co/aikar/commands/ACFPatterns.java @@ -60,6 +60,18 @@ final class ACFPatterns { .expirationPolicy(ExpirationPolicy.ACCESSED) .build(); + /** + * Gets a pattern and compiles it. + * If the pattern is stored already in {@link #patternCache}, it will simply fetch it from there. + * If it is not, it will store it there for further use. + *

+ * The {@link #patternCache} does not contain the constant patterns defined in this class. + * + * @param pattern + * The raw pattern in a String. + * + * @return The pattern which has been cached. + */ public static Pattern getPattern(String pattern) { return patternCache.computeIfAbsent(pattern, s -> Pattern.compile(pattern)); } diff --git a/core/src/main/java/co/aikar/commands/AnnotationLookups.java b/core/src/main/java/co/aikar/commands/AnnotationLookups.java index 72c52019..1089a333 100644 --- a/core/src/main/java/co/aikar/commands/AnnotationLookups.java +++ b/core/src/main/java/co/aikar/commands/AnnotationLookups.java @@ -29,25 +29,111 @@ import java.util.regex.Pattern; abstract class AnnotationLookups { + /** + * This checks whether the {@link AnnotatedElement} given has an annotation of the type given as annoClass. + * + * Runs through annotation processing + * + * @param object + * The element to check whether has an annotation of annoClass. + * @param annoClass + * The annotation type in form of a class. + * + * @return Whether an annotation of annoClass is attached to element. + * + * @see #hasAnnotation(AnnotatedElement, Class, boolean) + */ boolean hasAnnotation(AnnotatedElement object, Class annoClass) { return getAnnotationValue(object, annoClass, Annotations.NOTHING) != null; } + /** + * This checks whether the {@link AnnotatedElement} given has an annotation of the type given as annoClass. + * If the value is empty/null and allowEmpty is false, it will return false. + * + * @param object + * The element to check whether has an annotation of annoClass. + * @param annoClass + * The annotation type in form of a class. + * @param allowEmpty + * Whether or not to allow empty/null values. + * + * @return Whether an annotation of annoClass is attached to element, and if allowEmpty is false, whether it has a value. + */ boolean hasAnnotation(AnnotatedElement object, Class annoClass, boolean allowEmpty) { return getAnnotationValue(object, annoClass, Annotations.NOTHING | (allowEmpty ? 0 : Annotations.NO_EMPTY)) != null; } + /** + * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has. + * If the value contains a pipe (|), it will split on this and return an array of more indicies than 1. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * + * @return All the values of annoClass on the object split by pipe (|). If the value is empty, this is null. + * + * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int) + */ String[] getAnnotationValues(AnnotatedElement object, Class annoClass) { return getAnnotationValues(object, annoClass, ACFPatterns.PIPE, Annotations.REPLACEMENTS); } + + /** + * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has. + * The value is split by the pattern given and return an array of more indicies than 1. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * @param pattern + * The pattern the value element is split on. + * + * @return All the values of annoClass on the object split by the pattern given. If the value is empty, this is null. + * + * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int) + */ String[] getAnnotationValues(AnnotatedElement object, Class annoClass, Pattern pattern) { return getAnnotationValues(object, annoClass, pattern, Annotations.REPLACEMENTS); } + /** + * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has. + * The value is split by all pipes (|), but must follow the options. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * @param options + * The options to use. If several options are wanted, use the OR operator (opt1 | opt2). + * + * @return All the values of annoClass on the object split by a pipe (|). Nullability depends on options. + * + * @see #getAnnotationValues(AnnotatedElement, Class, Pattern, int) + */ String[] getAnnotationValues(AnnotatedElement object, Class annoClass, int options) { return getAnnotationValues(object, annoClass, ACFPatterns.PIPE, options); } + /** + * This fetches all the values the {@link AnnotatedElement}'s annotation of type annoClass has. + * The value is split by the pattern given, and must also follow the options. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * @param options + * The options to use. If several options are wanted, use the OR operator (opt1 | opt2). + * @param pattern + * The pattern to split by each occurrence of. + * + * @return All the values of annoClass on the object split by the pattern given. Nullability depends on options. + */ String[] getAnnotationValues(AnnotatedElement object, Class annoClass, Pattern pattern, int options) { String value = getAnnotationValue(object, annoClass, options); if (value == null) { @@ -56,9 +142,32 @@ abstract class AnnotationLookups { return pattern.split(value); } + /** + * Gets the value of the {@link AnnotatedElement}'s annotation of type annoClass as a string. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * + * @return The value of the annotation on the object given. + */ String getAnnotationValue(AnnotatedElement object, Class annoClass) { return getAnnotationValue(object, annoClass, Annotations.REPLACEMENTS); } - abstract String getAnnotationValue(AnnotatedElement annotation, Class annoClass, int options); + /** + * Gets the value of the {@link AnnotatedElement}'s annotation of type annoClass as a string. + * The value has to follow the given options. + * + * @param object + * The element to check the value of the annotation of type annoClass. + * @param annoClass + * The annotation type in form of a class. + * @param options + * The options to use. If several options are wanted, use the OR operator (opt1 | opt2). + * + * @return The value of the annotation on the object given. Nullability depends on options. + */ + abstract String getAnnotationValue(AnnotatedElement object, Class annoClass, int options); } diff --git a/core/src/main/java/co/aikar/commands/Annotations.java b/core/src/main/java/co/aikar/commands/Annotations.java index f9a05b08..7821f28e 100644 --- a/core/src/main/java/co/aikar/commands/Annotations.java +++ b/core/src/main/java/co/aikar/commands/Annotations.java @@ -49,8 +49,8 @@ class Annotations extends AnnotationLookups { this.manager = manager; } - String getAnnotationValue(AnnotatedElement element, Class annoClass, int options) { - Annotation annotation = element.getAnnotation(annoClass); + String getAnnotationValue(AnnotatedElement object, Class annoClass, int options) { + Annotation annotation = object.getAnnotation(annoClass); String value = null; if (annotation != null) { diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index 50d0a357..424dcb6a 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -42,6 +42,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -64,8 +65,17 @@ import java.util.stream.Stream; @SuppressWarnings("unused") public abstract class BaseCommand { - public static final String CATCHUNKNOWN = "__catchunknown"; - public static final String DEFAULT = "__default"; + /** + * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown + * argument to command states. + */ + static final String CATCHUNKNOWN = "__catchunknown"; + /** + * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the + * entire base command. + */ + static final String DEFAULT = "__default"; + final SetMultimap subCommands = HashMultimap.create(); final Map, String> contextFlags = Maps.newHashMap(); private Method preCommandHandler; @@ -77,16 +87,42 @@ public abstract class BaseCommand { @SuppressWarnings("WeakerAccess") private String[] origArgs; CommandManager manager = null; + + /** + * The command which owns this. This may be null if there are no owners. + */ BaseCommand parentCommand; Map registeredCommands = new HashMap<>(); - String description; - String commandName; - String permission; - String conditions; + /** + * The description of the command. This may be null if no description has been provided. + * Used for help documentation + */ + @Nullable String description; + /** + * The name of the command. This may be null if no name has been provided. + */ + @Nullable String commandName; + /** + * The permission of the command. This may be null if no permission has been provided. + */ + @Nullable String permission; + /** + * The conditions of the command. This may be null if no conditions has been provided. + */ + @Nullable String conditions; + /** + * The handler of all uncaught exceptions thrown by the user's command implementation. + */ private ExceptionHandler exceptionHandler = null; - CommandOperationContext lastCommandOperationContext; - private String parentSubcommand; + /** + * The last operative context data of this command. This may be null if this command hasn't been run yet. + */ + @Nullable CommandOperationContext lastCommandOperationContext; + /** + * If a parent exists to this command, and it has a Subcommand annotation, prefix all subcommands in this class with this + */ + @Nullable private String parentSubcommand; public BaseCommand() {} public BaseCommand(String cmd) { @@ -120,9 +156,27 @@ public abstract class BaseCommand { void setParentCommand(BaseCommand command) { this.parentCommand = command; } + + /** + * This should be called whenever the command gets registered. + * It sets all required fields correctly and injects dependencies. + * + * @param manager + * The manager to register as this command's owner and handler. + */ void onRegister(CommandManager manager) { onRegister(manager, this.commandName); } + + /** + * This should be called whenever the command gets registered. + * It sets all required fields correctly and injects dependencies. + * + * @param manager + * The manager to register as this command's owner and handler. + * @param cmd + * The command name to use register with. + */ void onRegister(CommandManager manager, String cmd) { manager.injectDependencies(this); this.manager = manager; @@ -160,6 +214,12 @@ public abstract class BaseCommand { } + /** + * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}. + * + * @param cmd + * The command name of this command. + */ private void registerSubclasses(String cmd) { for (Class clazz : this.getClass().getDeclaredClasses()) { if (BaseCommand.class.isAssignableFrom(clazz)) { @@ -191,6 +251,9 @@ public abstract class BaseCommand { } } + /** + * This registers all subcommands of the command. + */ private void registerSubcommands() { final Annotations annotations = manager.getAnnotations(); boolean foundDefault = false; @@ -256,6 +319,14 @@ public abstract class BaseCommand { } } + /** + * Gets the subcommand name of the method given. + * + * @param method + * The method to check. + * + * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached. + */ private String getSubcommandValue(Method method) { final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING); if (sub == null) { @@ -279,6 +350,14 @@ public abstract class BaseCommand { return ACFUtil.join(subList, " "); } + /** + * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given. + * + * @param name + * Name of the parent to cmd. + * @param cmd + * The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field. + */ private void register(String name, BaseCommand cmd) { String nameLower = name.toLowerCase(); RootCommand rootCommand = manager.obtainRootCommand(nameLower); @@ -287,6 +366,14 @@ public abstract class BaseCommand { this.registeredCommands.put(nameLower, rootCommand); } + /** + * Registers the given {@link Method} as a subcommand. + * + * @param method + * The method to register as a subcommand. + * @param subCommand + * The subcommand's name(s). + */ private void registerSubcommand(Method method, String subCommand) { subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase()); final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand); @@ -373,13 +460,13 @@ public abstract class BaseCommand { } if (subCommands.get(DEFAULT) != null && args.length == 0) { - executeSubcommand(commandContext, DEFAULT, issuer, args); + findAndExecuteCommand(commandContext, DEFAULT, issuer, args); } else if (subCommands.get(CATCHUNKNOWN) != null) { - if (!executeSubcommand(commandContext, CATCHUNKNOWN, issuer, args)) { + if (!findAndExecuteCommand(commandContext, CATCHUNKNOWN, issuer, args)) { help(issuer, args); } } else if (subCommands.get(DEFAULT) != null) { - executeSubcommand(commandContext, DEFAULT, issuer, args); + findAndExecuteCommand(commandContext, DEFAULT, issuer, args); } } finally { @@ -387,11 +474,23 @@ public abstract class BaseCommand { } } + /** + * Gets the registered command of the given arguments. + * @param args + * The arguments given by the user. + * + * @return The subcommand or null if none were found. + * + * @see #findSubCommand(String[]) + */ RegisteredCommand getRegisteredCommand(String[] args) { final CommandSearch cmd = findSubCommand(args); return cmd != null ? cmd.cmd : null; } + /** + * This is ran after any command operation has been performed. + */ private void postCommandOperation() { CommandManager.commandOperationContext.get().pop(); execSubcommand = null; @@ -399,6 +498,22 @@ public abstract class BaseCommand { origArgs = new String[]{}; } + /** + * This is ran before any command operation has been performed. + * + * @param issuer + * The user who executed the command. + * @param commandLabel + * The label the user used to execute the command. This is not the command name, but their input. + * When there is multiple aliases, this is which alias was used + * @param args + * The arguments passed to the command when executing it. + * @param isAsync + * Whether the command is executed off of the main thread. + * + * @return The context which is being registered to the {@link CommandManager}'s {@link + * CommandManager#commandOperationContext thread local stack}. + */ private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) { Stack contexts = CommandManager.commandOperationContext.get(); CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync); @@ -410,16 +525,48 @@ public abstract class BaseCommand { return context; } + /** + * Gets the current command issuer. + * + * @return The current command issuer. + */ public CommandIssuer getCurrentCommandIssuer() { return CommandManager.getCurrentCommandIssuer(); } + + /** + * Gets the current command manager. + * + * @return The current command manager. + */ public CommandManager getCurrentCommandManager() { return CommandManager.getCurrentCommandManager(); } + /** + * Finds a subcommand of the given arguments. + * + * @param args + * The arguments the user input. + * + * @return The identified subcommand. + * + * @see #findSubCommand(String[], boolean) + */ private CommandSearch findSubCommand(String[] args) { return findSubCommand(args, false); } + + /** + * Finds a subcommand of the given arguments. + * + * @param args + * The arguments the user input. + * @param completion + * Whether or not completion of arguments should kick in. This may end up with worse than wanted results. + * + * @return The identified subcommand. + */ private CommandSearch findSubCommand(String[] args, boolean completion) { for (int i = args.length; i >= 0; i--) { String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); @@ -470,13 +617,49 @@ public abstract class BaseCommand { } } + /** + * Please use command conditions for restricting execution + * @deprecated See {@link CommandConditions} + * @param issuer + * @param cmd + * @return + */ + @Deprecated public boolean canExecute(CommandIssuer issuer, RegisteredCommand cmd) { return true; } + /** + * Gets tab completed data from the given command from the user. + * + * @param issuer + * The user who executed the tabcomplete. + * @param commandLabel + * The label which is being used by the user. + * @param args + * The arguments the user has typed so far. + * + * @return All possibilities in the tab complete. + */ public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args) { return tabComplete(issuer, commandLabel, args, false); } + + /** + * Gets the tab complete suggestions from a given command. This will automatically find anything + * which is valid for the specified command through the command's implementation. + * + * @param issuer + * The issuer of the command. + * @param commandLabel + * The command name as entered by the user instead of the ACF registered name. + * @param args + * All arguments entered by the user. + * @param isAsync + * Whether this is run off of the main thread. + * + * @return The possibilities to tab complete in no particular order. + */ public List tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) throws IllegalArgumentException { @@ -506,6 +689,15 @@ public abstract class BaseCommand { } } + /** + * Gets all subcommands which are possible to tabcomplete. + * + * @param issuer + * The command issuer. + * @param args + * + * @return + */ List getCommandsForCompletion(CommandIssuer issuer, String[] args) { final Set cmds = new HashSet<>(); final int cmdIndex = Math.max(0, args.length - 1); @@ -525,6 +717,22 @@ public abstract class BaseCommand { return new ArrayList<>(cmds); } + /** + * Complete a command properly per issuer and input. + * + * @param issuer + * The user who executed this. + * @param cmd + * The command to be completed. + * @param args + * All arguments given by the user. + * @param commandLabel + * The command name the user used. + * @param isAsync + * Whether the command was executed async. + * + * @return All results to complete the command. + */ private List completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) { if (!cmd.hasPermission(issuer) || args.length > cmd.consumeInputResolvers || args.length == 0 || cmd.complete == null) { return ImmutableList.of(); @@ -534,6 +742,16 @@ public abstract class BaseCommand { return filterTabComplete(args[args.length-1], cmds); } + /** + * Gets the actual args in string form the user typed + * This returns a list of all tab complete options which are possible with the given argument and commands. + * @param arg + * Argument which was pressed tab on. + * @param cmds + * The possibilities to return. + * + * @return All possible options. This may be empty. + */ private static List filterTabComplete(String arg, List cmds) { return cmds.stream() .distinct() @@ -541,11 +759,30 @@ public abstract class BaseCommand { .collect(Collectors.toList()); } - RegisteredCommand getSubcommand(String subcommand) { - return getSubcommand(subcommand, false); + /** + * Gets a registered command under the given subcommand name. + * + * @param subcommand + * The name of the subcommand requested. + * + * @return The subcommand found or null if none. + */ + private RegisteredCommand getCommandBySubcommand(String subcommand) { + return getCommandBySubcommand(subcommand, false); } - RegisteredCommand getSubcommand(String subcommand, boolean requireOne) { + /** + * Gets a registered command under the given name. + * If requireOne is true, it won't accept more than a single matching subcommand. + * + * @param subcommand + * Name of the subcommand wanted. + * @param requireOne + * Whether to only accept 1 result. + * + * @return The subcommand found, or null if none/too many. + */ + private RegisteredCommand getCommandBySubcommand(String subcommand, boolean requireOne) { final Set commands = subCommands.get(subcommand); if (!commands.isEmpty() && (!requireOne || commands.size() == 1)) { return commands.iterator().next(); @@ -553,8 +790,27 @@ public abstract class BaseCommand { return null; } - private boolean executeSubcommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { - final RegisteredCommand cmd = this.getSubcommand(subcommand); + /** + * Internally calls {@link #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand)} + * and gets through {@link #getCommandBySubcommand(String)}. + * + * @param commandContext + * The command context to use. + * @param subcommand + * The subcommand to find the executor of. + * @param issuer + * The issuer who executed the subcommand. + * @param args + * All arguments given by the issuer. + * + * @return Whether it found a command or not. + * + * @see #executeCommand(CommandOperationContext, CommandIssuer, String[], RegisteredCommand) + * @see #getCommandBySubcommand(String) + * @see RegisteredCommand#invoke(CommandIssuer, List, CommandOperationContext) + */ + private boolean findAndExecuteCommand(CommandOperationContext commandContext, String subcommand, CommandIssuer issuer, String... args) { + final RegisteredCommand cmd = this.getCommandBySubcommand(subcommand); if (cmd != null) { executeCommand(commandContext, issuer, args, cmd); return true; @@ -563,6 +819,20 @@ public abstract class BaseCommand { return false; } + /** + * Executes the precommand and sees whether something is wrong. Ideally, you get false from this. + * + * @param commandOperationContext + * The context to use. + * @param cmd + * The command executed. + * @param issuer + * The issuer who executed the command. + * @param args + * The arguments the issuer provided. + * + * @return Whether something went wrong. + */ private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) { Method pre = this.preCommandHandler; if (pre != null) { @@ -657,7 +927,7 @@ public abstract class BaseCommand { } public RegisteredCommand getDefaultRegisteredCommand() { - return this.getSubcommand(DEFAULT); + return this.getCommandBySubcommand(DEFAULT); } public String setContextFlags(Class cls, String flags) { diff --git a/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java b/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java index 2b1ab723..54b6c6dd 100644 --- a/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java +++ b/core/src/main/java/co/aikar/commands/annotation/CommandAlias.java @@ -28,6 +28,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Allows to add a single or several command alias(es). + * In order to add more than one in a single go, use the syntax "alias|otheralias". + * You can register as many aliases as wanted in a single value. + * + * Used on a Class, defines the root command for all subcommands in the base command. + * Used on a method, defines a root command alias to that specific command + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface CommandAlias { diff --git a/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java b/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java index 919bb6a6..96c3111a 100644 --- a/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java +++ b/core/src/main/java/co/aikar/commands/annotation/CommandPermission.java @@ -28,6 +28,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Sets the permission required to perform this command. + * + * Permission format will vary based on implementation platform + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface CommandPermission { diff --git a/core/src/main/java/co/aikar/commands/annotation/Default.java b/core/src/main/java/co/aikar/commands/annotation/Default.java index 2d60ca90..93be2219 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Default.java +++ b/core/src/main/java/co/aikar/commands/annotation/Default.java @@ -28,6 +28,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * If used on a method, sets default command handler for the root command of this group + * If used on a parameter, sets the value to be used for context resolution + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.PARAMETER}) public @interface Default { diff --git a/core/src/main/java/co/aikar/commands/annotation/Dependency.java b/core/src/main/java/co/aikar/commands/annotation/Dependency.java index 5b19d810..4df4d200 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Dependency.java +++ b/core/src/main/java/co/aikar/commands/annotation/Dependency.java @@ -28,6 +28,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Injects a dependency into the field this is attached to. + * Any time a new dependency is registered, this will be overwritten. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Dependency { diff --git a/core/src/main/java/co/aikar/commands/annotation/Description.java b/core/src/main/java/co/aikar/commands/annotation/Description.java index 6de1260d..96aa234e 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Description.java +++ b/core/src/main/java/co/aikar/commands/annotation/Description.java @@ -28,6 +28,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Sets a description to the parameter or method this is attached to. + * This is used in the help menus. + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.PARAMETER}) public @interface Description { diff --git a/core/src/main/java/co/aikar/commands/annotation/Optional.java b/core/src/main/java/co/aikar/commands/annotation/Optional.java index a6e1618a..b7a96ead 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Optional.java +++ b/core/src/main/java/co/aikar/commands/annotation/Optional.java @@ -28,6 +28,13 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Marks the parameter this is attached to as optional. + * This will set the parameter as null if it was not provided. + *

+ * In the case the language used is Kotlin, Ceylon or any other null-enforcing JVM language, + * you will need to allow for a nullable value. + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER}) public @interface Optional { diff --git a/core/src/main/java/co/aikar/commands/annotation/PreCommand.java b/core/src/main/java/co/aikar/commands/annotation/PreCommand.java index 6c7a5e21..3fa16168 100644 --- a/core/src/main/java/co/aikar/commands/annotation/PreCommand.java +++ b/core/src/main/java/co/aikar/commands/annotation/PreCommand.java @@ -29,6 +29,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * This runs before any other command method each time it is invoked. + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface PreCommand {} diff --git a/core/src/main/java/co/aikar/commands/annotation/Split.java b/core/src/main/java/co/aikar/commands/annotation/Split.java index 2b375d64..994e4de2 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Split.java +++ b/core/src/main/java/co/aikar/commands/annotation/Split.java @@ -29,6 +29,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Joins arguments into a single piece of text with the specified separator. + * For array based parameters, defines the regex pattern to split on + */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER}) public @interface Split { diff --git a/core/src/main/java/co/aikar/commands/annotation/Syntax.java b/core/src/main/java/co/aikar/commands/annotation/Syntax.java index e88f6d86..2f5072e4 100644 --- a/core/src/main/java/co/aikar/commands/annotation/Syntax.java +++ b/core/src/main/java/co/aikar/commands/annotation/Syntax.java @@ -28,6 +28,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Specifies the syntax to be used when executing this command. + * It should not include any descriptions of the arguments nor when some are allowed and when they are not. + * + * Use of this annotation is not necessary. Syntax will be automatically generated for you. + * Use this annotation to override automatic syntax + * + * Use {@link Description} together with the help menu for that purpose. + **/ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.PARAMETER}) public @interface Syntax { diff --git a/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java index 5f2088c5..9b221a02 100644 --- a/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java +++ b/core/src/main/java/co/aikar/commands/contexts/ContextResolver.java @@ -27,7 +27,26 @@ import co.aikar.commands.CommandExecutionContext; import co.aikar.commands.CommandIssuer; import co.aikar.commands.InvalidCommandArgument; +/** + * This defines a context resolver, which parses {@link T} from {@link C}. + * + * @param + * The type to be parsed. + * @param + * The type of the context which the resolver would get its data from. + */ @FunctionalInterface public interface ContextResolver > { + /** + * Parses the context of type {@link C} into {@link T}, or throws an exception. + * + * @param c + * The context to parse from. + * + * @return The parsed instance of the wanted type. + * + * @throws InvalidCommandArgument + * In case the context contains any discrepancies, it will throw this exception. + */ T getContext(C c) throws InvalidCommandArgument; } diff --git a/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java b/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java index cb734c1e..15879fcc 100644 --- a/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java +++ b/core/src/main/java/co/aikar/commands/contexts/OptionalContextResolver.java @@ -27,6 +27,11 @@ import co.aikar.commands.CommandExecutionContext; import co.aikar.commands.CommandIssuer; /** - * Context Resolver that can accept null input + * The same as {@link ContextResolver}, however it can accept a null context. + * + * If the parameter was marked optional, will still be called with an empty args list + * + * @param + * @param */ public interface OptionalContextResolver > extends ContextResolver {}