Add parameter registry
This commit is contained in:
parent
e01fd6af37
commit
53e5720f52
11 changed files with 708 additions and 4 deletions
|
|
@ -26,6 +26,8 @@ package com.intellectualsites.commands;
|
||||||
import com.google.common.reflect.TypeToken;
|
import com.google.common.reflect.TypeToken;
|
||||||
import com.intellectualsites.commands.components.CommandSyntaxFormatter;
|
import com.intellectualsites.commands.components.CommandSyntaxFormatter;
|
||||||
import com.intellectualsites.commands.components.StandardCommandSyntaxFormatter;
|
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.CommandContext;
|
||||||
import com.intellectualsites.commands.context.CommandContextFactory;
|
import com.intellectualsites.commands.context.CommandContextFactory;
|
||||||
import com.intellectualsites.commands.context.StandardCommandContextFactory;
|
import com.intellectualsites.commands.context.StandardCommandContextFactory;
|
||||||
|
|
@ -61,6 +63,7 @@ public abstract class CommandManager<C extends CommandSender, M extends CommandM
|
||||||
|
|
||||||
private final CommandContextFactory<C> commandContextFactory = new StandardCommandContextFactory<>();
|
private final CommandContextFactory<C> commandContextFactory = new StandardCommandContextFactory<>();
|
||||||
private final ServicePipeline servicePipeline = ServicePipeline.builder().build();
|
private final ServicePipeline servicePipeline = ServicePipeline.builder().build();
|
||||||
|
private final ParserRegistry<C> parserRegistry = new StandardParserRegistry<>();
|
||||||
|
|
||||||
private final CommandExecutionCoordinator<C, M> commandExecutionCoordinator;
|
private final CommandExecutionCoordinator<C, M> commandExecutionCoordinator;
|
||||||
private final CommandRegistrationHandler<M> commandRegistrationHandler;
|
private final CommandRegistrationHandler<M> commandRegistrationHandler;
|
||||||
|
|
@ -274,4 +277,14 @@ public abstract class CommandManager<C extends CommandSender, M extends CommandM
|
||||||
this.commandSuggestionProcessor = commandSuggestionProcessor;
|
this.commandSuggestionProcessor = commandSuggestionProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parser registry instance
|
||||||
|
*
|
||||||
|
* @return Parser registry instance
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public ParserRegistry<C> getParserRegistry() {
|
||||||
|
return this.parserRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <T> Type required by the parameter
|
||||||
|
*/
|
||||||
|
public class ParserParameter<T> {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
private final TypeToken<T> 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<T> 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<T> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<ParserParameter<?>, 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 <T> Parameter type
|
||||||
|
* @return {@code true} if such a pair is stored, else {@code false}
|
||||||
|
*/
|
||||||
|
public <T> boolean has(@Nonnull final ParserParameter<T> parameter) {
|
||||||
|
return this.internalMap.containsKey(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a parameter-object pair
|
||||||
|
*
|
||||||
|
* @param parameter Parameter
|
||||||
|
* @param value Object
|
||||||
|
* @param <T> Parameter type
|
||||||
|
*/
|
||||||
|
public <T> void store(@Nonnull final ParserParameter<T> 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 <T> Parameter type
|
||||||
|
* @return Parameter value
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(@Nonnull final ParserParameter<T> 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<ParserParameter<?>, Object> getAll() {
|
||||||
|
return Collections.unmodifiableMap(this.internalMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <C> Command sender type
|
||||||
|
*/
|
||||||
|
public interface ParserRegistry<C extends CommandSender> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 <T> Generic type specifying what is produced by the parser
|
||||||
|
*/
|
||||||
|
<T> void registerParserSupplier(@Nonnull final TypeToken<T> type,
|
||||||
|
@Nonnull final Function<ParserParameters, ComponentParser<C, ?>> 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 <A> Annotation type
|
||||||
|
* @param <T> Type of the object that the parser is retrieved for
|
||||||
|
*/
|
||||||
|
<A extends Annotation, T> void registerAnnotationMapper(@Nonnull final Class<A> annotation,
|
||||||
|
@Nonnull final BiFunction<A, TypeToken<?>,
|
||||||
|
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<? extends Annotation> 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 <T> Generic type
|
||||||
|
* @return Parser, if one can be created
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
<T> Optional<ComponentParser<C, T>> createParser(@Nonnull final TypeToken<T> type,
|
||||||
|
@Nonnull final ParserParameters parserParameters);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<Number> RANGE_MIN = create("min", TypeToken.of(Number.class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum value accepted by a numerical parser
|
||||||
|
*/
|
||||||
|
public static final ParserParameter<Number> RANGE_MAX = create("max", TypeToken.of(Number.class));
|
||||||
|
|
||||||
|
private static <T> ParserParameter<T> create(@Nonnull final String key, @Nonnull final TypeToken<T> expectedType) {
|
||||||
|
return new ParserParameter<>(key, expectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 <C> Command sender type
|
||||||
|
*/
|
||||||
|
public class StandardParserRegistry<C extends CommandSender> implements ParserRegistry<C> {
|
||||||
|
|
||||||
|
private static final Map<Class<?>, Class<?>> primitiveMappings = ImmutableMap.<Class<?>, 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<TypeToken<?>, Function<ParserParameters, ComponentParser<C, ?>>> parserSuppliers = new HashMap<>();
|
||||||
|
private final Map<Class<? extends Annotation>, BiFunction<? extends Annotation, TypeToken<?>, ParserParameters>>
|
||||||
|
annotationMappers = new HashMap<>();
|
||||||
|
|
||||||
|
public StandardParserRegistry() {
|
||||||
|
/* Register standard mappers */
|
||||||
|
this.<Range, Number>registerAnnotationMapper(Range.class, new RangeMapper<>());
|
||||||
|
|
||||||
|
/* Register standard types */
|
||||||
|
this.registerParserSupplier(TypeToken.of(Integer.class), options ->
|
||||||
|
new IntegerComponent.IntegerParser<C>((int) options.get(StandardParameters.RANGE_MIN, Integer.MIN_VALUE),
|
||||||
|
(int) options.get(StandardParameters.RANGE_MAX, Integer.MAX_VALUE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void registerParserSupplier(@Nonnull final TypeToken<T> type,
|
||||||
|
@Nonnull final Function<ParserParameters, ComponentParser<C, ?>> supplier) {
|
||||||
|
this.parserSuppliers.put(type, supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <A extends Annotation, T> void registerAnnotationMapper(@Nonnull final Class<A> annotation,
|
||||||
|
@Nonnull final BiFunction<A, TypeToken<?>,
|
||||||
|
ParserParameters> mapper) {
|
||||||
|
this.annotationMappers.put(annotation, mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public ParserParameters parseAnnotations(@Nonnull final TypeToken<?> parsingType,
|
||||||
|
@Nonnull final Collection<? extends Annotation> 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 <T> Optional<ComponentParser<C, T>> createParser(@Nonnull final TypeToken<T> type,
|
||||||
|
@Nonnull final ParserParameters parserParameters) {
|
||||||
|
final TypeToken<?> actualType;
|
||||||
|
if (type.isPrimitive()) {
|
||||||
|
actualType = TypeToken.of(primitiveMappings.get(type.getRawType()));
|
||||||
|
} else {
|
||||||
|
actualType = type;
|
||||||
|
}
|
||||||
|
final Function<ParserParameters, ComponentParser<C, ?>> producer = this.parserSuppliers.get(actualType);
|
||||||
|
if (producer == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final ComponentParser<C, T> parser = (ComponentParser<C, T>) producer.apply(parserParameters);
|
||||||
|
return Optional.of(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final class RangeMapper<T> implements BiFunction<Range, TypeToken<?>, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ public final class BooleanComponent<C extends CommandSender> extends CommandComp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final class BooleanParser<C extends CommandSender> implements ComponentParser<C, Boolean> {
|
public static final class BooleanParser<C extends CommandSender> implements ComponentParser<C, Boolean> {
|
||||||
|
|
||||||
private static final List<String> LIBERAL = Arrays.asList("TRUE", "YES", "ON", "FALSE", "NO", "OFF");
|
private static final List<String> LIBERAL = Arrays.asList("TRUE", "YES", "ON", "FALSE", "NO", "OFF");
|
||||||
private static final List<String> LIBERAL_TRUE = Arrays.asList("TRUE", "YES", "ON");
|
private static final List<String> LIBERAL_TRUE = Arrays.asList("TRUE", "YES", "ON");
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ public final class ByteComponent<C extends CommandSender> extends CommandCompone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final class ByteParser<C extends CommandSender> implements ComponentParser<C, Byte> {
|
public static final class ByteParser<C extends CommandSender> implements ComponentParser<C, Byte> {
|
||||||
|
|
||||||
private final byte min;
|
private final byte min;
|
||||||
private final byte max;
|
private final byte max;
|
||||||
|
|
|
||||||
|
|
@ -166,12 +166,12 @@ public final class IntegerComponent<C extends CommandSender> extends CommandComp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final class IntegerParser<C extends CommandSender> implements ComponentParser<C, Integer> {
|
public static final class IntegerParser<C extends CommandSender> implements ComponentParser<C, Integer> {
|
||||||
|
|
||||||
private final int min;
|
private final int min;
|
||||||
private final int max;
|
private final int max;
|
||||||
|
|
||||||
private IntegerParser(final int min, final int max) {
|
public IntegerParser(final int min, final int max) {
|
||||||
this.min = min;
|
this.min = min;
|
||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
@ -197,6 +197,24 @@ public final class IntegerComponent<C extends CommandSender> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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<CommandSender> parserRegistry = new StandardParserRegistry<>();
|
||||||
|
final Range range = new Range() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> 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<CommandSender, ?> parser = parserRegistry.createParser(parsedType,
|
||||||
|
parserParameters)
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new NullPointerException("No parser found"));
|
||||||
|
Assertions.assertTrue(parser instanceof IntegerComponent.IntegerParser);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final IntegerComponent.IntegerParser<CommandSender> integerParser = (IntegerComponent.IntegerParser<CommandSender>) parser;
|
||||||
|
Assertions.assertEquals(RANGE_MIN, integerParser.getMin());
|
||||||
|
Assertions.assertEquals(RANGE_MAX, integerParser.getMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue