Improve error messages

This commit is contained in:
2025-11-24 10:00:45 +01:00
parent e9d814bc95
commit 3d6c50938c
31 changed files with 336 additions and 203 deletions
@@ -0,0 +1,43 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.Getter;
import javax.lang.model.element.AnnotationMirror;
import java.lang.annotation.Annotation;
public class HandlerForAnnotationMirror<A extends Annotation> implements Handler.AnnotationWrapper<A> {
private A annotation;
@Getter
private AnnotationMirror annotationMirror;
public HandlerForAnnotationMirror(A annotation, AnnotationMirror annotationMirror) {
this.annotation = annotation;
this.annotationMirror = annotationMirror;
}
@Override
public A getAnnotation() {
return annotation;
}
}
@@ -19,6 +19,8 @@
package de.steamwar.command;
import lombok.Getter;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
@@ -27,6 +29,7 @@ import java.util.List;
public class HandlerForExecutableElement implements Handler.MethodWrapper {
@Getter
private final ExecutableElement method;
private final Types types;
private final Elements elements;
@@ -19,6 +19,9 @@
package de.steamwar.command;
import de.steamwar.command.utils.Pair;
import lombok.Getter;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
@@ -26,12 +29,15 @@ import javax.lang.model.util.Types;
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class HandlerForVariableElement implements Handler.ParameterWrapper {
@Getter
private final VariableElement parameter;
private final Types types;
private final Elements elements;
@@ -60,8 +66,14 @@ public class HandlerForVariableElement implements Handler.ParameterWrapper {
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
return parameter.getAnnotation(annotation);
public <A extends Annotation> Handler.AnnotationWrapper<A> getAnnotation(Class<A> annotation) {
A ann = parameter.getAnnotation(annotation);
AnnotationMirror annMirror = parameter.getAnnotationMirrors()
.stream()
.filter(am -> new HandlerForTypeMirror(am.getAnnotationType(), types, elements).is(annotation))
.findFirst()
.orElse(null);
return new HandlerForAnnotationMirror<>(ann, annMirror);
}
@Override
@@ -70,44 +82,53 @@ public class HandlerForVariableElement implements Handler.ParameterWrapper {
}
@Override
public List<Annotation> getAnnotations() {
List<Annotation> annotations = new ArrayList<>();
for (AnnotationMirror annotationMirror : parameter.getAnnotationMirrors()) {
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
if (clazz == null) continue;
annotations.add(parameter.getAnnotation((Class<? extends Annotation>) clazz));
}
List<Annotation> annotationList = new ArrayList<>();
for (Annotation annotation : annotations) {
try {
Method method = annotation.annotationType().getMethod("value");
Class<?> returnType = method.getReturnType();
if (!returnType.isArray()) {
annotationList.add(annotation);
continue;
}
Class<?> innerReturnType = returnType.getComponentType();
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
annotationList.add(annotation);
continue;
}
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
Class<? extends Annotation> containerType = repeatable.value();
if (containerType == returnType) {
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
}
try {
Annotation[] innerAnnotations = (Annotation[]) method.invoke(annotation);
Collections.addAll(annotationList, innerAnnotations);
} catch (Exception e) {
annotationList.add(annotation);
}
} catch (NoSuchMethodException e) {
annotationList.add(annotation);
}
}
annotationList.removeIf(annotation -> !annotation.annotationType().isAnnotationPresent(Handler.Implementation.class));
return annotationList;
public List<Handler.AnnotationWrapper<?>> getAnnotations() {
return parameter.getAnnotationMirrors()
.stream()
.collect(Collectors.toMap(Function.identity(), annotationMirror -> {
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
if (clazz == null) return null;
return parameter.getAnnotation((Class<? extends Annotation>) clazz);
}))
.entrySet()
.stream()
.filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
Annotation annotation = entry.getValue();
try {
Method method = annotation.annotationType().getMethod("value");
Class<?> returnType = method.getReturnType();
if (!returnType.isArray()) {
return List.of(annotation);
}
Class<?> innerReturnType = returnType.getComponentType();
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
return List.of(annotation);
}
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
Class<? extends Annotation> containerType = repeatable.value();
if (containerType == returnType) {
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
}
try {
return Arrays.asList((Annotation[]) method.invoke(annotation));
} catch (Exception e) {
return List.of(annotation);
}
} catch (NoSuchMethodException e) {
return List.of(annotation);
}
}))
.entrySet()
.stream()
.flatMap(entry -> {
return entry.getValue()
.stream()
.map(annotation -> new Pair<AnnotationMirror, Annotation>(entry.getKey(), annotation));
})
.filter(pair -> pair.b.annotationType().isAnnotationPresent(Handler.Implementation.class))
.map(pair -> new HandlerForAnnotationMirror<>(pair.b, pair.a))
.collect(Collectors.toList());
}
private Class<?> getClass(String name) {
@@ -20,22 +20,22 @@
package de.steamwar.command.annotationprocessor;
import de.steamwar.command.Handler;
import de.steamwar.command.HandlerForAnnotationMirror;
import de.steamwar.command.HandlerForExecutableElement;
import de.steamwar.command.HandlerForVariableElement;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -102,9 +102,30 @@ public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
}
Handler.HandlerMethod handlerMethod = (Handler.HandlerMethod) handler;
try {
handlerMethod.check(annotation, new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE);
handlerMethod.check(new HandlerForAnnotationMirror(annotation, null), new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE);
} catch (Handler.HandlerException e) {
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), method);
Handler.CodePlace codePlace = e.getCodePlace();
AnnotationMirror[] annotationMirrors = new AnnotationMirror[0];
if (codePlace.getAnnotations().length > 0) {
annotationMirrors = Arrays.stream(codePlace.getAnnotations())
.map(annotationWrapper -> (HandlerForAnnotationMirror) annotationWrapper)
.map(HandlerForAnnotationMirror::getAnnotationMirror)
.toArray(AnnotationMirror[]::new);
}
Element element = null;
if (codePlace.getMethod() != null) {
element = ((HandlerForExecutableElement) codePlace.getMethod()).getMethod();
} else if (codePlace.getParameter() != null) {
element = ((HandlerForVariableElement) codePlace.getParameter()).getParameter();
}
if (annotationMirrors.length > 0) {
for (int i = 0; i < annotationMirrors.length; i++) {
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element, annotationMirrors[i]);
}
} else {
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element);
}
}
}
@@ -185,7 +185,7 @@ public abstract class AbstractCommand<T> {
handlerMap.get(runPriority).forEach((dataMethodAnnotationTriple, handlerMethods) -> {
handlerMethods.forEach(annotationHandlerMethod -> {
try {
annotationHandlerMethod.check(dataMethodAnnotationTriple.c, new Handler.MethodWrapper.ForMethod(dataMethodAnnotationTriple.b), dataMethodAnnotationTriple.a);
annotationHandlerMethod.check(new Handler.AnnotationWrapper.ForAnnotation<>(dataMethodAnnotationTriple.c), new Handler.MethodWrapper.ForMethod(dataMethodAnnotationTriple.b), dataMethodAnnotationTriple.a);
} catch (Exception e) {
throw new UnsupportedOperationException("Method check failed for " + dataMethodAnnotationTriple.b.getName(), e);
}
@@ -30,6 +30,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
public interface Handler {
@@ -63,8 +64,12 @@ public interface Handler {
}
class HandlerException extends Exception {
public HandlerException(String message) {
@Getter
private final CodePlace codePlace;
public HandlerException(String message, CodePlace codePlace) {
super(message);
this.codePlace = codePlace;
}
}
@@ -106,7 +111,7 @@ public interface Handler {
}
interface HandlerMethod<T extends Annotation> extends Handler {
void check(T annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException;
void check(AnnotationWrapper<T> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException;
int getRunPriority();
@@ -114,7 +119,7 @@ public interface Handler {
}
interface HandlerParameter<T extends Annotation, A, B> extends Handler {
void check(T annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException;
void check(AnnotationWrapper<T> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException;
default boolean needsParentTypeMapper() {
return false;
@@ -139,6 +144,26 @@ public interface Handler {
}
}
@Getter
class CodePlace {
private final MethodWrapper method;
private final ParameterWrapper parameter;
private final AnnotationWrapper<?>[] annotations;
public CodePlace(MethodWrapper method, AnnotationWrapper<?>... annotations) {
this.method = method;
this.parameter = null;
this.annotations = annotations;
}
public CodePlace(ParameterWrapper parameter, AnnotationWrapper<?>... annotations) {
this.method = null;
this.parameter = parameter;
this.annotations = annotations;
}
}
interface MethodWrapper {
String getName();
@@ -186,11 +211,11 @@ public interface Handler {
boolean isAnnotationPresent(Class<? extends Annotation> annotation);
<A extends Annotation> A getAnnotation(Class<A> annotation);
<A extends Annotation> AnnotationWrapper<A> getAnnotation(Class<A> annotation);
String getName();
List<Annotation> getAnnotations();
List<AnnotationWrapper<?>> getAnnotations();
class ForParameter implements ParameterWrapper {
@@ -217,8 +242,8 @@ public interface Handler {
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
return parameter.getAnnotation(annotation);
public <A extends Annotation> AnnotationWrapper<A> getAnnotation(Class<A> annotation) {
return new AnnotationWrapper.ForAnnotation<>(parameter.getAnnotation(annotation));
}
@Override
@@ -227,8 +252,11 @@ public interface Handler {
}
@Override
public List<Annotation> getAnnotations() {
return CommandUtils.getAnnotations(parameter);
public List<AnnotationWrapper<?>> getAnnotations() {
return CommandUtils.getAnnotations(parameter)
.stream()
.map(AnnotationWrapper.ForAnnotation::new)
.collect(Collectors.toList());
}
}
}
@@ -320,4 +348,23 @@ public interface Handler {
}
}
}
interface AnnotationWrapper<A extends Annotation> {
A getAnnotation();
class ForAnnotation<A extends Annotation> implements AnnotationWrapper<A> {
private A annotation;
public ForAnnotation(A annotation) {
this.annotation = annotation;
}
@Override
public A getAnnotation() {
return this.annotation;
}
}
}
}
@@ -36,12 +36,12 @@ public final class AllowNullHandler {
public static final class Impl implements Handler.HandlerParameter<AllowNull, Object, Object> {
@Override
public void check(AllowNull annotation, MethodWrapper method, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<AllowNull> annotation, MethodWrapper method, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("AllowNull annotation cannot be used on the first parameter");
throw new HandlerException("AllowNull annotation cannot be used on the first parameter", new CodePlace(parameter, annotation));
}
if (parameter.getType().isPrimitive()) {
throw new HandlerException("AllowNull annotation cannot be used on primitive types");
throw new HandlerException("AllowNull annotation cannot be used on primitive types", new CodePlace(parameter));
}
}
}
@@ -47,15 +47,15 @@ public final class ArrayLengthHandler {
public static final class Impl implements Handler.HandlerParameter<ArrayLength, Object, Object> {
@Override
public void check(ArrayLength arrayLength, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<ArrayLength> arrayLength, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("ArrayLength annotation cannot be used on first parameter");
throw new HandlerException("ArrayLength annotation cannot be used on first parameter", new CodePlace(parameter, arrayLength));
}
if (!parameter.getType().isArray()) {
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not an array");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not an array", new CodePlace(parameter));
}
if (arrayLength.min() > arrayLength.max()) {
throw new HandlerException("Min ArrayLength cannot be smaller than Max ArrayLength");
if (arrayLength.getAnnotation().min() > arrayLength.getAnnotation().max()) {
throw new HandlerException("Min ArrayLength cannot be smaller than Max ArrayLength", new CodePlace(parameter, arrayLength));
}
}
}
@@ -31,12 +31,12 @@ public final class CachedHandler {
public static final class Impl implements Handler.HandlerMethod<Cached> {
@Override
public void check(Cached annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Cached> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("Cached method must have no parameters");
throw new HandlerException("Cached method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) {
throw new HandlerException("Cached method must return AbstractTypeMapper");
throw new HandlerException("Cached method must return AbstractTypeMapper", new CodePlace(method));
}
}
@@ -31,12 +31,12 @@ public final class ClassMapperHandler {
public static final class Impl implements Handler.HandlerMethod<ClassMapper> {
@Override
public void check(ClassMapper annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<ClassMapper> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("ClassMapper method must have no parameters");
throw new HandlerException("ClassMapper method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) {
throw new HandlerException("ClassMapper method must return AbstractTypeMapper");
throw new HandlerException("ClassMapper method must return AbstractTypeMapper", new CodePlace(method));
}
}
@@ -31,12 +31,12 @@ public final class ClassValidatorHandler {
public static final class Impl implements Handler.HandlerMethod<ClassValidator> {
@Override
public void check(ClassValidator annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<ClassValidator> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("ClassValidator method must have no parameters");
throw new HandlerException("ClassValidator method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeValidator.class)) {
throw new HandlerException("ClassValidator method must return AbstractValidator");
throw new HandlerException("ClassValidator method must return AbstractValidator", new CodePlace(method));
}
}
@@ -35,12 +35,12 @@ public final class EndsWithHandler {
public static final class Impl implements Handler.HandlerParameter<EndsWith, Object, String> {
@Override
public void check(EndsWith annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<EndsWith> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("EndsWith annotation cannot be used on first parameter");
throw new HandlerException("EndsWith annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
if (!parameter.getType().is(String.class)) {
throw new HandlerException("EndsWith annotation cannot be used on String parameter");
throw new HandlerException("EndsWith annotation cannot be used on String parameter", new CodePlace(parameter));
}
}
@@ -31,12 +31,12 @@ public final class ErrorMessageHandler {
public static final class Impl implements Handler.HandlerParameter<ErrorMessage, Object, Object> {
@Override
public void check(ErrorMessage errorMessage, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<ErrorMessage> errorMessage, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("ErrorMessage annotation cannot be used on first parameter");
throw new HandlerException("ErrorMessage annotation cannot be used on first parameter", new CodePlace(parameter, errorMessage));
}
if (!errorMessage.allowEAs() && !(parameter.isVarArgs() || parameter.getType().isArray())) {
throw new HandlerException("ErrorMessage allowESs cannot be used on non array or varargs parameter");
if (!errorMessage.getAnnotation().allowEAs() && !(parameter.isVarArgs() || parameter.getType().isArray())) {
throw new HandlerException("ErrorMessage allowESs cannot be used on non array or varargs parameter", new CodePlace(parameter));
}
}
@@ -44,9 +44,9 @@ public final class GreedyHandler {
public static final class Impl implements Handler.HandlerParameter<Greedy, Object, Object> {
@Override
public void check(Greedy annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Greedy> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (!parameter.getType().isArray() || parameter.isVarArgs()) {
throw new HandlerException("Greedy annotation cannot be used on non array parameters");
throw new HandlerException("Greedy annotation cannot be used on non array parameters", new CodePlace(parameter));
}
}
}
@@ -35,9 +35,9 @@ public final class LengthHandler {
public static final class Impl implements Handler.HandlerParameter<Length, Object, Object> {
@Override
public void check(Length annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Length> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Length annotation cannot be used on first parameter");
throw new HandlerException("Length annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
}
@@ -32,28 +32,28 @@ public final class MapperHandler {
public static final class Impl implements Handler.HandlerMethod<Mapper>, Handler.HandlerParameter<Mapper, Object, Object> {
@Override
public void check(Mapper annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Mapper> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("Mapper method must have no parameters");
throw new HandlerException("Mapper method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) {
throw new HandlerException("Mapper method must return AbstractTypeMapper");
throw new HandlerException("Mapper method must return AbstractTypeMapper", new CodePlace(method));
}
if (annotation.value() != null && !annotation.value().isEmpty()) {
if (annotation.getAnnotation().value() != null && !annotation.getAnnotation().value().isEmpty()) {
return;
}
// TODO: Implement! for AnnotationProcessor as well!
if (method instanceof MethodWrapper.ForMethod) {
Optional<Class<?>> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod());
if (annotation.type() == void.class) {
if (annotation.getAnnotation().type() == void.class) {
if (genericType.isEmpty()) {
throw new HandlerException("Please supply a class type to the Mapper");
throw new HandlerException("Please supply a class type to the Mapper", new CodePlace(method));
}
} else {
if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) {
throw new HandlerException("Supplied type does not conform to actual type");
if (genericType.isPresent() && !annotation.getAnnotation().type().isAssignableFrom(genericType.get())) {
throw new HandlerException("Supplied type does not conform to actual type", new CodePlace(method));
}
}
}
@@ -77,12 +77,12 @@ public final class MapperHandler {
}
@Override
public void check(Mapper annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Mapper> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Mapper annotation cannot be used on first parameter");
throw new HandlerException("Mapper annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
if (!dataCheckable.hasMapper(annotation.value())) {
throw new HandlerException("Mapper '" + annotation.value() + "' not found");
if (!dataCheckable.hasMapper(annotation.getAnnotation().value())) {
throw new HandlerException("Mapper '" + annotation.getAnnotation().value() + "' not found", new CodePlace(parameter));
}
}
@@ -34,41 +34,41 @@ public final class MaxHandler {
public static final class Impl implements Handler.HandlerParameter<Max, Object, Number> {
@Override
public void check(Max max, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Max> max, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Max annotation cannot be used on first parameter");
throw new HandlerException("Max annotation cannot be used on first parameter", new CodePlace(parameter, max));
}
TypeWrapper type = parameter.getType();
if (parameter.isVarArgs()) type = type.getComponentType();
if (!type.is(int.class) && !type.is(Integer.class) && !type.is(long.class) && !type.is(Long.class) && !type.is(float.class) && !type.is(Float.class) && !type.is(double.class) && !type.is(Double.class)) {
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.", new CodePlace(parameter));
}
if (!parameter.isAnnotationPresent(Min.class)) {
return;
}
Min min = parameter.getAnnotation(Min.class);
AnnotationWrapper<Min> min = parameter.getAnnotation(Min.class);
Number minValue;
if (type.is(int.class) || type.is(Integer.class)) {
minValue = min.intValue();
minValue = min.getAnnotation().intValue();
} else if (type.is(long.class) || type.is(Long.class)) {
minValue = min.longValue();
minValue = min.getAnnotation().longValue();
} else if (type.is(float.class) || type.is(Float.class)) {
minValue = min.floatValue();
minValue = min.getAnnotation().floatValue();
} else if (type.is(double.class) || type.is(Double.class)) {
minValue = min.doubleValue();
minValue = min.getAnnotation().doubleValue();
} else {
throw new SecurityException();
}
ToIntFunction<Number> maxComparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue());
if (!(min.inclusive() && max.inclusive()) && maxComparator.applyAsInt(minValue) == 0) {
throw new HandlerException("Min and Max cannot be equal if not both are inclusive");
ToIntFunction<Number> maxComparator = CommandUtils.createComparator("Max", type, max.getAnnotation().intValue(), max.getAnnotation().longValue(), max.getAnnotation().floatValue(), max.getAnnotation().doubleValue());
if (!(min.getAnnotation().inclusive() && max.getAnnotation().inclusive()) && maxComparator.applyAsInt(minValue) == 0) {
throw new HandlerException("Min and Max cannot be equal if not both are inclusive", new CodePlace(parameter, max, min));
} else if (maxComparator.applyAsInt(minValue) > 0) {
throw new HandlerException("Max must be bigger then Min");
throw new HandlerException("Max must be bigger then Min", new CodePlace(parameter, max, min));
}
}
@@ -36,38 +36,38 @@ public final class MaxReferenceHandler {
public static final class Impl implements Handler.HandlerParameter<Max.Reference, Object, Number> {
@Override
public void check(Max.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Max.Reference> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Max.Reference annotation cannot be used on first parameter");
throw new HandlerException("Max.Reference annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (type.isArray()) type = type.getComponentType();
if (!type.is(int.class) && !type.is(Integer.class) && !type.is(long.class) && !type.is(Long.class) && !type.is(float.class) && !type.is(Float.class) && !type.is(double.class) && !type.is(Double.class)) {
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.", new CodePlace(parameter));
}
ParameterWrapper[] parameters = methodWrapper.getParameters();
for (int i = index - 1; i >= 1; i--) {
ParameterWrapper toCheck = parameters[i];
Name name = toCheck.getAnnotation(Name.class);
AnnotationWrapper<Name> name = toCheck.getAnnotation(Name.class);
String parameterName;
if (name == null) {
if (name.getAnnotation() == null) {
parameterName = toCheck.getName();
} else {
parameterName = name.value();
parameterName = name.getAnnotation().value();
}
if (!parameterName.equals(annotation.value())) {
if (!parameterName.equals(annotation.getAnnotation().value())) {
continue;
}
TypeWrapper parameterType = toCheck.getType();
if (!parameterType.isAssignableTo(type)) {
throw new HandlerException("Parameter type being referenced cannot be assigned here!");
throw new HandlerException("Parameter type being referenced cannot be assigned here!", new CodePlace(toCheck, name));
} else {
return;
}
}
throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist.");
throw new HandlerException("Parameter with name '" + annotation.getAnnotation().value() + "' does not exist.", new CodePlace(parameter, annotation));
}
@Override
@@ -33,9 +33,9 @@ public final class MinHandler {
public static final class Impl implements Handler.HandlerParameter<Min, Object, Number> {
@Override
public void check(Min annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Min> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Min annotation cannot be used on first parameter");
throw new HandlerException("Min annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (parameter.isVarArgs()) type = type.getComponentType();
@@ -43,7 +43,7 @@ public final class MinHandler {
if (type.is(long.class) || type.is(Long.class)) return;
if (type.is(float.class) || type.is(Float.class)) return;
if (type.is(double.class) || type.is(Double.class)) return;
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.", new CodePlace(parameter));
}
@Override
@@ -36,38 +36,38 @@ public final class MinReferenceHandler {
public static final class Impl implements Handler.HandlerParameter<Min.Reference, Object, Number> {
@Override
public void check(Min.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Min.Reference> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Min.Reference annotation cannot be used on first parameter");
throw new HandlerException("Min.Reference annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (type.isArray()) type = type.getComponentType();
if (!type.is(int.class) && !type.is(Integer.class) && !type.is(long.class) && !type.is(Long.class) && !type.is(float.class) && !type.is(Float.class) && !type.is(double.class) && !type.is(Double.class)) {
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a number.", new CodePlace(parameter));
}
ParameterWrapper[] parameters = methodWrapper.getParameters();
for (int i = index - 1; i >= 1; i--) {
ParameterWrapper toCheck = parameters[i];
Name name = toCheck.getAnnotation(Name.class);
AnnotationWrapper<Name> name = toCheck.getAnnotation(Name.class);
String parameterName;
if (name == null) {
if (name.getAnnotation() == null) {
parameterName = toCheck.getName();
} else {
parameterName = name.value();
parameterName = name.getAnnotation().value();
}
if (!parameterName.equals(annotation.value())) {
if (!parameterName.equals(annotation.getAnnotation().value())) {
continue;
}
TypeWrapper parameterType = toCheck.getType();
if (!parameterType.isAssignableTo(type)) {
throw new HandlerException("Parameter type being referenced cannot be assigned here!");
throw new HandlerException("Parameter type being referenced cannot be assigned here!", new CodePlace(toCheck, name));
} else {
return;
}
}
throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist.");
throw new HandlerException("Parameter with name '" + annotation.getAnnotation().value() + "' does not exist.", new CodePlace(parameter, annotation));
}
@Override
@@ -35,12 +35,12 @@ public final class OptionalValueHandler {
public static final class Impl implements Handler.HandlerParameter<OptionalValue, Object, Object> {
@Override
public void check(OptionalValue annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<OptionalValue> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("OptionalValue annotation cannot be used on the first parameter");
throw new HandlerException("OptionalValue annotation cannot be used on the first parameter", new CodePlace(parameter, annotation));
}
if (parameter.isVarArgs() || parameter.getType().isArray()) {
throw new HandlerException("OptionalValue annotation cannot be used on varargs or array parameters");
throw new HandlerException("OptionalValue annotation cannot be used on varargs or array parameters", new CodePlace(parameter));
}
}
@@ -31,12 +31,12 @@ public final class RegexHandler {
public static final class Impl implements Handler.HandlerParameter<Regex, Object, String> {
@Override
public void check(Regex annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Regex> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Regex annotation cannot be used on first parameter");
throw new HandlerException("Regex annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
if (!parameter.getType().is(String.class)) {
throw new HandlerException("Regex annotation cannot be used on String parameter");
throw new HandlerException("Regex annotation cannot be used on String parameter", new CodePlace(parameter));
}
}
@@ -19,14 +19,11 @@
package de.steamwar.command.handler;
import de.steamwar.command.CommandUtils;
import de.steamwar.command.Handler;
import de.steamwar.command.annotations.Register;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
public final class RegisterHandler {
@@ -34,24 +31,24 @@ public final class RegisterHandler {
public static final class Impl implements Handler.HandlerMethod<Register> {
@Override
public void check(Register annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Register> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() == 0) {
throw new HandlerException("Register method must have at least one parameter");
throw new HandlerException("Register method must have at least one parameter", new CodePlace(method));
}
if (!method.getReturnType().is(void.class)) {
throw new HandlerException("Register method must return void");
throw new HandlerException("Register method must return void", new CodePlace(method));
}
// TODO: Implement hasExecutorMapper!
if (method instanceof MethodWrapper.ForMethod) {
if (!dataCheckable.hasExecutorMapper(((MethodWrapper.ForMethod) method).getMethod().getParameterTypes()[0])) {
throw new HandlerException("Register method first parameter must have a executor mapper registered");
throw new HandlerException("Register method first parameter must have a executor mapper registered", new CodePlace(method));
}
}
ParameterWrapper[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
ParameterWrapper parameter = parameters[i];
List<Annotation> annotationList = parameter.getAnnotations();
List<AnnotationWrapper<?>> annotationList = parameter.getAnnotations();
if (annotationList.isEmpty()) {
if (i == 0) {
continue;
@@ -62,27 +59,27 @@ public final class RegisterHandler {
type = type.getComponentType();
}
if (!type.isEnum() && !dataCheckable.hasMapper(type.getName())) {
throw new HandlerException("Register method parameter " + parameter.getName() + " must be annotated or have a type mapper");
throw new HandlerException("Register method parameter " + parameter.getName() + " must be annotated or have a type mapper", new CodePlace(parameter));
}
} else {
for (Annotation annotation1 : annotationList) {
getParameterHandler(annotation1).check(annotation1, method, parameter, i, dataCheckable);
for (AnnotationWrapper<?> annotation1 : annotationList) {
getParameterHandler(parameter, annotation1).check(annotation1, method, parameter, i, dataCheckable);
}
}
}
}
public static HandlerParameter getParameterHandler(Annotation annotation) throws HandlerException {
Implementation handler = annotation.annotationType().getAnnotation(Implementation.class);
public static HandlerParameter getParameterHandler(ParameterWrapper parameter, AnnotationWrapper<?> annotation) throws HandlerException {
Implementation handler = annotation.getAnnotation().annotationType().getAnnotation(Implementation.class);
Handler handlerObject;
try {
handlerObject = handler.value().getConstructor().newInstance();
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new HandlerException("Handler " + handler.value().getName() + " cannot be used to check the argument validity");
throw new HandlerException("Handler " + handler.value().getName() + " cannot be used to check the argument validity", new CodePlace(parameter, annotation));
}
if (!(handlerObject instanceof HandlerParameter)) {
throw new HandlerException("Handler " + handlerObject.getClass().getName() + " is not a HandlerParameter");
throw new HandlerException("Handler " + handlerObject.getClass().getName() + " is not a HandlerParameter", new CodePlace(parameter, annotation));
}
return (HandlerParameter) handlerObject;
}
@@ -35,12 +35,12 @@ public final class StartsWithHandler {
public static final class Impl implements Handler.HandlerParameter<StartsWith, Object, String> {
@Override
public void check(StartsWith annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<StartsWith> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("StartsWith annotation cannot be used on first parameter");
throw new HandlerException("StartsWith annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
if (!parameter.getType().is(String.class)) {
throw new HandlerException("StartsWith annotation cannot be used on String parameter");
throw new HandlerException("StartsWith annotation cannot be used on String parameter", new CodePlace(parameter));
}
}
@@ -34,16 +34,16 @@ public final class StaticValueHandler {
public static final class Impl implements Handler.HandlerParameter<StaticValue, Object, Object> {
@Override
public void check(StaticValue annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<StaticValue> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("StaticValue annotation cannot be used on first parameter");
throw new HandlerException("StaticValue annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (type.is(String.class)) return;
if (type.is(int.class) || type.is(Integer.class)) return;
if (type.is(long.class) || type.is(Long.class)) return;
if (type.is(boolean.class) || type.is(Boolean.class)) return;
throw new HandlerException("StaticValue parameter must be String, int, long or boolean");
throw new HandlerException("StaticValue parameter must be String, int, long or boolean", new CodePlace(parameter));
}
@Override
@@ -33,28 +33,28 @@ public final class SupplierHandler {
public static final class Impl implements Handler.HandlerMethod<Supplier>, Handler.HandlerParameter<Supplier, Object, Object> {
@Override
public void check(Supplier annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Supplier> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("Supplier method must have no parameters");
throw new HandlerException("Supplier method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeSupplier.class)) {
throw new HandlerException("Supplier method must return AbstractTypeSupplier");
throw new HandlerException("Supplier method must return AbstractTypeSupplier", new CodePlace(method));
}
if (annotation.value() != null && !annotation.value().isEmpty()) {
if (annotation.getAnnotation().value() != null && !annotation.getAnnotation().value().isEmpty()) {
return;
}
// TODO: Implement! for AnnotationProcessor as well!
if (method instanceof MethodWrapper.ForMethod) {
Optional<Class<?>> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod());
if (annotation.type() == void.class) {
if (annotation.getAnnotation().type() == void.class) {
if (genericType.isEmpty()) {
throw new UnsupportedOperationException("Please supply a class type to the Supplier");
throw new HandlerException("Please supply a class type to the Supplier", new CodePlace(method));
}
} else {
if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) {
throw new UnsupportedOperationException("Supplied type does not conform to actual type");
if (genericType.isPresent() && !annotation.getAnnotation().type().isAssignableFrom(genericType.get())) {
throw new HandlerException("Supplied type does not conform to actual type", new CodePlace(method));
}
}
}
@@ -78,22 +78,23 @@ public final class SupplierHandler {
}
@Override
public void check(Supplier annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Supplier> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Supplier annotation cannot be used on the first parameter");
throw new HandlerException("Supplier annotation cannot be used on the first parameter", new CodePlace(parameter, annotation));
}
String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName();
String s = annotation.getAnnotation().value() != null && !annotation.getAnnotation().value().isEmpty() ? annotation.getAnnotation().value() : parameter.getType().getTypeName();
if (!dataCheckable.hasSupplier(s)) {
throw new HandlerException("Supplier '" + annotation.value() + "' not found");
throw new HandlerException("Supplier '" + annotation.getAnnotation().value() + "' not found", new CodePlace(parameter));
}
boolean hasDisallowedAnnotations = parameter.getAnnotations()
.stream()
.filter(anno -> !(anno instanceof Supplier))
.filter(anno -> !(anno instanceof AllowNull))
.filter(anno -> !(anno instanceof Name))
.anyMatch(anno -> anno.getClass().isAnnotationPresent(Implementation.class));
.filter(anno -> !(anno.getAnnotation() instanceof Supplier))
.filter(anno -> !(anno.getAnnotation() instanceof AllowNull))
.filter(anno -> !(anno.getAnnotation() instanceof Name))
.anyMatch(anno -> anno.getAnnotation().annotationType().isAnnotationPresent(Implementation.class));
if (hasDisallowedAnnotations) {
throw new HandlerException("Only AllowNull or Name can be used in conjunction with Supplier annotation");
// TODO: Improve annotation handling!
throw new HandlerException("Only AllowNull or Name can be used in conjunction with Supplier annotation", new CodePlace(parameter));
}
}
}
@@ -40,9 +40,9 @@ public final class TabFilterHandler {
public static final class Impl implements Handler.HandlerParameter<TabFilter, Object, Object> {
@Override
public void check(TabFilter annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<TabFilter> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("TabFilter annotation cannot be used on first parameter");
throw new HandlerException("TabFilter annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
}
}
@@ -36,12 +36,12 @@ public final class UniqueHandler {
public static final class Impl implements Handler.HandlerParameter<Unique, Object, Object> {
@Override
public void check(Unique annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Unique> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Unique annotation cannot be used on the first parameter");
throw new HandlerException("Unique annotation cannot be used on the first parameter", new CodePlace(parameter, annotation));
}
if (!parameter.getType().isArray() && !parameter.isVarArgs()) {
throw new HandlerException("Unique annotation cannot be used on non array types");
throw new HandlerException("Unique annotation cannot be used on non array types", new CodePlace(parameter));
}
}
}
@@ -32,28 +32,28 @@ public final class ValidatorHandler {
public static final class Impl implements Handler.HandlerMethod<Validator>, Handler.HandlerParameter<Validator, Object, Object> {
@Override
public void check(Validator annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Validator> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
if (method.getParameterCount() != 0) {
throw new HandlerException("Validator method must have no parameters");
throw new HandlerException("Validator method must have no parameters", new CodePlace(method));
}
if (!method.getReturnType().isAssignableTo(AbstractTypeValidator.class)) {
throw new HandlerException("Validator method must return AbstractValidator");
throw new HandlerException("Validator method must return AbstractValidator", new CodePlace(method));
}
if (annotation.value() != null && !annotation.value().isEmpty()) {
if (annotation.getAnnotation().value() != null && !annotation.getAnnotation().value().isEmpty()) {
return;
}
// TODO: Implement! for AnnotationProcessor as well!
if (method instanceof MethodWrapper.ForMethod) {
Optional<Class<?>> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod());
if (annotation.type() == void.class) {
if (annotation.getAnnotation().type() == void.class) {
if (genericType.isEmpty()) {
throw new HandlerException("Please supply a class type to the Validator");
throw new HandlerException("Please supply a class type to the Validator", new CodePlace(method));
}
} else {
if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) {
throw new HandlerException("Supplied type does not conform to actual type");
if (genericType.isPresent() && !annotation.getAnnotation().type().isAssignableFrom(genericType.get())) {
throw new HandlerException("Supplied type does not conform to actual type", new CodePlace(method));
}
}
}
@@ -77,10 +77,10 @@ public final class ValidatorHandler {
}
@Override
public void check(Validator annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName();
public void check(AnnotationWrapper<Validator> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
String s = annotation.getAnnotation().value() != null && !annotation.getAnnotation().value().isEmpty() ? annotation.getAnnotation().value() : parameter.getType().getTypeName();
if (!dataCheckable.hasValidator(s)) {
throw new HandlerException("Validator '" + annotation.value() + "' not found");
throw new HandlerException("Validator '" + annotation.getAnnotation().value() + "' not found", new CodePlace(parameter, annotation));
}
}
@@ -33,16 +33,16 @@ public final class ValuesHandler {
public static final class Impl implements Handler.HandlerParameter<Values, Object, Object> {
@Override
public void check(Values annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Values> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Values annotation cannot be used on first parameter");
throw new HandlerException("Values annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (type.is(String.class)) return;
if (type.is(int.class) || type.is(Integer.class)) return;
if (type.is(long.class) || type.is(Long.class)) return;
if (type.is(boolean.class) || type.is(Boolean.class)) return;
throw new HandlerException("Values parameter must be String, int, long or boolean");
throw new HandlerException("Values parameter must be String, int, long or boolean", new CodePlace(parameter));
}
@Override
@@ -36,39 +36,39 @@ public class ValuesReferenceHandler {
public static final class Impl implements Handler.HandlerParameter<Values.Reference, Object, Object> {
@Override
public void check(Values.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
public void check(AnnotationWrapper<Values.Reference> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) {
throw new HandlerException("Values.Reference annotation cannot be used on first parameter");
throw new HandlerException("Values.Reference annotation cannot be used on first parameter", new CodePlace(parameter, annotation));
}
TypeWrapper type = parameter.getType();
if (type.isArray()) type = type.getComponentType();
if (!type.is(int.class) && !type.is(Integer.class) && !type.is(long.class) && !type.is(Long.class) && !type.is(String.class)) {
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a String or Int or Long.");
throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not a String or Int or Long.", new CodePlace(parameter));
}
ParameterWrapper[] parameters = methodWrapper.getParameters();
for (int i = index - 1; i >= 1; i--) {
ParameterWrapper toCheck = parameters[i];
Name name = toCheck.getAnnotation(Name.class);
AnnotationWrapper<Name> name = toCheck.getAnnotation(Name.class);
String parameterName;
if (name == null) {
if (name.getAnnotation() == null) {
parameterName = toCheck.getName();
} else {
parameterName = name.value();
parameterName = name.getAnnotation().value();
}
if (!parameterName.equals(annotation.value())) {
if (!parameterName.equals(annotation.getAnnotation().value())) {
continue;
}
TypeWrapper toCheckType = toCheck.getType();
if (toCheckType.isArray()) toCheckType = toCheckType.getComponentType();
if (!toCheckType.is(type)) {
throw new HandlerException("Parameter type being referenced cannot be assigned here!");
throw new HandlerException("Parameter type being referenced cannot be assigned here!", new CodePlace(toCheck, name));
} else {
return;
}
}
throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist.");
throw new HandlerException("Parameter with name '" + annotation.getAnnotation().value() + "' does not exist.", new CodePlace(parameter, annotation));
}
@Override