diff --git a/cloud-annotations/src/main/java/com/intellectualsites/commands/annotations/AnnotationParser.java b/cloud-annotations/src/main/java/com/intellectualsites/commands/annotations/AnnotationParser.java index baa3d4c0..cf078759 100644 --- a/cloud-annotations/src/main/java/com/intellectualsites/commands/annotations/AnnotationParser.java +++ b/cloud-annotations/src/main/java/com/intellectualsites/commands/annotations/AnnotationParser.java @@ -261,14 +261,28 @@ public final class AnnotationParser { final TypeToken token = TypeToken.of(parameter.getParameterizedType()); final ParserParameters parameters = this.manager.getParserRegistry() .parseAnnotations(token, annotations); - final ArgumentParser parser = this.manager.getParserRegistry() - .createParser(token, parameters) - .orElseThrow(() -> new IllegalArgumentException( - String.format("Parameter '%s' in method '%s' " - + "has parser '%s' but no parser exists " - + "for that type", - parameter.getName(), method.getName(), - token.toString()))); + + final ArgumentParser parser; + if (argumentPair.getArgument().parserName().isEmpty()) { + parser = this.manager.getParserRegistry() + .createParser(token, parameters) + .orElseThrow(() -> new IllegalArgumentException( + String.format("Parameter '%s' in method '%s' " + + "has parser '%s' but no parser exists " + + "for that type", + parameter.getName(), method.getName(), + token.toString()))); + } else { + parser = this.manager.getParserRegistry() + .createParser(argumentPair.getArgument().parserName(), parameters) + .orElseThrow(() -> new IllegalArgumentException( + String.format("Parameter '%s' in method '%s' " + + "has parser '%s' but no parser exists " + + "for that type", + parameter.getName(), method.getName(), + token.toString()))); + } + if (syntaxFragment == null || syntaxFragment.getArgumentMode() == ArgumentMode.LITERAL) { throw new IllegalArgumentException(String.format( "Invalid command argument '%s' in method '%s': " diff --git a/cloud-annotations/src/test/java/com/intellectualsites/commands/annotations/AnnotationParserTest.java b/cloud-annotations/src/test/java/com/intellectualsites/commands/annotations/AnnotationParserTest.java index 1825ffd6..c0f246e6 100644 --- a/cloud-annotations/src/test/java/com/intellectualsites/commands/annotations/AnnotationParserTest.java +++ b/cloud-annotations/src/test/java/com/intellectualsites/commands/annotations/AnnotationParserTest.java @@ -26,6 +26,7 @@ package com.intellectualsites.commands.annotations; import com.intellectualsites.commands.Command; import com.intellectualsites.commands.CommandManager; import com.intellectualsites.commands.annotations.specifier.Range; +import com.intellectualsites.commands.arguments.standard.StringArgument; import com.intellectualsites.commands.meta.SimpleCommandMeta; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -33,6 +34,7 @@ import org.junit.jupiter.api.Test; import javax.annotation.Nonnull; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.CompletionException; class AnnotationParserTest { @@ -44,6 +46,8 @@ class AnnotationParserTest { static void setup() { manager = new TestCommandManager(); annotationParser = new AnnotationParser<>(manager, TestCommandSender.class, p -> SimpleCommandMeta.empty()); + manager.getParserRegistry().registerNamedParserSupplier("potato", p -> new StringArgument.StringParser<>( + StringArgument.StringMode.SINGLE, (c, s) -> Collections.singletonList("potato"))); } @Test @@ -59,7 +63,8 @@ class AnnotationParserTest { @CommandMethod("test|t [string]") public void testCommand(@Nonnull final TestCommandSender sender, @Argument("int") @Range(max = "100") final int argument, - @Nonnull @Argument(value = "string", defaultValue = "potato") final String string) { + @Nonnull @Argument(value = "string", defaultValue = "potato", parserName = "potato") + final String string) { System.out.printf("Received int: %d and string '%s'\n", argument, string); } diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/ParserRegistry.java b/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/ParserRegistry.java index 9e2f6e0f..6ac85997 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/ParserRegistry.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/ParserRegistry.java @@ -52,6 +52,16 @@ public interface ParserRegistry { void registerParserSupplier(@Nonnull TypeToken type, @Nonnull Function> supplier); + /** + * Register a named parser supplier + * + * @param name Parser name + * @param supplier The function that generates the parser. The map supplied my contain parameters used + * to configure the parser, many of which are documented in {@link StandardParameters} + */ + void registerNamedParserSupplier(@Nonnull String name, + @Nonnull Function> supplier); + /** * Register a mapper that maps annotation instances to a map of parameter-object pairs * @@ -88,4 +98,17 @@ public interface ParserRegistry { Optional> createParser(@Nonnull TypeToken type, @Nonnull ParserParameters parserParameters); + /** + * Attempt to create a {@link ArgumentParser} for a specified type, using + * an instance of {@link ParserParameter} to configure the parser settings + * + * @param name Parser + * @param parserParameters Parser parameters + * @param Generic type + * @return Parser, if one can be created + */ + @Nonnull + Optional> createParser(@Nonnull String name, + @Nonnull ParserParameters parserParameters); + } diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/StandardParserRegistry.java b/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/StandardParserRegistry.java index 3140d713..051c52c3 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/StandardParserRegistry.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/arguments/parser/StandardParserRegistry.java @@ -65,6 +65,7 @@ public final class StandardParserRegistry implements ParserRegistry { .put(boolean.class, Boolean.class) .build(); + private final Map>> namedParsers = new HashMap<>(); private final Map, Function>> parserSuppliers = new HashMap<>(); private final Map, BiFunction, ParserParameters>> annotationMappers = new HashMap<>(); @@ -109,6 +110,12 @@ public final class StandardParserRegistry implements ParserRegistry { this.parserSuppliers.put(type, supplier); } + @Override + public void registerNamedParserSupplier(@Nonnull final String name, + @Nonnull final Function> supplier) { + this.namedParsers.put(name, supplier); + } + @Override public void registerAnnotationMapper(@Nonnull final Class annotation, @Nonnull final BiFunction, @@ -160,6 +167,19 @@ public final class StandardParserRegistry implements ParserRegistry { return Optional.of(parser); } + @Nonnull + @Override + public Optional> createParser(@Nonnull final String name, + @Nonnull final ParserParameters parserParameters) { + final Function> producer = this.namedParsers.get(name); + if (producer == null) { + return Optional.empty(); + } + @SuppressWarnings("unchecked") final ArgumentParser parser = (ArgumentParser) producer.apply( + parserParameters); + return Optional.of(parser); + } + private static final class RangeMapper implements BiFunction, ParserParameters> {