From 53e5720f525094c2a1ad8ffa09ef3ffe35e648b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 13 Sep 2020 13:50:47 +0200 Subject: [PATCH] Add parameter registry --- .../commands/CommandManager.java | 13 ++ .../commands/annotations/specifier/Range.java | 53 +++++ .../components/parser/ParserParameter.java | 88 ++++++++ .../components/parser/ParserParameters.java | 108 ++++++++++ .../components/parser/ParserRegistry.java | 92 +++++++++ .../components/parser/StandardParameters.java | 52 +++++ .../parser/StandardParserRegistry.java | 194 ++++++++++++++++++ .../components/standard/BooleanComponent.java | 2 +- .../components/standard/ByteComponent.java | 2 +- .../components/standard/IntegerComponent.java | 22 +- .../commands/ParserRegistryTest.java | 86 ++++++++ 11 files changed, 708 insertions(+), 4 deletions(-) create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/annotations/specifier/Range.java create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameter.java create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameters.java create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserRegistry.java create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParameters.java create mode 100644 cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParserRegistry.java create mode 100644 cloud-core/src/test/java/com/intellectualsites/commands/ParserRegistryTest.java diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/CommandManager.java b/cloud-core/src/main/java/com/intellectualsites/commands/CommandManager.java index ed50d2a5..ba23c61b 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/CommandManager.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/CommandManager.java @@ -26,6 +26,8 @@ package com.intellectualsites.commands; import com.google.common.reflect.TypeToken; import com.intellectualsites.commands.components.CommandSyntaxFormatter; import com.intellectualsites.commands.components.StandardCommandSyntaxFormatter; +import com.intellectualsites.commands.components.parser.ParserRegistry; +import com.intellectualsites.commands.components.parser.StandardParserRegistry; import com.intellectualsites.commands.context.CommandContext; import com.intellectualsites.commands.context.CommandContextFactory; import com.intellectualsites.commands.context.StandardCommandContextFactory; @@ -61,6 +63,7 @@ public abstract class CommandManager commandContextFactory = new StandardCommandContextFactory<>(); private final ServicePipeline servicePipeline = ServicePipeline.builder().build(); + private final ParserRegistry parserRegistry = new StandardParserRegistry<>(); private final CommandExecutionCoordinator commandExecutionCoordinator; private final CommandRegistrationHandler commandRegistrationHandler; @@ -274,4 +277,14 @@ public abstract class CommandManager getParserRegistry() { + return this.parserRegistry; + } + } diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/annotations/specifier/Range.java b/cloud-core/src/main/java/com/intellectualsites/commands/annotations/specifier/Range.java new file mode 100644 index 00000000..fcf72e21 --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/annotations/specifier/Range.java @@ -0,0 +1,53 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.annotations.specifier; + +import javax.annotation.Nonnull; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to specify min and max values of numerical {@link com.intellectualsites.commands.components.parser.ComponentParser parsers} + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface Range { + + /** + * Minimum value accepted by the parser + * + * @return String serialized number + */ + @Nonnull String min() default ""; + + /** + * Maximum value accepted by the parser + * + * @return String serialized number + */ + @Nonnull String max() default ""; + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameter.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameter.java new file mode 100644 index 00000000..1399cb4e --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameter.java @@ -0,0 +1,88 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.parser; + +import com.google.common.reflect.TypeToken; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * Parser parameter used when retrieving parsers from the {@link ParserRegistry} + * + * @param Type required by the parameter + */ +public class ParserParameter { + + private final String key; + private final TypeToken expectedType; + + /** + * Create a new parser parameter + * + * @param key Parameter key + * @param expectedType Type that is expected to be mapped to this parameter + */ + public ParserParameter(@Nonnull final String key, @Nonnull final TypeToken expectedType) { + this.key = key; + this.expectedType = expectedType; + } + + /** + * Get the parameter key + * + * @return Parameter key + */ + @Nonnull public String getKey() { + return this.key; + } + + /** + * Ge the type that is expected to be mapped to this parameter + * + * @return Expected type + */ + @Nonnull public TypeToken getExpectedType() { + return this.expectedType; + } + + @Override + public final boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ParserParameter that = (ParserParameter) o; + return Objects.equals(key, that.key) && + Objects.equals(expectedType, that.expectedType); + } + + @Override + public final int hashCode() { + return Objects.hash(key, expectedType); + } + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameters.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameters.java new file mode 100644 index 00000000..06b8d2fc --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserParameters.java @@ -0,0 +1,108 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.parser; + +import com.google.common.collect.Maps; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Map; + +/** + * Collection of {@link ParserParameter parameter}-{@link Object object} pairs + */ +public final class ParserParameters { + + private final Map, Object> internalMap = Maps.newHashMap(); + + public ParserParameters() { + } + + /** + * Get an empty {@link ParserParameters} instance + * + * @return Empty instance + */ + @Nonnull + public static ParserParameters empty() { + return new ParserParameters(); + } + + /** + * Check if this instance contains a parameter-object pair for a given parameter + * + * @param parameter Parameter + * @param Parameter type + * @return {@code true} if such a pair is stored, else {@code false} + */ + public boolean has(@Nonnull final ParserParameter parameter) { + return this.internalMap.containsKey(parameter); + } + + /** + * Store a parameter-object pair + * + * @param parameter Parameter + * @param value Object + * @param Parameter type + */ + public void store(@Nonnull final ParserParameter parameter, @Nonnull final T value) { + this.internalMap.put(parameter, value); + } + + /** + * Get a value from the parameter map, if it is stored, else return a default value + * + * @param parameter Parameter to retrieve + * @param defaultValue Default value + * @param Parameter type + * @return Parameter value + */ + @Nonnull + @SuppressWarnings("unchecked") + public T get(@Nonnull final ParserParameter parameter, @Nonnull final T defaultValue) { + return (T) this.internalMap.getOrDefault(parameter, defaultValue); + } + + /** + * Attempt to merge two {@link ParserParameters} instances. If the instances contain conflicting + * values, the values of the "other" instance will be preferred + * + * @param other Other instance + */ + public void merge(@Nonnull final ParserParameters other) { + this.internalMap.putAll(other.internalMap); + } + + /** + * Get an immutable view of the internal map + * + * @return Immutable map + */ + @Nonnull + public Map, Object> getAll() { + return Collections.unmodifiableMap(this.internalMap); + } + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserRegistry.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserRegistry.java new file mode 100644 index 00000000..2e761cdf --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/ParserRegistry.java @@ -0,0 +1,92 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.parser; + +import com.google.common.reflect.TypeToken; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Registry of {@link ComponentParser} that allows these components to be + * referenced by a {@link Class} (or really, a {@link com.google.common.reflect.TypeToken}) + * or a {@link String} key + * + * @param Command sender type + */ +public interface ParserRegistry { + + /** + * Register a parser supplier + * + * @param type The type that is parsed by the parser + * @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} + * @param Generic type specifying what is produced by the parser + */ + void registerParserSupplier(@Nonnull final TypeToken type, + @Nonnull final Function> supplier); + + /** + * Register a mapper that maps annotation instances to a map of parameter-object pairs + * + * @param annotation Annotation class + * @param mapper Mapper that maps the pair (annotation, type to be parsed) to a map of + * {@link ParserParameter parameter}-{@link Object object} pairs + * @param Annotation type + * @param Type of the object that the parser is retrieved for + */ + void registerAnnotationMapper(@Nonnull final Class annotation, + @Nonnull final BiFunction, + ParserParameters> mapper); + + /** + * Parse annotations into {@link ParserParameters} + * + * @param parsingType The type that is produced by the parser that is requesting the parsing parameters + * @param annotations The annotations to be parsed + * @return Parsed parameters + */ + @Nonnull + ParserParameters parseAnnotations(@Nonnull final TypeToken parsingType, @Nonnull final Collection annotations); + + /** + * Attempt to create a {@link ComponentParser} for a specified type, using + * an instance of {@link ParserParameter} to configure the parser settings + * + * @param type Type that should be produced by the parser + * @param parserParameters Parser parameters + * @param Generic type + * @return Parser, if one can be created + */ + @Nonnull + Optional> createParser(@Nonnull final TypeToken type, + @Nonnull final ParserParameters parserParameters); + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParameters.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParameters.java new file mode 100644 index 00000000..cf839548 --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParameters.java @@ -0,0 +1,52 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.parser; + +import com.google.common.reflect.TypeToken; + +import javax.annotation.Nonnull; + +/** + * Common parser parameters used when resolving types in the {@link ParserRegistry} + */ +public final class StandardParameters { + + private StandardParameters() { + } + + /** + * Minimum value accepted by a numerical parser + */ + public static final ParserParameter RANGE_MIN = create("min", TypeToken.of(Number.class)); + + /** + * Maximum value accepted by a numerical parser + */ + public static final ParserParameter RANGE_MAX = create("max", TypeToken.of(Number.class)); + + private static ParserParameter create(@Nonnull final String key, @Nonnull final TypeToken expectedType) { + return new ParserParameter<>(key, expectedType); + } + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParserRegistry.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParserRegistry.java new file mode 100644 index 00000000..69f80008 --- /dev/null +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/parser/StandardParserRegistry.java @@ -0,0 +1,194 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands.components.parser; + +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; +import com.intellectualsites.commands.annotations.specifier.Range; +import com.intellectualsites.commands.components.standard.IntegerComponent; +import com.intellectualsites.commands.sender.CommandSender; + +import javax.annotation.Nonnull; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Standard implementation of {@link ParserRegistry} + * + * @param Command sender type + */ +public class StandardParserRegistry implements ParserRegistry { + + private static final Map, Class> primitiveMappings = ImmutableMap., Class>builder() + .put(char.class, Character.class) + .put(int.class, Integer.class) + .put(short.class, Short.class) + .put(byte.class, Byte.class) + .put(float.class, Float.class) + .put(double.class, Double.class) + .put(long.class, Long.class) + .put(boolean.class, Boolean.class) + .build(); + + private final Map, Function>> parserSuppliers = new HashMap<>(); + private final Map, BiFunction, ParserParameters>> + annotationMappers = new HashMap<>(); + + public StandardParserRegistry() { + /* Register standard mappers */ + this.registerAnnotationMapper(Range.class, new RangeMapper<>()); + + /* Register standard types */ + this.registerParserSupplier(TypeToken.of(Integer.class), options -> + new IntegerComponent.IntegerParser((int) options.get(StandardParameters.RANGE_MIN, Integer.MIN_VALUE), + (int) options.get(StandardParameters.RANGE_MAX, Integer.MAX_VALUE))); + } + + @Override + public void registerParserSupplier(@Nonnull final TypeToken type, + @Nonnull final Function> supplier) { + this.parserSuppliers.put(type, supplier); + } + + @Override + public void registerAnnotationMapper(@Nonnull final Class annotation, + @Nonnull final BiFunction, + ParserParameters> mapper) { + this.annotationMappers.put(annotation, mapper); + } + + @Nonnull + @Override + public ParserParameters parseAnnotations(@Nonnull final TypeToken parsingType, + @Nonnull final Collection annotations) { + final ParserParameters parserParameters = new ParserParameters(); + annotations.forEach(annotation -> { + // noinspection all + final BiFunction mapper = this.annotationMappers.get(annotation.annotationType()); + if (mapper == null) { + return; + } + @SuppressWarnings("unchecked") + final ParserParameters parserParametersCasted = (ParserParameters) mapper.apply(annotation, parsingType); + parserParameters.merge(parserParametersCasted); + }); + return parserParameters; + } + + @Nonnull + @Override + public Optional> createParser(@Nonnull final TypeToken type, + @Nonnull final ParserParameters parserParameters) { + final TypeToken actualType; + if (type.isPrimitive()) { + actualType = TypeToken.of(primitiveMappings.get(type.getRawType())); + } else { + actualType = type; + } + final Function> producer = this.parserSuppliers.get(actualType); + if (producer == null) { + return Optional.empty(); + } + @SuppressWarnings("unchecked") + final ComponentParser parser = (ComponentParser) producer.apply(parserParameters); + return Optional.of(parser); + } + + + private static final class RangeMapper implements BiFunction, ParserParameters> { + + @Override + public ParserParameters apply(final Range range, final TypeToken type) { + final Class clazz; + if (type.isPrimitive()) { + clazz = primitiveMappings.get(type.getRawType()); + } else { + clazz = type.getRawType(); + } + if (!Number.class.isAssignableFrom(clazz)) { + return ParserParameters.empty(); + } + Number min = null; + Number max = null; + if (clazz.equals(Byte.class)) { + if (!range.min().isEmpty()) { + min = Byte.parseByte(range.min()); + } + if (!range.max().isEmpty()) { + max = Byte.parseByte(range.max()); + } + } else if (clazz.equals(Short.class)) { + if (!range.min().isEmpty()) { + min = Short.parseShort(range.min()); + } + if (!range.max().isEmpty()) { + max = Short.parseShort(range.max()); + } + } else if (clazz.equals(Integer.class)) { + if (!range.min().isEmpty()) { + min = Integer.parseInt(range.min()); + } + if (!range.max().isEmpty()) { + max = Integer.parseInt(range.max()); + } + } else if (clazz.equals(Long.class)) { + if (!range.min().isEmpty()) { + min = Long.parseLong(range.min()); + } + if (!range.max().isEmpty()) { + max = Long.parseLong(range.max()); + } + } else if (clazz.equals(Float.class)) { + if (!range.min().isEmpty()) { + min = Float.parseFloat(range.min()); + } + if (!range.max().isEmpty()) { + max = Float.parseFloat(range.max()); + } + } else if (clazz.equals(Double.class)) { + if (!range.min().isEmpty()) { + min = Double.parseDouble(range.min()); + } + if (!range.max().isEmpty()) { + max = Double.parseDouble(range.max()); + } + } + final ParserParameters parserParameters = new ParserParameters(); + if (min != null) { + parserParameters.store(StandardParameters.RANGE_MIN, min); + } + if (max != null) { + parserParameters.store(StandardParameters.RANGE_MAX, max); + } + return parserParameters; + } + + } + +} diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/BooleanComponent.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/BooleanComponent.java index 9722d7dd..7fa83807 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/BooleanComponent.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/BooleanComponent.java @@ -138,7 +138,7 @@ public final class BooleanComponent extends CommandComp } - private static final class BooleanParser implements ComponentParser { + public static final class BooleanParser implements ComponentParser { private static final List LIBERAL = Arrays.asList("TRUE", "YES", "ON", "FALSE", "NO", "OFF"); private static final List LIBERAL_TRUE = Arrays.asList("TRUE", "YES", "ON"); diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java index 148b87b7..6afbd514 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/ByteComponent.java @@ -162,7 +162,7 @@ public final class ByteComponent extends CommandCompone } - private static final class ByteParser implements ComponentParser { + public static final class ByteParser implements ComponentParser { private final byte min; private final byte max; diff --git a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java index 9511c1c4..09171d69 100644 --- a/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java +++ b/cloud-core/src/main/java/com/intellectualsites/commands/components/standard/IntegerComponent.java @@ -166,12 +166,12 @@ public final class IntegerComponent extends CommandComp } - private static final class IntegerParser implements ComponentParser { + public static final class IntegerParser implements ComponentParser { private final int min; private final int max; - private IntegerParser(final int min, final int max) { + public IntegerParser(final int min, final int max) { this.min = min; this.max = max; } @@ -197,6 +197,24 @@ public final class IntegerComponent extends CommandComp } } + /** + * Get the minimum value accepted by this parser + * + * @return Min value + */ + public int getMin() { + return this.min; + } + + /** + * Get the maximum value accepted by this parser + * + * @return Max value + */ + public int getMax() { + return this.max; + } + } diff --git a/cloud-core/src/test/java/com/intellectualsites/commands/ParserRegistryTest.java b/cloud-core/src/test/java/com/intellectualsites/commands/ParserRegistryTest.java new file mode 100644 index 00000000..f85cc481 --- /dev/null +++ b/cloud-core/src/test/java/com/intellectualsites/commands/ParserRegistryTest.java @@ -0,0 +1,86 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +package com.intellectualsites.commands; + +import com.google.common.reflect.TypeToken; +import com.intellectualsites.commands.annotations.specifier.Range; +import com.intellectualsites.commands.components.parser.ComponentParser; +import com.intellectualsites.commands.components.parser.ParserParameters; +import com.intellectualsites.commands.components.parser.ParserRegistry; +import com.intellectualsites.commands.components.parser.StandardParameters; +import com.intellectualsites.commands.components.parser.StandardParserRegistry; +import com.intellectualsites.commands.components.standard.IntegerComponent; +import com.intellectualsites.commands.sender.CommandSender; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.lang.annotation.Annotation; +import java.util.Collections; + +public class ParserRegistryTest { + + public static final int RANGE_MIN = 10; + public static final int RANGE_MAX = 100; + + @Test + void testParserRegistry() { + final ParserRegistry parserRegistry = new StandardParserRegistry<>(); + final Range range = new Range() { + + @Override + public Class annotationType() { + return Range.class; + } + + @Nonnull + @Override + public String min() { + return Integer.toString(RANGE_MIN); + } + + @Nonnull + @Override + public String max() { + return Integer.toString(RANGE_MAX); + } + }; + + + final TypeToken parsedType = TypeToken.of(int.class); + final ParserParameters parserParameters = parserRegistry.parseAnnotations(parsedType, Collections.singleton(range)); + Assertions.assertTrue(parserParameters.has(StandardParameters.RANGE_MIN)); + Assertions.assertTrue(parserParameters.has(StandardParameters.RANGE_MAX)); + final ComponentParser parser = parserRegistry.createParser(parsedType, + parserParameters) + .orElseThrow( + () -> new NullPointerException("No parser found")); + Assertions.assertTrue(parser instanceof IntegerComponent.IntegerParser); + @SuppressWarnings("unchecked") + final IntegerComponent.IntegerParser integerParser = (IntegerComponent.IntegerParser) parser; + Assertions.assertEquals(RANGE_MIN, integerParser.getMin()); + Assertions.assertEquals(RANGE_MAX, integerParser.getMax()); + } + +}