semi-auto cleanup
This commit is contained in:
1 parent
cad80f82c6
commit
8f61271606
99 files changed
+11463
-8007
No files matched your search
@@ -105,32 +105,38 @@ public final class AnnotationParser
|
||||
* @see ScarpetFunction
|
||||
* @param clazz The class to parse
|
||||
*/
|
||||
public static void parseFunctionClass(Class<?> clazz)
|
||||
public static void parseFunctionClass(final Class<?> clazz)
|
||||
{
|
||||
// Only try to instantiate or require concrete classes if there are non-static annotated methods
|
||||
Supplier<Object> instanceSupplier = Suppliers.memoize(() -> {
|
||||
final Supplier<Object> instanceSupplier = Suppliers.memoize(() -> {
|
||||
if (Modifier.isAbstract(clazz.getModifiers()))
|
||||
{
|
||||
throw new IllegalArgumentException("Function class must be concrete to support non-static methods! Class: " + clazz.getSimpleName());
|
||||
}
|
||||
try
|
||||
{
|
||||
return clazz.getConstructor().newInstance();
|
||||
}
|
||||
catch (ReflectiveOperationException e)
|
||||
catch (final ReflectiveOperationException e)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Couldn't create instance of given " + clazz + ". This is needed for non-static methods. Make sure default constructor is available", e);
|
||||
}
|
||||
});
|
||||
Method[] methodz = clazz.getDeclaredMethods();
|
||||
for (Method method : methodz)
|
||||
final Method[] methodz = clazz.getDeclaredMethods();
|
||||
for (final Method method : methodz)
|
||||
{
|
||||
if (!method.isAnnotationPresent(ScarpetFunction.class))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getExceptionTypes().length != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Annotated method '" + method.getName() +"', provided in '"+clazz+"' must not declare checked exceptions");
|
||||
}
|
||||
|
||||
ParsedFunction function = new ParsedFunction(method, clazz, instanceSupplier);
|
||||
final ParsedFunction function = new ParsedFunction(method, clazz, instanceSupplier);
|
||||
functionList.add(function);
|
||||
}
|
||||
}
|
||||
@@ -141,10 +147,12 @@ public final class AnnotationParser
|
||||
*
|
||||
* @param expr The expression to add every function to
|
||||
*/
|
||||
public static void apply(Expression expr)
|
||||
public static void apply(final Expression expr)
|
||||
{
|
||||
for (ParsedFunction function : functionList)
|
||||
for (final ParsedFunction function : functionList)
|
||||
{
|
||||
expr.addLazyFunction(function.name, function.scarpetParamCount, function);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ParsedFunction implements TriFunction<Context, Context.Type, List<LazyValue>, LazyValue>, UsageProvider
|
||||
@@ -164,25 +172,27 @@ public final class AnnotationParser
|
||||
private final int scarpetParamCount;
|
||||
private final Context.Type contextType;
|
||||
|
||||
private ParsedFunction(Method method, Class<?> originClass, Supplier<Object> instance)
|
||||
private ParsedFunction(final Method method, final Class<?> originClass, final Supplier<Object> instance)
|
||||
{
|
||||
this.name = method.getName();
|
||||
this.isMethodVarArgs = method.isVarArgs();
|
||||
this.methodParamCount = method.getParameterCount();
|
||||
|
||||
Parameter[] methodParameters = method.getParameters();
|
||||
final Parameter[] methodParameters = method.getParameters();
|
||||
this.valueConverters = new ValueConverter[isMethodVarArgs ? methodParamCount - 1 : methodParamCount];
|
||||
for (int i = 0; i < this.methodParamCount; i++)
|
||||
{
|
||||
Parameter param = methodParameters[i];
|
||||
final Parameter param = methodParameters[i];
|
||||
if (!isMethodVarArgs || i != this.methodParamCount - 1) // Varargs converter is separate
|
||||
{
|
||||
this.valueConverters[i] = ValueConverter.fromAnnotatedType(param.getAnnotatedType());
|
||||
}
|
||||
}
|
||||
Class<?> originalVarArgsType = isMethodVarArgs ? methodParameters[methodParamCount - 1].getType().getComponentType() : null;
|
||||
final Class<?> originalVarArgsType = isMethodVarArgs ? methodParameters[methodParamCount - 1].getType().getComponentType() : null;
|
||||
this.varArgsType = ClassUtils.primitiveToWrapper(originalVarArgsType); // Primitive array cannot be cast to Obj[]
|
||||
this.primitiveVarArgs = originalVarArgsType != null && originalVarArgsType.isPrimitive();
|
||||
this.varArgsConverter = isMethodVarArgs ? ValueConverter.fromAnnotatedType(methodParameters[methodParamCount - 1].getAnnotatedType()) : null;
|
||||
@SuppressWarnings("unchecked") // Yes. Making a T is not worth
|
||||
@SuppressWarnings("unchecked") final // Yes. Making a T is not worth
|
||||
OutputConverter<Object> converter = OutputConverter.get((Class<Object>) method.getReturnType());
|
||||
this.outputConverter = converter;
|
||||
|
||||
@@ -193,13 +203,19 @@ public final class AnnotationParser
|
||||
{
|
||||
maxParams = method.getAnnotation(ScarpetFunction.class).maxParams();
|
||||
if (maxParams == UNDEFINED_PARAMS)
|
||||
{
|
||||
throw new IllegalArgumentException("No maximum number of params specified for " + name + ", use ScarpetFunction.UNLIMITED_PARAMS for unlimited. "
|
||||
+ "Provided in " + originClass);
|
||||
}
|
||||
if (maxParams == ScarpetFunction.UNLIMITED_PARAMS)
|
||||
{
|
||||
maxParams = Integer.MAX_VALUE;
|
||||
}
|
||||
if (maxParams < this.minParams)
|
||||
{
|
||||
throw new IllegalArgumentException("Provided maximum number of params for " + name + " is smaller than method's param count."
|
||||
+ "Provided in " + originClass);
|
||||
}
|
||||
}
|
||||
this.maxParams = maxParams;
|
||||
|
||||
@@ -227,56 +243,66 @@ public final class AnnotationParser
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyValue apply(Context context, Context.Type t, List<LazyValue> lazyValues)
|
||||
public LazyValue apply(final Context context, final Context.Type t, final List<LazyValue> lazyValues)
|
||||
{
|
||||
List<Value> lv = AbstractLazyFunction.unpackLazy(lazyValues, context, contextType);
|
||||
final List<Value> lv = AbstractLazyFunction.unpackLazy(lazyValues, context, contextType);
|
||||
if (isEffectivelyVarArgs)
|
||||
{
|
||||
if (lv.size() < minParams)
|
||||
throw new InternalExpressionException("Function '" + name + "' expected at least " + minParams + " arguments, got " + lv.size() + ". "
|
||||
{
|
||||
throw new InternalExpressionException("Function '" + name + "' expected at least " + minParams + " arguments, got " + lv.size() + ". "
|
||||
+ getUsage());
|
||||
}
|
||||
if (lv.size() > maxParams)
|
||||
throw new InternalExpressionException("Function '" + name + " expected up to " + maxParams + " arguments, got " + lv.size() + ". "
|
||||
{
|
||||
throw new InternalExpressionException("Function '" + name + " expected up to " + maxParams + " arguments, got " + lv.size() + ". "
|
||||
+ getUsage());
|
||||
}
|
||||
}
|
||||
Object[] params = getMethodParams(lv, context, t);
|
||||
final Object[] params = getMethodParams(lv, context, t);
|
||||
try
|
||||
{
|
||||
return outputConverter.convert(handle.invokeExact(params));
|
||||
}
|
||||
catch (Throwable e)
|
||||
catch (final Throwable e)
|
||||
{
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException) e;
|
||||
if (e instanceof RuntimeException re)
|
||||
{
|
||||
throw re;
|
||||
}
|
||||
throw (Error) e; // Stack overflow or something. Methods are guaranteed not to throw checked exceptions
|
||||
}
|
||||
}
|
||||
|
||||
// Hot code: Must be optimized
|
||||
private Object[] getMethodParams(final List<Value> lv, final Context context, Context.Type theLazyT)
|
||||
private Object[] getMethodParams(final List<Value> lv, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
Object[] params = new Object[methodParamCount];
|
||||
ListIterator<Value> lvIterator = lv.listIterator();
|
||||
final Object[] params = new Object[methodParamCount];
|
||||
final ListIterator<Value> lvIterator = lv.listIterator();
|
||||
|
||||
int regularArgs = isMethodVarArgs ? methodParamCount - 1 : methodParamCount;
|
||||
final int regularArgs = isMethodVarArgs ? methodParamCount - 1 : methodParamCount;
|
||||
for (int i = 0; i < regularArgs; i++)
|
||||
{
|
||||
params[i] = valueConverters[i].checkAndConvert(lvIterator, context, theLazyT);
|
||||
if (params[i] == null)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect argument passsed to '" + name + "' function.\n" + getUsage());
|
||||
}
|
||||
}
|
||||
if (isMethodVarArgs)
|
||||
{
|
||||
int remaining = lv.size() - lvIterator.nextIndex();
|
||||
Object[] varArgs;
|
||||
final int remaining = lv.size() - lvIterator.nextIndex();
|
||||
final Object[] varArgs;
|
||||
if (varArgsConverter.consumesVariableArgs())
|
||||
{
|
||||
List<Object> varArgsList = new ArrayList<>(); // fastutil's is extremely slow in toArray, and we use that
|
||||
final List<Object> varArgsList = new ArrayList<>(); // fastutil's is extremely slow in toArray, and we use that
|
||||
while (lvIterator.hasNext())
|
||||
{
|
||||
Object obj = varArgsConverter.checkAndConvert(lvIterator, context, theLazyT);
|
||||
final Object obj = varArgsConverter.checkAndConvert(lvIterator, context, theLazyT);
|
||||
if (obj == null)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect argument passsed to '" + name + "' function.\n" + getUsage());
|
||||
}
|
||||
varArgsList.add(obj);
|
||||
}
|
||||
varArgs = varArgsList.toArray((Object[])Array.newInstance(varArgsType, 0));
|
||||
@@ -287,7 +313,9 @@ public final class AnnotationParser
|
||||
{
|
||||
varArgs[i] = varArgsConverter.checkAndConvert(lvIterator, context, theLazyT);
|
||||
if (varArgs[i] == null)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect argument passsed to '" + name + "' function.\n" + getUsage());
|
||||
}
|
||||
}
|
||||
}
|
||||
params[methodParamCount - 1] = primitiveVarArgs ? ArrayUtils.toPrimitive(varArgs) : varArgs; // Copies the array
|
||||
@@ -299,7 +327,7 @@ public final class AnnotationParser
|
||||
public String getUsage()
|
||||
{
|
||||
// Possibility: More descriptive messages using param.getName()? Would need changing gradle setup to keep those
|
||||
StringBuilder builder = new StringBuilder("Usage: '");
|
||||
final StringBuilder builder = new StringBuilder("Usage: '");
|
||||
builder.append(name);
|
||||
builder.append('(');
|
||||
builder.append(Arrays.stream(valueConverters).map(ValueConverter::getTypeName).filter(Objects::nonNull).collect(Collectors.joining(", ")));
|
||||
|
||||
@@ -32,34 +32,38 @@ final class ListConverter<T> implements ValueConverter<List<T>>
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> convert(Value value)
|
||||
public List<T> convert(final Value value)
|
||||
{
|
||||
return value instanceof ListValue ? convertListValue((ListValue) value) : allowSingletonCreation ? convertSingleton(value) : null;
|
||||
}
|
||||
|
||||
private List<T> convertListValue(ListValue values)
|
||||
private List<T> convertListValue(final ListValue values)
|
||||
{
|
||||
List<T> list = new ArrayList<>(values.getItems().size());
|
||||
for (Value value : values)
|
||||
final List<T> list = new ArrayList<>(values.getItems().size());
|
||||
for (final Value value : values)
|
||||
{
|
||||
T converted = itemConverter.convert(value);
|
||||
final T converted = itemConverter.convert(value);
|
||||
if (converted == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
list.add(converted);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<T> convertSingleton(Value val)
|
||||
private List<T> convertSingleton(final Value val)
|
||||
{
|
||||
T converted = itemConverter.convert(val);
|
||||
final T converted = itemConverter.convert(val);
|
||||
if (converted == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Collections.singletonList(converted);
|
||||
|
||||
}
|
||||
|
||||
private ListConverter(AnnotatedType itemType, boolean allowSingletonCreation)
|
||||
private ListConverter(final AnnotatedType itemType, final boolean allowSingletonCreation)
|
||||
{
|
||||
itemConverter = ValueConverter.fromAnnotatedType(itemType);
|
||||
this.allowSingletonCreation = allowSingletonCreation;
|
||||
@@ -79,11 +83,11 @@ final class ListConverter<T> implements ValueConverter<List<T>>
|
||||
* @param annotatedType The type to get generics information from
|
||||
* @return A new {@link ListConverter} for the data specified in the {@link AnnotatedType}
|
||||
*/
|
||||
static ListConverter<?> fromAnnotatedType(AnnotatedType annotatedType)
|
||||
static ListConverter<?> fromAnnotatedType(final AnnotatedType annotatedType)
|
||||
{
|
||||
AnnotatedParameterizedType paramType = (AnnotatedParameterizedType) annotatedType;
|
||||
AnnotatedType itemType = paramType.getAnnotatedActualTypeArguments()[0];
|
||||
boolean allowSingletonCreation = annotatedType.isAnnotationPresent(Param.AllowSingleton.class);
|
||||
final AnnotatedParameterizedType paramType = (AnnotatedParameterizedType) annotatedType;
|
||||
final AnnotatedType itemType = paramType.getAnnotatedActualTypeArguments()[0];
|
||||
final boolean allowSingletonCreation = annotatedType.isAnnotationPresent(Param.AllowSingleton.class);
|
||||
return new ListConverter<>(itemType, allowSingletonCreation);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public interface Locator
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface Block
|
||||
@interface Block
|
||||
{
|
||||
/**
|
||||
* <p>Whether or not should the locator accept a single {@link String} as the parameter and let parsing to {@link BlockValue}.</p>
|
||||
@@ -66,7 +66,7 @@ public interface Locator
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface Vec3d
|
||||
@interface Vec3d
|
||||
{
|
||||
/**
|
||||
* <p>Whether or not should the {@link Vector3Argument} locator accept an optional direction aside from the
|
||||
@@ -94,7 +94,7 @@ public interface Locator
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface Function
|
||||
@interface Function
|
||||
{
|
||||
/**
|
||||
* <p>Whether this Locator should allow no function to be passed.</p> <p>This is not compatible with {@link FunctionValue} type, since a
|
||||
@@ -115,18 +115,27 @@ public interface Locator
|
||||
*
|
||||
* <p>Not part of the public API, just that interfaces must have all members public</p>
|
||||
*/
|
||||
static final class Locators
|
||||
final class Locators
|
||||
{
|
||||
private Locators() {}
|
||||
private Locators()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
static <R> ValueConverter<R> fromAnnotatedType(AnnotatedType annoType, Class<R> type)
|
||||
static <R> ValueConverter<R> fromAnnotatedType(final AnnotatedType annoType, final Class<R> type)
|
||||
{
|
||||
if (annoType.isAnnotationPresent(Block.class))
|
||||
return new BlockLocator<R>(annoType.getAnnotation(Block.class), type);
|
||||
{
|
||||
return new BlockLocator<>(annoType.getAnnotation(Block.class), type);
|
||||
}
|
||||
if (annoType.isAnnotationPresent(Function.class))
|
||||
return new FunctionLocator<R>(annoType.getAnnotation(Function.class), type);
|
||||
{
|
||||
return new FunctionLocator<>(annoType.getAnnotation(Function.class), type);
|
||||
}
|
||||
if (annoType.isAnnotationPresent(Vec3d.class))
|
||||
return new Vec3dLocator<R>(annoType.getAnnotation(Vec3d.class), type);
|
||||
{
|
||||
return new Vec3dLocator<>(annoType.getAnnotation(Vec3d.class), type);
|
||||
}
|
||||
throw new IllegalStateException("Locator#fromAnnotatedType got called with an incompatible AnnotatedType");
|
||||
}
|
||||
|
||||
@@ -137,28 +146,42 @@ public interface Locator
|
||||
private final boolean anyString;
|
||||
private final boolean optional;
|
||||
|
||||
public BlockLocator(Block annotation, Class<R> type)
|
||||
public BlockLocator(final Block annotation, final Class<R> type)
|
||||
{
|
||||
super();
|
||||
this.acceptString = annotation.acceptString();
|
||||
this.anyString = annotation.anyString();
|
||||
this.optional = annotation.optional();
|
||||
if (type != BlockArgument.class && (anyString || optional))
|
||||
{
|
||||
throw new IllegalArgumentException("Can only use anyString or optional parameters of Locator.Block if targeting a BlockArgument");
|
||||
}
|
||||
this.returnFunction = getReturnFunction(type);
|
||||
if (returnFunction == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Locator.Block can only be used against BlockArgument, BlockValue, BlockPos or BlockState types!");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <R> java.util.function.Function<BlockArgument, R> getReturnFunction(Class<R> type) {
|
||||
private static <R> java.util.function.Function<BlockArgument, R> getReturnFunction(final Class<R> type)
|
||||
{
|
||||
if (type == BlockArgument.class)
|
||||
{
|
||||
return r -> (R) r;
|
||||
}
|
||||
if (type == BlockValue.class)
|
||||
{
|
||||
return r -> (R) r.block;
|
||||
}
|
||||
if (type == BlockPos.class)
|
||||
{
|
||||
return r -> (R) r.block.getPos();
|
||||
}
|
||||
if (type == BlockState.class)
|
||||
{
|
||||
return r -> (R) r.block.getBlockState();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -169,9 +192,9 @@ public interface Locator
|
||||
}
|
||||
|
||||
@Override
|
||||
public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public R checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
BlockArgument locator = BlockArgument.findIn((CarpetContext) context, valueIterator, 0, acceptString, optional, anyString);
|
||||
final BlockArgument locator = BlockArgument.findIn((CarpetContext) context, valueIterator, 0, acceptString, optional, anyString);
|
||||
return returnFunction.apply(locator);
|
||||
}
|
||||
}
|
||||
@@ -182,15 +205,19 @@ public interface Locator
|
||||
private final boolean optionalEntity;
|
||||
private final boolean returnVec3d;
|
||||
|
||||
public Vec3dLocator(Vec3d annotation, Class<R> type)
|
||||
public Vec3dLocator(final Vec3d annotation, final Class<R> type)
|
||||
{
|
||||
this.optionalDirection = annotation.optionalDirection();
|
||||
this.optionalEntity = annotation.optionalEntity();
|
||||
this.returnVec3d = type == net.minecraft.world.phys.Vec3.class; // Because of the locator
|
||||
if (returnVec3d && optionalDirection)
|
||||
{
|
||||
throw new IllegalArgumentException("optionalDirection Locator.Vec3d cannot be used for Vec3d type, use Vector3Argument instead");
|
||||
}
|
||||
if (!returnVec3d && type != Vector3Argument.class)
|
||||
{
|
||||
throw new IllegalArgumentException("Locator.Vec3d can only be used in Vector3Argument or Vec3d types");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -200,11 +227,10 @@ public interface Locator
|
||||
}
|
||||
|
||||
@Override
|
||||
public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public R checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
Vector3Argument locator = Vector3Argument.findIn(valueIterator, 0, optionalDirection, optionalEntity);
|
||||
@SuppressWarnings("unchecked")
|
||||
R ret = (R) (returnVec3d ? locator.vec : locator);
|
||||
final Vector3Argument locator = Vector3Argument.findIn(valueIterator, 0, optionalDirection, optionalEntity);
|
||||
@SuppressWarnings("unchecked") final R ret = (R) (returnVec3d ? locator.vec : locator);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -215,24 +241,28 @@ public interface Locator
|
||||
private final boolean allowNone;
|
||||
private final boolean checkArgs;
|
||||
|
||||
FunctionLocator(Function annotation, Class<R> type)
|
||||
FunctionLocator(final Function annotation, final Class<R> type)
|
||||
{
|
||||
super();
|
||||
this.returnFunctionValue = type == FunctionValue.class;
|
||||
if (!returnFunctionValue && type != FunctionArgument.class)
|
||||
{
|
||||
throw new IllegalArgumentException("Params annotated with Locator.Function must be of either FunctionArgument or FunctionValue type");
|
||||
}
|
||||
this.allowNone = annotation.allowNone();
|
||||
this.checkArgs = annotation.checkArgs();
|
||||
if (returnFunctionValue && allowNone)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot use allowNone of Locator.Function in FunctionValue types, use FunctionArgument");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public R checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
Module module = context.host.main;
|
||||
FunctionArgument locator = FunctionArgument.findIn(context, module, Lists.newArrayList(valueIterator), 0, allowNone, checkArgs);
|
||||
@SuppressWarnings("unchecked")
|
||||
R ret = (R) (returnFunctionValue ? locator.function : locator);
|
||||
final Module module = context.host.main;
|
||||
final FunctionArgument locator = FunctionArgument.findIn(context, module, Lists.newArrayList(valueIterator), 0, allowNone, checkArgs);
|
||||
@SuppressWarnings("unchecked") final R ret = (R) (returnFunctionValue ? locator.function : locator);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -243,10 +273,10 @@ public interface Locator
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class AbstractLocator<R> implements ValueConverter<R>, Locator
|
||||
private abstract static class AbstractLocator<R> implements ValueConverter<R>, Locator
|
||||
{
|
||||
@Override
|
||||
public R convert(Value value)
|
||||
public R convert(final Value value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Cannot call a locator in a parameter that doesn't contain a context!");
|
||||
}
|
||||
|
||||
@@ -37,17 +37,19 @@ class MapConverter<K, V> implements ValueConverter<Map<K, V>>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> convert(Value value)
|
||||
public Map<K, V> convert(final Value value)
|
||||
{
|
||||
Map<K, V> result = new HashMap<>();
|
||||
final Map<K, V> result = new HashMap<>();
|
||||
if (value instanceof MapValue)
|
||||
{
|
||||
for (Entry<Value, Value> entry : ((MapValue) value).getMap().entrySet())
|
||||
for (final Entry<Value, Value> entry : ((MapValue) value).getMap().entrySet())
|
||||
{
|
||||
K key = keyConverter.convert(entry.getKey());
|
||||
V val = valueConverter.convert(entry.getValue());
|
||||
final K key = keyConverter.convert(entry.getKey());
|
||||
final V val = valueConverter.convert(entry.getValue());
|
||||
if (key == null || val == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
result.put(key, val);
|
||||
}
|
||||
return result;
|
||||
@@ -55,8 +57,9 @@ class MapConverter<K, V> implements ValueConverter<Map<K, V>>
|
||||
return null;
|
||||
}
|
||||
|
||||
private MapConverter(AnnotatedType keyType, AnnotatedType valueType)
|
||||
private MapConverter(final AnnotatedType keyType, final AnnotatedType valueType)
|
||||
{
|
||||
super();
|
||||
keyConverter = ValueConverter.fromAnnotatedType(keyType);
|
||||
valueConverter = ValueConverter.fromAnnotatedType(valueType);
|
||||
}
|
||||
@@ -77,9 +80,9 @@ class MapConverter<K, V> implements ValueConverter<Map<K, V>>
|
||||
* @param annotatedType The type to get generics information from
|
||||
* @return A new {@link MapConverter} for the data specified in the {@link AnnotatedType}
|
||||
*/
|
||||
static MapConverter<?, ?> fromAnnotatedType(AnnotatedType annotatedType)
|
||||
static MapConverter<?, ?> fromAnnotatedType(final AnnotatedType annotatedType)
|
||||
{
|
||||
AnnotatedType[] annotatedGenerics = ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
|
||||
final AnnotatedType[] annotatedGenerics = ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
|
||||
return annotatedType.isAnnotationPresent(Param.KeyValuePairs.class)
|
||||
? new PairConverter<>(annotatedGenerics[0], annotatedGenerics[1], annotatedType.getAnnotation(Param.KeyValuePairs.class))
|
||||
: new MapConverter<>(annotatedGenerics[0], annotatedGenerics[1]);
|
||||
@@ -89,7 +92,7 @@ class MapConverter<K, V> implements ValueConverter<Map<K, V>>
|
||||
{
|
||||
private final boolean acceptMultiParam;
|
||||
|
||||
private PairConverter(AnnotatedType keyType, AnnotatedType valueType, Param.KeyValuePairs config)
|
||||
private PairConverter(final AnnotatedType keyType, final AnnotatedType valueType, final Param.KeyValuePairs config)
|
||||
{
|
||||
super(keyType, valueType);
|
||||
acceptMultiParam = config.allowMultiparam();
|
||||
@@ -102,51 +105,63 @@ class MapConverter<K, V> implements ValueConverter<Map<K, V>>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> convert(Value value) {
|
||||
public Map<K, V> convert(final Value value) {
|
||||
return value instanceof MapValue ? super.convert(value)
|
||||
: value instanceof ListValue ? convertList(((ListValue)value).getItems())
|
||||
: null; // Multiparam mode can only be used in evalAndConvert
|
||||
}
|
||||
|
||||
|
||||
private Map<K, V> convertList(List<Value> valueList)
|
||||
private Map<K, V> convertList(final List<Value> valueList)
|
||||
{
|
||||
if (valueList.size() % 2 == 1)
|
||||
{
|
||||
return null;
|
||||
Map<K, V> map = new HashMap<>();
|
||||
Iterator<Value> val = valueList.iterator();
|
||||
}
|
||||
final Map<K, V> map = new HashMap<>();
|
||||
final Iterator<Value> val = valueList.iterator();
|
||||
while (val.hasNext())
|
||||
{
|
||||
K key = keyConverter.convert(val.next());
|
||||
V value = valueConverter.convert(val.next());
|
||||
final K key = keyConverter.convert(val.next());
|
||||
final V value = valueConverter.convert(val.next());
|
||||
if (key == null || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public Map<K, V> checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
if (!valueIterator.hasNext())
|
||||
{
|
||||
return null;
|
||||
Value val = valueIterator.next();
|
||||
}
|
||||
final Value val = valueIterator.next();
|
||||
if (!acceptMultiParam || val instanceof MapValue || (val instanceof ListValue && !(keyConverter instanceof ListConverter)))
|
||||
{
|
||||
return convert(val); // @KeyValuePairs Map<List<Something>, Boolean> will not support list consumption
|
||||
}
|
||||
|
||||
Map<K, V> map = new HashMap<>();
|
||||
final Map<K, V> map = new HashMap<>();
|
||||
K key = keyConverter.convert(val); //First pair is manual since we got it to check for a different conversion mode
|
||||
V value = valueConverter.checkAndConvert(valueIterator, context, theLazyT);
|
||||
if (key == null || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
map.put(key, value);
|
||||
while (valueIterator.hasNext())
|
||||
{
|
||||
key = keyConverter.checkAndConvert(valueIterator, context, theLazyT);
|
||||
value = valueConverter.checkAndConvert(valueIterator, context, theLazyT);
|
||||
if (key == null || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
|
||||
@@ -50,25 +50,33 @@ final class OptionalConverter<R> implements ValueConverter<Optional<R>>
|
||||
* {@link #checkAndConvert(Iterator, Context, Context.Type)} and is only used as a fallback in types that don't support it.
|
||||
*/
|
||||
@Override
|
||||
public Optional<R> convert(Value value)
|
||||
public Optional<R> convert(final Value value)
|
||||
{
|
||||
if (value.isNull())
|
||||
{
|
||||
return Optional.empty();
|
||||
R converted = typeConverter.convert(value);
|
||||
}
|
||||
final R converted = typeConverter.convert(value);
|
||||
if (converted == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Optional.of(converted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<R> checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public Optional<R> checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
if (!valueIterator.hasNext() || valueIterator.next().isNull())
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
((ListIterator<Value>) valueIterator).previous();
|
||||
R converted = typeConverter.checkAndConvert(valueIterator, context, theLazyT);
|
||||
final R converted = typeConverter.checkAndConvert(valueIterator, context, theLazyT);
|
||||
if (converted == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Optional.of(converted);
|
||||
}
|
||||
|
||||
@@ -98,10 +106,10 @@ final class OptionalConverter<R> implements ValueConverter<Optional<R>>
|
||||
* @param annotatedType The type to get generics information from
|
||||
* @return A new {@link OptionalConverter} for the data specified in the {@link AnnotatedType}
|
||||
*/
|
||||
static OptionalConverter<?> fromAnnotatedType(AnnotatedType annotatedType)
|
||||
static OptionalConverter<?> fromAnnotatedType(final AnnotatedType annotatedType)
|
||||
{
|
||||
AnnotatedParameterizedType paramType = (AnnotatedParameterizedType) annotatedType;
|
||||
AnnotatedType wrappedType = paramType.getAnnotatedActualTypeArguments()[0];
|
||||
final AnnotatedParameterizedType paramType = (AnnotatedParameterizedType) annotatedType;
|
||||
final AnnotatedType wrappedType = paramType.getAnnotatedActualTypeArguments()[0];
|
||||
return new OptionalConverter<>(wrappedType);
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public final class OutputConverter<T>
|
||||
|
||||
private final Function<T, LazyValue> converter;
|
||||
|
||||
private OutputConverter(Function<T, LazyValue> converter)
|
||||
private OutputConverter(final Function<T, LazyValue> converter)
|
||||
{
|
||||
this.converter = converter;
|
||||
}
|
||||
@@ -75,7 +75,9 @@ public final class OutputConverter<T>
|
||||
public static <T> OutputConverter<T> get(Class<T> returnType)
|
||||
{
|
||||
if (Value.class.isAssignableFrom(returnType))
|
||||
{
|
||||
return (OutputConverter<T>) VALUE;
|
||||
}
|
||||
returnType = (Class<T>) ClassUtils.primitiveToWrapper(returnType); // wrapper holds same generic as primitive: wrapped
|
||||
return (OutputConverter<T>) Objects.requireNonNull(byResult.get(returnType),
|
||||
"Unregistered output type: " + returnType + ". Register in OutputConverter");
|
||||
@@ -89,7 +91,7 @@ public final class OutputConverter<T>
|
||||
* @param input The value to convert
|
||||
* @return The converted value
|
||||
*/
|
||||
public LazyValue convert(T input)
|
||||
public LazyValue convert(final T input)
|
||||
{
|
||||
return input == null ? LazyValue.NULL : converter.apply(input);
|
||||
}
|
||||
@@ -102,11 +104,13 @@ public final class OutputConverter<T>
|
||||
* @param inputType The class of T
|
||||
* @param converter The function that converts the an instance of T to a {@link LazyValue}
|
||||
*/
|
||||
public static <T> void register(Class<T> inputType, Function<T, LazyValue> converter)
|
||||
public static <T> void register(final Class<T> inputType, final Function<T, LazyValue> converter)
|
||||
{
|
||||
OutputConverter<T> instance = new OutputConverter<T>(converter);
|
||||
final OutputConverter<T> instance = new OutputConverter<>(converter);
|
||||
if (byResult.containsKey(inputType))
|
||||
{
|
||||
throw new IllegalArgumentException(inputType + " already has a registered OutputConverter");
|
||||
}
|
||||
byResult.put(inputType, instance);
|
||||
}
|
||||
|
||||
@@ -119,11 +123,13 @@ public final class OutputConverter<T>
|
||||
* @param inputType The class of T
|
||||
* @param converter The function that converts an instance of T to a {@link Value}
|
||||
*/
|
||||
public static <T> void registerToValue(Class<T> inputType, Function<T, Value> converter)
|
||||
public static <T> void registerToValue(final Class<T> inputType, final Function<T, Value> converter)
|
||||
{
|
||||
OutputConverter<T> instance = new OutputConverter<>(converter.andThen(v -> (c, t) -> v));
|
||||
final OutputConverter<T> instance = new OutputConverter<>(converter.andThen(v -> (c, t) -> v));
|
||||
if (byResult.containsKey(inputType))
|
||||
{
|
||||
throw new IllegalArgumentException(inputType + " already has a registered OutputConverter");
|
||||
}
|
||||
byResult.put(inputType, instance);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public interface Param
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface AllowSingleton
|
||||
@interface AllowSingleton
|
||||
{
|
||||
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public interface Param
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface KeyValuePairs
|
||||
@interface KeyValuePairs
|
||||
{
|
||||
/**
|
||||
* <p>Whether or not this accepts the key-value pairs directly in the function call as myFunction(..., key, value, key2, value2)</p>
|
||||
@@ -91,7 +91,7 @@ public interface Param
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface Custom
|
||||
@interface Custom
|
||||
{
|
||||
|
||||
}
|
||||
@@ -111,7 +111,7 @@ public interface Param
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@Target({ PARAMETER, TYPE_USE })
|
||||
public @interface Strict
|
||||
@interface Strict
|
||||
{
|
||||
/**
|
||||
* <p>Defines whether this parameter can accept types with "shallow strictness", that is, in order to get a {@link Component}, accepting either a
|
||||
@@ -137,7 +137,7 @@ public interface Param
|
||||
* @see #registerCustomConverterFactory(BiFunction)
|
||||
*
|
||||
*/
|
||||
public static final class Params
|
||||
final class Params
|
||||
{
|
||||
/**
|
||||
* <p>A {@link ValueConverter} that outputs the {@link Context} in which the function has been called, and throws {@link UnsupportedOperationException} when trying to convert a {@link Value}
|
||||
@@ -148,13 +148,13 @@ public interface Param
|
||||
@Override public String getTypeName() { return null; }
|
||||
|
||||
@Override
|
||||
public Context convert(Value value)
|
||||
public Context convert(final Value value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Called convert() with Value in Context Provider converter, where only checkAndConvert is supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public Context checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
@@ -175,13 +175,13 @@ public interface Param
|
||||
@Override public String getTypeName() { return null; }
|
||||
|
||||
@Override
|
||||
public Context.Type convert(Value value)
|
||||
public Context.Type convert(final Value value)
|
||||
{
|
||||
throw new UnsupportedOperationException("Called convert() with a Value in TheLazyT Provider, where only checkAndConvert is supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context.Type checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
|
||||
public Context.Type checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type theLazyT)
|
||||
{
|
||||
return theLazyT;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ public interface Param
|
||||
}
|
||||
};
|
||||
|
||||
static record StrictConverterInfo(Class<?> type, boolean shallow) {}
|
||||
record StrictConverterInfo(Class<?> type, boolean shallow) {}
|
||||
private static final Map<StrictConverterInfo, ValueConverter<?>> strictParamsByClassAndShallowness = new HashMap<>();
|
||||
static
|
||||
{ // TODO Specify strictness in name?
|
||||
@@ -214,14 +214,16 @@ public interface Param
|
||||
* @throws IllegalArgumentException If the type doesn't accept the {@link Strict} annotation or if it has been used incorrectly (shallow in
|
||||
* unsupported places)
|
||||
*/
|
||||
static ValueConverter<?> getStrictConverter(AnnotatedType type)
|
||||
static ValueConverter<?> getStrictConverter(final AnnotatedType type)
|
||||
{
|
||||
boolean shallow = type.getAnnotation(Strict.class).shallow();
|
||||
Class<?> clazz = (Class<?>) type.getType();
|
||||
var key = new StrictConverterInfo(clazz, shallow);
|
||||
ValueConverter<?> converter = strictParamsByClassAndShallowness.get(key);
|
||||
final boolean shallow = type.getAnnotation(Strict.class).shallow();
|
||||
final Class<?> clazz = (Class<?>) type.getType();
|
||||
final StrictConverterInfo key = new StrictConverterInfo(clazz, shallow);
|
||||
final ValueConverter<?> converter = strictParamsByClassAndShallowness.get(key);
|
||||
if (converter != null)
|
||||
{
|
||||
return converter;
|
||||
}
|
||||
throw new IllegalArgumentException("Incorrect use of @Param.Strict annotation");
|
||||
}
|
||||
|
||||
@@ -237,11 +239,13 @@ public interface Param
|
||||
* @param shallow {@code true} if you are registering a shallow-strict parameter, {@code false} if a "fully" strict one
|
||||
* @param converter The {@link ValueConverter} for the given type and shallowness.
|
||||
*/
|
||||
public static <T> void registerStrictConverter(Class<T> type, boolean shallow, ValueConverter<T> converter)
|
||||
public static <T> void registerStrictConverter(final Class<T> type, final boolean shallow, final ValueConverter<T> converter)
|
||||
{
|
||||
var key = new StrictConverterInfo(type, shallow);
|
||||
final StrictConverterInfo key = new StrictConverterInfo(type, shallow);
|
||||
if (strictParamsByClassAndShallowness.containsKey(key))
|
||||
{
|
||||
throw new IllegalArgumentException(type + " already has a registered " + (shallow ? "" : "non-") + "shallow StrictConverter");
|
||||
}
|
||||
strictParamsByClassAndShallowness.put(key, converter);
|
||||
}
|
||||
|
||||
@@ -267,19 +271,21 @@ public interface Param
|
||||
* avoid possible collisions with other extensions.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // this makes no sense... But I guess its preferable to enforce typesafety in callers
|
||||
public static <T> void registerCustomConverterFactory(BiFunction<AnnotatedType, Class<T>, ValueConverter<T>> factory)
|
||||
public static <T> void registerCustomConverterFactory(final BiFunction<AnnotatedType, Class<T>, ValueConverter<T>> factory)
|
||||
{
|
||||
customFactories.add((BiFunction<AnnotatedType, Class<?>, ValueConverter<?>>) (Object) factory);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Stored correctly
|
||||
static <R> ValueConverter<R> getCustomConverter(AnnotatedType annoType, Class<R> type)
|
||||
static <R> ValueConverter<R> getCustomConverter(final AnnotatedType annoType, final Class<R> type)
|
||||
{
|
||||
ValueConverter<R> result;
|
||||
for (BiFunction<AnnotatedType, Class<?>, ValueConverter<?>> factory : customFactories)
|
||||
for (final BiFunction<AnnotatedType, Class<?>, ValueConverter<?>> factory : customFactories)
|
||||
{
|
||||
if ((result = (ValueConverter<R>) factory.apply(annoType, type)) != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No custom converter found for Param.Custom annotated param with type " + annoType.getType().getTypeName());
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public @interface ScarpetFunction
|
||||
/**
|
||||
* <p>Used to define that this {@link ScarpetFunction} can accept an unlimited number of parameters</p>
|
||||
*/
|
||||
public static final int UNLIMITED_PARAMS = -1;
|
||||
int UNLIMITED_PARAMS = -1;
|
||||
|
||||
/**
|
||||
* <p>If the function can accept a variable number of parameters, either by declaring its last parameter as a varargs parameter or by having one
|
||||
|
||||
@@ -58,8 +58,9 @@ public final class SimpleTypeConverter<T extends Value, R> implements ValueConve
|
||||
* @param inputType The required type for the input {@link Value}
|
||||
* @param converter The function to convert an instance of inputType into R.
|
||||
*/
|
||||
public SimpleTypeConverter(Class<T> inputType, Function<T, R> converter, String typeName)
|
||||
public SimpleTypeConverter(final Class<T> inputType, final Function<T, R> converter, final String typeName)
|
||||
{
|
||||
super();
|
||||
this.converter = converter;
|
||||
this.valueClass = inputType;
|
||||
this.typeName = typeName;
|
||||
@@ -79,14 +80,14 @@ public final class SimpleTypeConverter<T extends Value, R> implements ValueConve
|
||||
* @return The {@link SimpleTypeConverter} for the specified outputType
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // T always extends Value, R is always the same as map's key, since map is private.
|
||||
static <R> SimpleTypeConverter<Value, R> get(Class<R> outputType)
|
||||
static <R> SimpleTypeConverter<Value, R> get(final Class<R> outputType)
|
||||
{
|
||||
return (SimpleTypeConverter<Value, R>) byResult.get(outputType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // more than checked. not using class.cast because then "method is too big" for inlining, because javac is useless
|
||||
public R convert(Value value) // and adds millions of casts. This one is even removed
|
||||
public R convert(final Value value) // and adds millions of casts. This one is even removed
|
||||
{
|
||||
return valueClass.isInstance(value) ? converter.apply((T)value) : null;
|
||||
}
|
||||
@@ -103,10 +104,10 @@ public final class SimpleTypeConverter<T extends Value, R> implements ValueConve
|
||||
* can also throw an {@link InternalExpressionException} by itself if really necessary.
|
||||
* @param typeName The name of the type, following the conventions of {@link ValueConverter#getTypeName()}
|
||||
*/
|
||||
public static <T extends Value, R> void registerType(Class<T> requiredInputType, Class<R> outputType,
|
||||
Function<T, R> converter, String typeName)
|
||||
public static <T extends Value, R> void registerType(final Class<T> requiredInputType, final Class<R> outputType,
|
||||
final Function<T, R> converter, final String typeName)
|
||||
{
|
||||
SimpleTypeConverter<T, R> type = new SimpleTypeConverter<>(requiredInputType, converter, typeName);
|
||||
final SimpleTypeConverter<T, R> type = new SimpleTypeConverter<>(requiredInputType, converter, typeName);
|
||||
byResult.put(outputType, type);
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,9 @@ public final class ValueCaster<R> implements ValueConverter<R> // R always exten
|
||||
private final Class<R> outputType;
|
||||
private final String typeName;
|
||||
|
||||
private ValueCaster(Class<R> outputType, String typeName)
|
||||
private ValueCaster(final Class<R> outputType, final String typeName)
|
||||
{
|
||||
super();
|
||||
this.outputType = outputType;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
@@ -71,17 +72,19 @@ public final class ValueCaster<R> implements ValueConverter<R> // R always exten
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // Casters are stored with their exact class, for sure since the map is private (&& class has same generic as
|
||||
// caster)
|
||||
public static <R> ValueCaster<R> get(Class<R> outputType)
|
||||
public static <R> ValueCaster<R> get(final Class<R> outputType)
|
||||
{
|
||||
return (ValueCaster<R>) byResult.get(outputType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // more than checked, see SimpleTypeConverter#converter for reasoning
|
||||
public R convert(Value value)
|
||||
public R convert(final Value value)
|
||||
{
|
||||
if (!outputType.isInstance(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (R)value;
|
||||
}
|
||||
|
||||
@@ -94,9 +97,9 @@ public final class ValueCaster<R> implements ValueConverter<R> // R always exten
|
||||
* required<!--, with the form //Outdated concept <code>(function name) requires a (typeName) to be passed as (argName, if
|
||||
* available)</code>-->
|
||||
*/
|
||||
public static <R extends Value> void register(Class<R> valueClass, String typeName)
|
||||
public static <R extends Value> void register(final Class<R> valueClass, final String typeName)
|
||||
{
|
||||
ValueCaster<R> caster = new ValueCaster<R>(valueClass, typeName);
|
||||
final ValueCaster<R> caster = new ValueCaster<>(valueClass, typeName);
|
||||
byResult.putIfAbsent(valueClass, caster);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public interface ValueConverter<R>
|
||||
* @apiNote This method is intended to only be called when an error has occurred and therefore there is a need to print a stacktrace with some
|
||||
* helpful usage instructions.
|
||||
*/
|
||||
public String getTypeName();
|
||||
String getTypeName();
|
||||
|
||||
/**
|
||||
* <p>Converts the given {@link Value} to {@code <R>}, which was defined when being registered.</p>
|
||||
@@ -62,8 +62,7 @@ public interface ValueConverter<R>
|
||||
* <p>Even with the above reasons, {@link ValueConverter} users should try to implement {@link #convert(Value)} whenever possible instead of
|
||||
* {@link #checkAndConvert(Iterator, Context, Context.Type)}, since it allows its usage in generics of lists and maps.</p>
|
||||
*/
|
||||
@Nullable
|
||||
public R convert(Value value);
|
||||
@Nullable R convert(Value value);
|
||||
|
||||
/**
|
||||
* <p>Returns whether this {@link ValueConverter} consumes a variable number of elements from the {@link Iterator} passed to it via
|
||||
@@ -72,7 +71,7 @@ public interface ValueConverter<R>
|
||||
* @implNote The default implementation returns {@code false}
|
||||
* @see #valueConsumption()
|
||||
*/
|
||||
default public boolean consumesVariableArgs()
|
||||
default boolean consumesVariableArgs()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -87,7 +86,7 @@ public interface ValueConverter<R>
|
||||
* @implNote The default implementation returns {@code 1}
|
||||
*
|
||||
*/
|
||||
default public int valueConsumption()
|
||||
default int valueConsumption()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -107,7 +106,7 @@ public interface ValueConverter<R>
|
||||
* @return A usable {@link ValueConverter} to convert from a {@link Value} to {@code <R>}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <R> ValueConverter<R> fromAnnotatedType(AnnotatedType annoType)
|
||||
static <R> ValueConverter<R> fromAnnotatedType(final AnnotatedType annoType)
|
||||
{
|
||||
Class<R> type = annoType.getType() instanceof ParameterizedType ? // We are defining R here.
|
||||
(Class<R>) ((ParameterizedType) annoType.getType()).getRawType() :
|
||||
@@ -118,33 +117,51 @@ public interface ValueConverter<R>
|
||||
// Example: AnnotatedGenericTypeArray (or similar) being (@Paran.KeyValuePairs Map<String, String>... name)
|
||||
// Those will just fail with a ClassCastException.
|
||||
if (type.isArray())
|
||||
{
|
||||
type = (Class<R>) type.getComponentType(); // Varargs
|
||||
}
|
||||
type = (Class<R>) ClassUtils.primitiveToWrapper(type); // It will be boxed anyway, this saves unboxing-boxing
|
||||
if (type == List.class)
|
||||
{
|
||||
return (ValueConverter<R>) ListConverter.fromAnnotatedType(annoType); // Already checked that type is List
|
||||
}
|
||||
if (type == Map.class)
|
||||
{
|
||||
return (ValueConverter<R>) MapConverter.fromAnnotatedType(annoType); // Already checked that type is Map
|
||||
}
|
||||
if (type == Optional.class)
|
||||
{
|
||||
return (ValueConverter<R>) OptionalConverter.fromAnnotatedType(annoType);
|
||||
}
|
||||
if (annoType.getDeclaredAnnotations().length != 0)
|
||||
{
|
||||
if (annoType.isAnnotationPresent(Param.Custom.class))
|
||||
return Param.Params.getCustomConverter(annoType, type); // Throws if incorrect usage
|
||||
{
|
||||
return Params.getCustomConverter(annoType, type); // Throws if incorrect usage
|
||||
}
|
||||
if (annoType.isAnnotationPresent(Param.Strict.class))
|
||||
{
|
||||
return (ValueConverter<R>) Params.getStrictConverter(annoType); // Throws if incorrect usage
|
||||
}
|
||||
if (annoType.getAnnotations()[0].annotationType().getEnclosingClass() == Locator.class)
|
||||
{
|
||||
return Locator.Locators.fromAnnotatedType(annoType, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Class only checks
|
||||
if (Value.class.isAssignableFrom(type))
|
||||
{
|
||||
return Objects.requireNonNull(ValueCaster.get(type), "Value subclass " + type + " is not registered. Register it in ValueCaster to use it");
|
||||
// if (type == LazyValue.class) // No longer supported
|
||||
// return (ValueConverter<R>) Params.LAZY_VALUE_IDENTITY;
|
||||
}
|
||||
if (type == Context.class)
|
||||
{
|
||||
return (ValueConverter<R>) Params.CONTEXT_PROVIDER;
|
||||
}
|
||||
if (type == Context.Type.class)
|
||||
{
|
||||
return (ValueConverter<R>) Params.CONTEXT_TYPE_PROVIDER;
|
||||
}
|
||||
return Objects.requireNonNull(SimpleTypeConverter.get(type), "Type " + type + " is not registered. Register it in SimpleTypeConverter to use it");
|
||||
}
|
||||
|
||||
@@ -168,10 +185,8 @@ public interface ValueConverter<R>
|
||||
* @implNote This method's default implementation runs the {@link #convert(Value)} function in the next {@link Value} ignoring {@link Context} and
|
||||
* {@code theLazyT}.
|
||||
*/
|
||||
default public R checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type contextType)
|
||||
default R checkAndConvert(final Iterator<Value> valueIterator, final Context context, final Context.Type contextType)
|
||||
{
|
||||
if (!valueIterator.hasNext())
|
||||
return null;
|
||||
return convert(valueIterator.next());
|
||||
return !valueIterator.hasNext() ? null : convert(valueIterator.next());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user