Skip to content

Commit

Permalink
Merge pull request #4 from networkers-studio/typereference
Browse files Browse the repository at this point in the history
feat: use java Type and drop guava dependency + create MatchingMap
  • Loading branch information
mimbrero authored Jul 4, 2023
2 parents 001be9b + e576121 commit 8ee212e
Show file tree
Hide file tree
Showing 50 changed files with 959 additions and 764 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package st.networkers.rimor.params;

import st.networkers.rimor.params.parse.InstructionParamParser;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Method parameters with this annotation are injected with the corresponding command parameter.
*
* <p>If the index of the command parameter is not manually specified in this annotation, it is automatically
* detected by the position of this parameter relative to all the method's {@code @Param}-annotated parameters.
*
* <p>The injected object will be {@code null} if the index is greater than the command parameter size.
*
* <p>If the type of the method parameter matches the type of the command parameter, it is directly injected. Also,
* the object can be parsed and injected into, for example, a Boolean or Enum parameter, following the registered {@link InstructionParamParser}s.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface InstructionParam {

/**
* The name of the parameter.
*/
String value() default "";

/**
* The description of the parameter.
*/
String description() default "";

/**
* The index of this parameter, or -1 to automatically detect by the method's parameter order.
*/
int index() default -1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import java.lang.annotation.Target;

/**
* Attached to a list of objects (or, if the used framework like bukkit or jline do not parse anything, a list of
* strings) containing the parameters of a command execution. This does not contain the path to the instruction.
* Attached to a {@code List<Object>} containing the parameters of a command execution. This does not contain the
* path to the instruction.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Params {
public @interface InstructionParams {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package st.networkers.rimor.params;

import st.networkers.rimor.extension.AbstractRimorExtension;
import st.networkers.rimor.params.parse.builtin.BooleanParamParser;
import st.networkers.rimor.params.parse.builtin.DefaultParamParser;
import st.networkers.rimor.params.parse.builtin.EnumParamParser;
import st.networkers.rimor.params.parse.builtin.StringParamParser;
import st.networkers.rimor.params.parse.builtin.BooleanInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.DefaultInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.EnumInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.StringInstructionParamParser;

public class ParamsExtension extends AbstractRimorExtension {

@Override
public void configure() {
registerProvider(new BooleanParamParser());
registerProvider(new DefaultParamParser());
registerProvider(new EnumParamParser());
registerProvider(new StringParamParser());
registerProvider(new BooleanInstructionParamParser());
registerProvider(new DefaultInstructionParamParser());
registerProvider(new EnumInstructionParamParser());
registerProvider(new StringInstructionParamParser());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
package st.networkers.rimor.params.parse;

import com.google.common.reflect.TypeToken;
import st.networkers.rimor.context.ExecutionContext;
import st.networkers.rimor.inject.Token;
import st.networkers.rimor.internal.inject.ParameterToken;
import st.networkers.rimor.params.Param;
import st.networkers.rimor.params.Params;
import st.networkers.rimor.params.InstructionParam;
import st.networkers.rimor.params.InstructionParams;
import st.networkers.rimor.params.parse.builtin.StringInstructionParamParser;
import st.networkers.rimor.provide.AbstractRimorProvider;
import st.networkers.rimor.reflect.CachedMethod;
import st.networkers.rimor.reflect.CachedParameter;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
* Abstract useful class for implementing {@link ParamParser}s.
* Abstract useful class for implementing {@link InstructionParamParser}s.
* <p>
* Check {@link st.networkers.rimor.params.parse.builtin.StringParamParser} for a quick example.
* Check {@link StringInstructionParamParser} for a quick example.
*/
public abstract class AbstractParamParser<T> extends AbstractRimorProvider<T> implements ParamParser<T> {
public abstract class AbstractInstructionParamParser<T> extends AbstractRimorProvider<T> implements InstructionParamParser<T> {

protected static final Token<List<Object>> PARAMS_TOKEN = new Token<>(new TypeToken<List<Object>>() {}).annotatedWith(Params.class);
protected static final Token<List<Object>> PARAMS_TOKEN = new Token<List<Object>>() {}.annotatedWith(InstructionParams.class);

@SafeVarargs
protected AbstractParamParser(Class<? extends T>... providedTypes) {
super(providedTypes);
this.annotatedWith(Param.class);
protected AbstractInstructionParamParser(Class<? extends T> providedType, Class<? extends T>... otherTypes) {
super(providedType, otherTypes);
this.annotatedWith(InstructionParam.class);
}

@SafeVarargs
protected AbstractParamParser(TypeToken<? extends T>... providedTypes) {
super(providedTypes);
this.annotatedWith(Param.class);
protected AbstractInstructionParamParser(Type providedType, Type... otherTypes) {
super(providedType, otherTypes);
this.annotatedWith(InstructionParam.class);
}

@Override
public T get(Token<T> token, ExecutionContext context) {
return this.parse(this.getParameter(token, context), token, context);
}

@Override
public Object getParameter(Token<T> token, ExecutionContext context) {
private Object getParameter(Token<T> token, ExecutionContext context) {
int position = this.getPosition(token, context);
List<Object> commandParameters = context.get(PARAMS_TOKEN).orElseGet(ArrayList::new);
List<Object> commandParameters = context.get(PARAMS_TOKEN)
.orElseThrow(() -> new IllegalArgumentException("there is no @InstructionParams annotated List<String> in the execution context!"));

return position >= 0
? position < commandParameters.size() ? commandParameters.get(position) : null
: null;
}

private int getPosition(Token<T> token, ExecutionContext context) {
Param param = token.getAnnotation(Param.class);
InstructionParam param = token.getAnnotation(InstructionParam.class);

// if position is indicated, just return it
if (param.position() > -1)
return param.position();
if (param.index() > -1)
return param.index();

if (token instanceof ParameterToken) {
ParameterToken<T> parameterToken = (ParameterToken<T>) token;
Expand All @@ -65,8 +65,10 @@ private int getPosition(Token<T> token, ExecutionContext context) {
}

private int getPositionFromParameter(CachedMethod method, CachedParameter parameter) {
// TODO cache
List<CachedParameter> parameters = new ArrayList<>(method.getParameters());
parameters.removeIf(p -> !p.isAnnotationPresent(Param.class));
parameters.removeIf(p -> !p.isAnnotationPresent(InstructionParam.class)
|| p.getAnnotation(InstructionParam.class).index() > -1);

return parameters.indexOf(parameter);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package st.networkers.rimor.params.parse;

import st.networkers.rimor.context.ExecutionContext;
import st.networkers.rimor.inject.Token;
import st.networkers.rimor.params.InstructionParams;
import st.networkers.rimor.params.parse.builtin.BooleanInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.DefaultInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.EnumInstructionParamParser;
import st.networkers.rimor.params.parse.builtin.StringInstructionParamParser;
import st.networkers.rimor.provide.RimorProvider;

/**
* Abstract class for providers that just parse an element from the {@link InstructionParams}-annotated lists.
*
* @see AbstractInstructionParamParser
* @see BooleanInstructionParamParser
* @see DefaultInstructionParamParser
* @see EnumInstructionParamParser
* @see StringInstructionParamParser
*/
public interface InstructionParamParser<T> extends RimorProvider<T> {

T parse(Object parameter, Token<T> token, ExecutionContext context);

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
package st.networkers.rimor.params.parse.builtin;

import st.networkers.rimor.Rimor;
import org.apache.commons.lang3.ArrayUtils;
import st.networkers.rimor.context.ExecutionContext;
import st.networkers.rimor.inject.Token;
import st.networkers.rimor.params.parse.AbstractParamParser;
import st.networkers.rimor.provide.RimorProvider;
import st.networkers.rimor.params.parse.AbstractInstructionParamParser;

import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;

/**
* Built-in param parser for boolean types.
* <p>
* Registered by default. Feel free to register it again with {@link Rimor#registerProvider(RimorProvider)}
* instantiating this class with your own aliases to parse as {@code true}, like {@code "yes"}, {@code "on"}...
* <pre>
* rimor.registerProvider(
* new BooleanParamParser("yes", "on")
* );
* </pre>
*/
public class BooleanParamParser extends AbstractParamParser<Boolean> {
public class BooleanInstructionParamParser extends AbstractInstructionParamParser<Boolean> {

private final Collection<String> trueAliases;

public BooleanParamParser(String... trueAliases) {
public BooleanInstructionParamParser(String... trueAliases) {
this(Arrays.asList(trueAliases));
}

public BooleanParamParser(Collection<String> trueAliases) {
public BooleanInstructionParamParser(Collection<String> trueAliases) {
super(boolean.class);
this.trueAliases = trueAliases.stream().map(String::toLowerCase).collect(Collectors.toList());
this.trueAliases = trueAliases.stream().map(String::toLowerCase).collect(Collectors.toSet());
}

@Override
Expand All @@ -41,10 +32,17 @@ public Boolean parse(Object rawParameter, Token<Boolean> token, ExecutionContext
}

if (rawParameter instanceof String) {
String parameter = (String) rawParameter;
return Boolean.parseBoolean(parameter) || this.trueAliases.contains(parameter.toLowerCase());
return this.parse((String) rawParameter, token);
}

throw new IllegalArgumentException(rawParameter + " is neither a Boolean or String type");
}

private boolean parse(String parameter, Token<Boolean> token) {
if (Boolean.parseBoolean(parameter) || this.trueAliases.contains(parameter.toLowerCase()))
return true;

TrueValues trueValues = token.getAnnotation(TrueValues.class);
return trueValues != null && ArrayUtils.contains(trueValues.value(), parameter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package st.networkers.rimor.params.parse.builtin;

import st.networkers.rimor.context.ExecutionContext;
import st.networkers.rimor.inject.Token;
import st.networkers.rimor.params.parse.AbstractInstructionParamParser;

/**
* Built-in basic param parser.
*/
public class DefaultInstructionParamParser extends AbstractInstructionParamParser<Object> {

public DefaultInstructionParamParser() {
super(Object.class);
}

@Override
public Object parse(Object parameter, Token<Object> token, ExecutionContext context) {
return parameter;
}
}

This file was deleted.

Loading

0 comments on commit 8ee212e

Please sign in to comment.