From 9e48a41eab99e58ef7b47d9ea6032a197fcfa574 Mon Sep 17 00:00:00 2001 From: Irmo van den Berge Date: Sun, 29 Nov 2020 15:31:04 +0100 Subject: [PATCH] :bug: Annotations API fix Annotations API fix failure when a literal name matches an argument name (#143) --- .../annotations/AnnotationParser.java | 30 +++++++++++++------ .../annotations/SyntaxParser.java | 11 ++++--- 2 files changed, 26 insertions(+), 15 deletions(-) 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 491157e7..ff094f61 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/AnnotationParser.java @@ -55,7 +55,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -261,7 +260,7 @@ public final class AnnotationParser { for (final CommandMethodPair commandMethodPair : methodPairs) { final CommandMethod commandMethod = commandMethodPair.getCommandMethod(); final Method method = commandMethodPair.getMethod(); - final LinkedHashMap tokens = this.syntaxParser.apply(commandMethod.value()); + final List tokens = this.syntaxParser.apply(commandMethod.value()); /* Determine command name */ final String commandToken = commandMethod.value().split(" ")[0].split("\\|")[0]; @SuppressWarnings("rawtypes") final CommandManager manager = this.manager; @@ -274,7 +273,7 @@ public final class AnnotationParser { @SuppressWarnings("rawtypes") Command.Builder builder = manager.commandBuilder( commandToken, - tokens.get(commandToken).getMinor(), + tokens.get(0).getMinor(), metaBuilder.build() ); final Collection arguments = this.argumentExtractor.apply(method); @@ -285,7 +284,7 @@ public final class AnnotationParser { for (final ArgumentParameterPair argumentPair : arguments) { final CommandArgument argument = this.buildArgument( method, - tokens.get(argumentPair.getArgument().value()), + this.findSyntaxFragment(tokens, argumentPair.getArgument().value()), argumentPair ); commandArguments.put(argument.getName(), argument); @@ -293,19 +292,19 @@ public final class AnnotationParser { } boolean commandNameFound = false; /* Build the command tree */ - for (final Map.Entry entry : tokens.entrySet()) { + for (final SyntaxFragment token : tokens) { if (!commandNameFound) { commandNameFound = true; continue; } - if (entry.getValue().getArgumentMode() == ArgumentMode.LITERAL) { - builder = builder.literal(entry.getKey(), entry.getValue().getMinor().toArray(new String[0])); + if (token.getArgumentMode() == ArgumentMode.LITERAL) { + builder = builder.literal(token.getMajor(), token.getMinor().toArray(new String[0])); } else { - final CommandArgument argument = commandArguments.get(entry.getKey()); + final CommandArgument argument = commandArguments.get(token.getMajor()); if (argument == null) { throw new IllegalArgumentException(String.format( "Found no mapping for argument '%s' in method '%s'", - entry.getKey(), method.getName() + token.getMajor(), method.getName() )); } @@ -372,6 +371,19 @@ public final class AnnotationParser { return commands; } + private @NonNull SyntaxFragment findSyntaxFragment( + final @NonNull List<@NonNull SyntaxFragment> fragments, + final @NonNull String argumentName + ) { + for (SyntaxFragment fragment : fragments) { + if (fragment.getArgumentMode() != ArgumentMode.LITERAL + && fragment.getMajor().equals(argumentName)) { + return fragment; + } + } + throw new IllegalArgumentException("Argument is not declared in syntax: " + argumentName); + } + @SuppressWarnings("unchecked") private @NonNull CommandArgument buildArgument( final @NonNull Method method, diff --git a/cloud-annotations/src/main/java/cloud/commandframework/annotations/SyntaxParser.java b/cloud-annotations/src/main/java/cloud/commandframework/annotations/SyntaxParser.java index 4a2fb73d..ab13e34c 100644 --- a/cloud-annotations/src/main/java/cloud/commandframework/annotations/SyntaxParser.java +++ b/cloud-annotations/src/main/java/cloud/commandframework/annotations/SyntaxParser.java @@ -27,7 +27,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashMap; import java.util.List; import java.util.StringTokenizer; import java.util.function.Function; @@ -37,7 +36,7 @@ import java.util.regex.Pattern; /** * Parses command syntax into syntax fragments */ -final class SyntaxParser implements Function<@NonNull String, @NonNull LinkedHashMap<@NonNull String, @NonNull SyntaxFragment>> { +final class SyntaxParser implements Function<@NonNull String, @NonNull List<@NonNull SyntaxFragment>> { private static final Predicate PATTERN_ARGUMENT_LITERAL = Pattern.compile("([A-Za-z0-9]+)(|([A-Za-z0-9]+))*") .asPredicate(); @@ -47,9 +46,9 @@ final class SyntaxParser implements Function<@NonNull String, @NonNull LinkedHas .asPredicate(); @Override - public @NonNull LinkedHashMap<@NonNull String, @NonNull SyntaxFragment> apply(final @NonNull String syntax) { + public @NonNull List<@NonNull SyntaxFragment> apply(final @NonNull String syntax) { final StringTokenizer stringTokenizer = new StringTokenizer(syntax, " "); - final LinkedHashMap map = new LinkedHashMap<>(); + final List syntaxFragments = new ArrayList<>(); while (stringTokenizer.hasMoreTokens()) { final String token = stringTokenizer.nextToken(); String major; @@ -70,9 +69,9 @@ final class SyntaxParser implements Function<@NonNull String, @NonNull LinkedHas } else { throw new IllegalArgumentException(String.format("Unrecognizable syntax token '%s'", syntax)); } - map.put(major, new SyntaxFragment(major, minor, mode)); + syntaxFragments.add(new SyntaxFragment(major, minor, mode)); } - return map; + return syntaxFragments; } }