From ad80933a20ff392a8fc1178998cdb62a970d4db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 2 Oct 2021 11:49:02 +0200 Subject: [PATCH] Feature: Allow argument names to be inferred from parameter names --- CHANGELOG.md | 1 + .../annotations/AnnotationParser.java | 11 ++++++++--- .../commandframework/annotations/Argument.java | 10 ++++++++-- .../annotations/ArgumentParameterPair.java | 8 ++++++++ .../MethodCommandExecutionHandler.java | 16 ++++++++++++---- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d729c56b..e3486368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `executeFuture` to `CommandExecutionHandler` which is now used internally. By default, this delegates to the old `execute` method - Annotations: Apply builder modifiers from class annotations ([#303](https://github.com/Incendo/cloud/pull/303)) +- Annotations: Add default value to `@Argument`, which will force the parser to infer the argument name from the parameter name ### Fixed - Bukkit: Permission checking and syntax string for Bukkit '/help' command diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java index dccc0054..98e78a58 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java @@ -79,6 +79,11 @@ import java.util.function.Function; */ public final class AnnotationParser { + /** + * The value of {@link Argument} that should be used to infer argument names from parameter names. + */ + public static final String INFERRED_ARGUMENT_NAME = "__INFERRED_ARGUMENT_NAME__"; + private final SyntaxParser syntaxParser = new SyntaxParser(); private final ArgumentExtractor argumentExtractor = new ArgumentExtractor(); @@ -438,7 +443,7 @@ public final class AnnotationParser { for (final ArgumentParameterPair argumentPair : arguments) { final CommandArgument argument = this.buildArgument( method, - this.findSyntaxFragment(tokens, argumentPair.getArgument().value()), + this.findSyntaxFragment(tokens, argumentPair.argumentName()), argumentPair ); commandArguments.put(argument.getName(), argument); @@ -606,13 +611,13 @@ public final class AnnotationParser { if (syntaxFragment == null || syntaxFragment.getArgumentMode() == ArgumentMode.LITERAL) { throw new IllegalArgumentException(String.format( "Invalid command argument '%s' in method '%s': " - + "Missing syntax mapping", argumentPair.getArgument().value(), method.getName())); + + "Missing syntax mapping", argumentPair.argumentName(), method.getName())); } final Argument argument = argumentPair.getArgument(); /* Create the argument builder */ @SuppressWarnings("rawtypes") final CommandArgument.Builder argumentBuilder = CommandArgument.ofType( parameter.getType(), - argument.value() + argumentPair.argumentName() ); /* Set the argument requirement status */ if (syntaxFragment.getArgumentMode() == ArgumentMode.OPTIONAL) { diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/Argument.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/Argument.java index 9c304faf..82efc9e0 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/Argument.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/Argument.java @@ -39,11 +39,17 @@ import java.util.function.BiFunction; public @interface Argument { /** - * Argument name + * The name of the argument that this parameter is bound to. + * This value must be overridden unless you have explicitly enabled + * the preservation of parameter names in your compiler options. + * + * If the parameter names are preserved and the name of the bound + * argument is the same as the parameter name, the default value + * may be used. * * @return Argument name */ - @NonNull String value(); + @NonNull String value() default AnnotationParser.INFERRED_ARGUMENT_NAME; /** * Name of the argument parser diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/ArgumentParameterPair.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/ArgumentParameterPair.java index f7ccea34..32de9cb1 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/ArgumentParameterPair.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/ArgumentParameterPair.java @@ -48,4 +48,12 @@ final class ArgumentParameterPair { return this.argument; } + @NonNull String argumentName() { + if (this.argument.value().equals(AnnotationParser.INFERRED_ARGUMENT_NAME)) { + return this.parameter.getName(); + } else { + return this.argument.value(); + } + } + } diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/MethodCommandExecutionHandler.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/MethodCommandExecutionHandler.java index 07b88564..6014624c 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/MethodCommandExecutionHandler.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/MethodCommandExecutionHandler.java @@ -105,11 +105,19 @@ public class MethodCommandExecutionHandler implements CommandExecutionHandler for (final Parameter parameter : this.parameters) { if (parameter.isAnnotationPresent(Argument.class)) { final Argument argument = parameter.getAnnotation(Argument.class); - final CommandArgument commandArgument = this.context.commandArguments.get(argument.value()); - if (commandArgument.isRequired()) { - arguments.add(commandContext.get(argument.value())); + + final String argumentName; + if (argument.value().equals(AnnotationParser.INFERRED_ARGUMENT_NAME)) { + argumentName = parameter.getName(); } else { - final Object optional = commandContext.getOptional(argument.value()).orElse(null); + argumentName = argument.value(); + } + + final CommandArgument commandArgument = this.context.commandArguments.get(argumentName); + if (commandArgument.isRequired()) { + arguments.add(commandContext.get(argumentName)); + } else { + final Object optional = commandContext.getOptional(argumentName).orElse(null); arguments.add(optional); } } else if (parameter.isAnnotationPresent(Flag.class)) {