From 18659385d2628717af9a1bed00516d1c87c9bf1d Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 23 Nov 2025 20:27:44 +0100 Subject: [PATCH] Add Annotation Processor for compile time checks --- .../build.gradle.kts | 32 +++ .../javax.annotation.processing.Processor | 5 + .../command/HandlerForExecutableElement.java | 65 ++++++ .../command/HandlerForTypeMirror.java | 107 +++++++++ .../command/HandlerForVariableElement.java | 77 +++++++ .../AbstractAnnotationProcessor.java | 176 +++++++++++++++ .../impl/CachedAnnotationProcessor.java | 33 +++ .../impl/MapperAnnotationProcessor.java | 33 +++ .../impl/RegisterAnnotationProcessor.java | 33 +++ .../impl/SupplierAnnotationProcessor.java | 33 +++ .../impl/ValidatorAnnotationProcessor.java | 33 +++ .../src/de/steamwar/command/CommandUtils.java | 10 +- .../src/de/steamwar/command/Handler.java | 209 +++++++++++++++++- .../command/handler/AllowNullHandler.java | 6 +- .../command/handler/ArrayLengthHandler.java | 8 +- .../command/handler/CachedHandler.java | 8 +- .../command/handler/ClassMapperHandler.java | 8 +- .../handler/ClassValidatorHandler.java | 8 +- .../command/handler/EndsWithHandler.java | 8 +- .../command/handler/ErrorMessageHandler.java | 6 +- .../command/handler/GreedyHandler.java | 4 +- .../command/handler/LengthHandler.java | 4 +- .../command/handler/MapperHandler.java | 31 +-- .../steamwar/command/handler/MaxHandler.java | 26 +-- .../command/handler/MaxReferenceHandler.java | 26 +-- .../steamwar/command/handler/MinHandler.java | 21 +- .../command/handler/MinReferenceHandler.java | 26 +-- .../command/handler/OptionalValueHandler.java | 6 +- .../command/handler/RegexHandler.java | 8 +- .../command/handler/RegisterHandler.java | 33 +-- .../command/handler/StartsWithHandler.java | 8 +- .../command/handler/StaticValueHandler.java | 16 +- .../command/handler/SupplierHandler.java | 28 +-- .../command/handler/TabFilterHandler.java | 4 +- .../command/handler/UniqueHandler.java | 6 +- .../command/handler/ValidatorHandler.java | 27 ++- .../command/handler/ValuesHandler.java | 16 +- .../handler/ValuesReferenceHandler.java | 23 +- .../CommandFrameworkTests/build.gradle.kts | 2 + settings.gradle.kts | 1 + 40 files changed, 1029 insertions(+), 185 deletions(-) create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/build.gradle.kts create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/META-INF/services/javax.annotation.processing.Processor create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForExecutableElement.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForTypeMirror.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForVariableElement.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/AbstractAnnotationProcessor.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/CachedAnnotationProcessor.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/MapperAnnotationProcessor.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/RegisterAnnotationProcessor.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/SupplierAnnotationProcessor.java create mode 100644 CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/ValidatorAnnotationProcessor.java diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/build.gradle.kts b/CommandFramework/CommandFrameworkAnnotationProcessor/build.gradle.kts new file mode 100644 index 00000000..c0457098 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/build.gradle.kts @@ -0,0 +1,32 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 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 . + */ + +plugins { + steamwar.java +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +dependencies { + implementation(project(":CommandFramework:CommandFrameworkBase", "default")) + annotationProcessor(project(":CommandFramework:CommandFrameworkBase", "default")) +} \ No newline at end of file diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/META-INF/services/javax.annotation.processing.Processor b/CommandFramework/CommandFrameworkAnnotationProcessor/src/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..a8e2a61b --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,5 @@ +de.steamwar.command.annotationprocessor.impl.CachedAnnotationProcessor +de.steamwar.command.annotationprocessor.impl.MapperAnnotationProcessor +de.steamwar.command.annotationprocessor.impl.RegisterAnnotationProcessor +de.steamwar.command.annotationprocessor.impl.SupplierAnnotationProcessor +de.steamwar.command.annotationprocessor.impl.ValidatorAnnotationProcessor \ No newline at end of file diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForExecutableElement.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForExecutableElement.java new file mode 100644 index 00000000..5810b2bf --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForExecutableElement.java @@ -0,0 +1,65 @@ +/* + * 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 . + */ + +package de.steamwar.command; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.List; + +public class HandlerForExecutableElement implements Handler.MethodWrapper { + + private final ExecutableElement method; + private final Types types; + private final Elements elements; + + public HandlerForExecutableElement(ExecutableElement method, Types types, Elements elements) { + this.method = method; + this.types = types; + this.elements = elements; + } + + @Override + public String getName() { + return method.getSimpleName().toString(); + } + + @Override + public int getParameterCount() { + return method.getParameters().size(); + } + + @Override + public Handler.TypeWrapper getReturnType() { + return new HandlerForTypeMirror(method.getReturnType(), types, elements); + } + + @Override + public Handler.ParameterWrapper[] getParameters() { + Handler.ParameterWrapper[] parameters = new Handler.ParameterWrapper[method.getParameters().size()]; + List variableElements = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + VariableElement variableElement = variableElements.get(i); + parameters[i] = new HandlerForVariableElement(variableElement, types, elements, i == parameters.length - 1 && method.isVarArgs()); + } + return parameters; + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForTypeMirror.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForTypeMirror.java new file mode 100644 index 00000000..d5622056 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForTypeMirror.java @@ -0,0 +1,107 @@ +/* + * 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 . + */ + +package de.steamwar.command; + +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +public class HandlerForTypeMirror implements Handler.TypeWrapper { + + private final TypeMirror type; + private final Types types; + private final Elements elements; + + public HandlerForTypeMirror(TypeMirror type, Types types, Elements elements) { + this.type = type; + this.types = types; + this.elements = elements; + } + + @Override + public boolean isAssignableTo(Class clazz) { + return types.isAssignable(types.erasure(type), types.erasure(elements.getTypeElement(clazz.getTypeName()).asType())); + } + + @Override + public boolean isAssignableTo(Handler.TypeWrapper type) { + if (type instanceof ForClass) { + return isAssignableTo(((ForClass) type).getClazz()); + } else if (type instanceof HandlerForTypeMirror) { + return types.isAssignable(types.erasure(this.type), types.erasure(((HandlerForTypeMirror) type).type)); + } + return false; + } + + @Override + public boolean isPrimitive() { + return type.getKind().isPrimitive(); + } + + @Override + public boolean isArray() { + return type instanceof ArrayType; + } + + @Override + public boolean isEnum() { + System.out.println(type); + return false; + } + + @Override + public boolean is(Class clazz) { + if (type.getKind() == TypeKind.VOID && clazz == Void.TYPE) { + return true; + } else if (type.getKind().isPrimitive() && clazz.isPrimitive()) { + return type.toString().equals(clazz.getTypeName()); + } else if (!type.getKind().isPrimitive() && !clazz.isPrimitive()) { + return types.isSameType(types.erasure(type), types.erasure(elements.getTypeElement(clazz.getTypeName()).asType())); + } else { + return false; + } + } + + @Override + public boolean is(Handler.TypeWrapper type) { + if (type instanceof ForClass) { + return is(((ForClass) type).getClazz()); + } else if (type instanceof HandlerForTypeMirror) { + return types.isSameType(types.erasure(this.type), types.erasure(((HandlerForTypeMirror) type).type)); + } + return false; + } + + @Override + public Handler.TypeWrapper getComponentType() { + if (type instanceof ArrayType) { + return new HandlerForTypeMirror(((ArrayType) type).getComponentType(), types, elements); + } else { + return new HandlerForTypeMirror(null, types, elements); + } + } + + @Override + public String getName() { + return type.toString(); + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForVariableElement.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForVariableElement.java new file mode 100644 index 00000000..abc670fa --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/HandlerForVariableElement.java @@ -0,0 +1,77 @@ +/* + * 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 . + */ + +package de.steamwar.command; + +import de.steamwar.command.handler.RegisterHandler; + +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.List; + +public class HandlerForVariableElement implements Handler.ParameterWrapper { + + private final VariableElement parameter; + private final Types types; + private final Elements elements; + private final boolean varArgs; + + public HandlerForVariableElement(VariableElement variableElement, Types types, Elements elements, boolean varArgs) { + this.parameter = variableElement; + this.types = types; + this.elements = elements; + this.varArgs = varArgs; + } + + @Override + public Handler.TypeWrapper getType() { + return new HandlerForTypeMirror(parameter.asType(), types, elements); + } + + @Override + public boolean isVarArgs() { + return varArgs; + } + + @Override + public boolean isAnnotationPresent(Class annotation) { + return parameter.getAnnotation(annotation) != null; + } + + @Override + public A getAnnotation(Class annotation) { + return parameter.getAnnotation(annotation); + } + + @Override + public String getName() { + return parameter.getSimpleName().toString(); + } + + @Override + public List getAnnotations() { + parameter.getAnnotationMirrors().forEach(annotationMirror -> { + System.out.println(annotationMirror); + }); + return Collections.emptyList(); + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/AbstractAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/AbstractAnnotationProcessor.java new file mode 100644 index 00000000..e0dfbab9 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/AbstractAnnotationProcessor.java @@ -0,0 +1,176 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor; + +import de.steamwar.command.Handler; +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.*; +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.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public abstract class AbstractAnnotationProcessor extends AbstractProcessor { + + private Messager messager; + private Types types; + private Elements elements; + + public abstract Class getAnnotationClass(); + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.messager = processingEnv.getMessager(); + this.types = processingEnv.getTypeUtils(); + this.elements = processingEnv.getElementUtils(); + } + + @Override + public Set getSupportedAnnotationTypes() { + return Collections.singleton(this.getAnnotationClass().getCanonicalName()); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + List elements = roundEnv.getElementsAnnotatedWith(getAnnotationClass()) + .stream() + .filter(element -> element.getKind() == ElementKind.METHOD) + .map(ExecutableElement.class::cast) + .collect(Collectors.toList()); + if (elements.isEmpty()) return false; + elements.forEach(element -> { + checkMethodAnnotation(element, element.getAnnotation(getAnnotationClass())); + + List parameters = element.getParameters(); + for (int index = 0; index < parameters.size(); index++) { + VariableElement parameter = parameters.get(index); + for (AnnotationMirror annotationMirror : parameter.getAnnotationMirrors()) { + Class clazz = getClass(annotationMirror.getAnnotationType().toString()); + if (clazz == null) return; + checkParameterAnnotation(element, parameter, index, parameter.getAnnotation((Class) clazz)); + } + } + }); + return false; + } + + private Class getClass(String name) { + try { + return Class.forName(name); + } catch (ClassNotFoundException e) { + // Ignore + } + if (!name.contains(".")) return null; + Class outerClass = getClass(name.substring(0, name.lastIndexOf('.'))); + if (outerClass == null) return null; + name = name.substring(name.lastIndexOf('.') + 1); + for (Class declaredClass : outerClass.getDeclaredClasses()) { + if (declaredClass.getSimpleName().equals(name)) { + return declaredClass; + } + } + return null; + } + + private Handler getHandler(Annotation annotation, Element element) { + Handler.Implementation implementation = annotation.annotationType().getAnnotation(Handler.Implementation.class); + if (implementation == null) return null; + try { + return implementation.value().getConstructor().newInstance(); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + messager.printMessage(Diagnostic.Kind.ERROR, "Handler " + implementation.value().getName() + " cannot be used to check the argument validity", element); + return null; + } + } + + private void checkMethodAnnotation(ExecutableElement method, Annotation annotation) { + Handler handler = getHandler(annotation, method); + if (handler == null) return; + if (!(handler instanceof Handler.HandlerMethod)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Handler " + handler.getClass().getName() + " is not a HandlerMethod", method); + return; + } + Handler.HandlerMethod handlerMethod = (Handler.HandlerMethod) handler; + try { + handlerMethod.check(annotation, new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE); + } catch (Handler.HandlerException e) { + messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), method); + } + } + + private void checkParameterAnnotation(ExecutableElement method, VariableElement parameter, int index, Annotation annotation) { + Handler handler = getHandler(annotation, parameter); + if (handler == null) return; + if (!(handler instanceof Handler.HandlerParameter)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Handler " + handler.getClass().getName() + " is not a HandlerParameter", method); + return; + } + Handler.HandlerParameter handlerParameter = (Handler.HandlerParameter) handler; + try { + handlerParameter.check(annotation, new HandlerForExecutableElement(method, types, elements), new HandlerForVariableElement(parameter, types, elements, index == method.getParameters().size() - 1 && method.isVarArgs()), index, DataCheckableImpl.INSTANCE); + } catch (Handler.HandlerException e) { + messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), parameter); + } + } + + private static final class DataCheckableImpl implements Handler.DataCheckable { + + private static final DataCheckableImpl INSTANCE = new DataCheckableImpl(); + + @Override + public boolean hasExecutorMapper(Class clazz) { + return true; + } + + @Override + public boolean hasMapper(String key) { + return true; + } + + @Override + public boolean hasValidator(String key) { + return true; + } + + @Override + public boolean hasSupplier(String key) { + return true; + } + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/CachedAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/CachedAnnotationProcessor.java new file mode 100644 index 00000000..8c82c418 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/CachedAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor.impl; + +import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor; +import de.steamwar.command.annotations.Cached; + +import java.lang.annotation.Annotation; + +public class CachedAnnotationProcessor extends AbstractAnnotationProcessor { + + @Override + public Class getAnnotationClass() { + return Cached.class; + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/MapperAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/MapperAnnotationProcessor.java new file mode 100644 index 00000000..02f24506 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/MapperAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor.impl; + +import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor; +import de.steamwar.command.annotations.Mapper; + +import java.lang.annotation.Annotation; + +public class MapperAnnotationProcessor extends AbstractAnnotationProcessor { + + @Override + public Class getAnnotationClass() { + return Mapper.class; + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/RegisterAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/RegisterAnnotationProcessor.java new file mode 100644 index 00000000..b25c06b3 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/RegisterAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor.impl; + +import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor; +import de.steamwar.command.annotations.Register; + +import java.lang.annotation.Annotation; + +public class RegisterAnnotationProcessor extends AbstractAnnotationProcessor { + + @Override + public Class getAnnotationClass() { + return Register.class; + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/SupplierAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/SupplierAnnotationProcessor.java new file mode 100644 index 00000000..844c33d0 --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/SupplierAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor.impl; + +import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor; +import de.steamwar.command.annotations.Supplier; + +import java.lang.annotation.Annotation; + +public class SupplierAnnotationProcessor extends AbstractAnnotationProcessor { + + @Override + public Class getAnnotationClass() { + return Supplier.class; + } +} diff --git a/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/ValidatorAnnotationProcessor.java b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/ValidatorAnnotationProcessor.java new file mode 100644 index 00000000..1526c49c --- /dev/null +++ b/CommandFramework/CommandFrameworkAnnotationProcessor/src/de/steamwar/command/annotationprocessor/impl/ValidatorAnnotationProcessor.java @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +package de.steamwar.command.annotationprocessor.impl; + +import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor; +import de.steamwar.command.annotations.Validator; + +import java.lang.annotation.Annotation; + +public class ValidatorAnnotationProcessor extends AbstractAnnotationProcessor { + + @Override + public Class getAnnotationClass() { + return Validator.class; + } +} diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/CommandUtils.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/CommandUtils.java index be9dc2e0..b72bd936 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/CommandUtils.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/CommandUtils.java @@ -132,14 +132,14 @@ public class CommandUtils { return annotations; } - public static ToIntFunction createComparator(String type, Class clazz, int iValue, long lValue, float fValue, double dValue) { - if (clazz == int.class || clazz == Integer.class) { + public static ToIntFunction createComparator(String type, Handler.TypeWrapper clazz, int iValue, long lValue, float fValue, double dValue) { + if (clazz.is(int.class) || clazz.is(Integer.class)) { return number -> Integer.compare(number.intValue(), iValue); - } else if (clazz == long.class || clazz == Long.class) { + } else if (clazz.is(long.class) || clazz.is(Long.class)) { return number -> Long.compare(number.longValue(), lValue); - } else if (clazz == float.class || clazz == Float.class) { + } else if (clazz.is(float.class) || clazz.is(Float.class)) { return number -> Float.compare(number.floatValue(), fValue); - } else if (clazz == double.class || clazz == Double.class) { + } else if (clazz.is(double.class) || clazz.is(Double.class)) { return number -> Double.compare(number.doubleValue(), dValue); } else { throw new IllegalArgumentException(type + " annotation is not supported for " + clazz); diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/Handler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/Handler.java index 667c0375..5529af6e 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/Handler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/Handler.java @@ -19,11 +19,15 @@ package de.steamwar.command; +import lombok.Getter; + import java.lang.annotation.*; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -58,17 +62,29 @@ public interface Handler { Class value(); } + class HandlerException extends Exception { + public HandlerException(String message) { + super(message); + } + } + interface DataCheckable { boolean hasExecutorMapper(Class clazz); + boolean hasMapper(String key); + boolean hasValidator(String key); + boolean hasSupplier(String key); } interface DataReadable { Function getExecutorMapper(Class clazz); + AbstractTypeMapper getMapper(String key); + AbstractTypeValidator getValidator(String key); + AbstractTypeSupplier getSupplier(String key); } @@ -76,17 +92,26 @@ public interface Handler { Function getExecutorMapper(Class clazz); void addMapper(String key, boolean local, AbstractTypeMapper mapper); + void addValidator(String key, boolean local, AbstractTypeValidator validator); + void addSupplier(String key, boolean local, AbstractTypeSupplier supplier); + /** * Invoking the same method twice will result in the exact same result. */ T invoke(Method method); + void addCommand(Method method, String[] subCommand, String[] description, boolean noTabComplete); } interface HandlerMethod extends Handler { - void check(T annotation, Method method, DataCheckable dataCheckable) throws Exception; + default void check(T annotation, Method method, DataCheckable dataCheckable) throws Exception { + check(annotation, new MethodWrapper.ForMethod(method), dataCheckable); + } + + default void check(T annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { + } int getRunPriority(); @@ -94,7 +119,12 @@ public interface Handler { } interface HandlerParameter extends Handler { - void check(T annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception; + default void check(T annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + check(annotation, new MethodWrapper.ForMethod((Method) parameter.getDeclaringExecutable()), new ParameterWrapper.ForParameter(parameter), index, dataCheckable); + } + + default void check(T annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { + } default boolean needsParentTypeMapper() { return false; @@ -118,4 +148,179 @@ public interface Handler { return null; } } + + interface MethodWrapper { + String getName(); + + int getParameterCount(); + + TypeWrapper getReturnType(); + + ParameterWrapper[] getParameters(); + + class ForMethod implements MethodWrapper { + + @Getter + private final Method method; + + public ForMethod(Method method) { + this.method = method; + } + + @Override + public String getName() { + return method.getName(); + } + + @Override + public int getParameterCount() { + return method.getParameterCount(); + } + + @Override + public TypeWrapper getReturnType() { + return new TypeWrapper.ForClass(method.getReturnType()); + } + + @Override + public ParameterWrapper[] getParameters() { + return Arrays.stream(method.getParameters()).map(ParameterWrapper.ForParameter::new).toArray(ParameterWrapper[]::new); + } + } + } + + interface ParameterWrapper { + TypeWrapper getType(); + + boolean isVarArgs(); + + boolean isAnnotationPresent(Class annotation); + + A getAnnotation(Class annotation); + + String getName(); + + List getAnnotations(); + + class ForParameter implements ParameterWrapper { + + @Getter + private final Parameter parameter; + + public ForParameter(Parameter parameter) { + this.parameter = parameter; + } + + @Override + public TypeWrapper getType() { + return new TypeWrapper.ForClass(this.parameter.getType()); + } + + @Override + public boolean isVarArgs() { + return parameter.isVarArgs(); + } + + @Override + public boolean isAnnotationPresent(Class annotation) { + return parameter.isAnnotationPresent(annotation); + } + + @Override + public A getAnnotation(Class annotation) { + return parameter.getAnnotation(annotation); + } + + @Override + public String getName() { + return parameter.getName(); + } + + @Override + public List getAnnotations() { + return CommandUtils.getAnnotations(parameter); + } + } + } + + interface TypeWrapper { + + boolean isAssignableTo(Class clazz); + + boolean isAssignableTo(TypeWrapper type); + + boolean isPrimitive(); + + boolean isArray(); + + boolean isEnum(); + + boolean is(Class clazz); + + boolean is(TypeWrapper type); + + TypeWrapper getComponentType(); + + String getName(); + + class ForClass implements TypeWrapper { + @Getter + private final Class clazz; + + public ForClass(Class clazz) { + this.clazz = clazz; + } + + @Override + public boolean isAssignableTo(Class clazz) { + return clazz.isAssignableFrom(this.clazz); + } + + @Override + public boolean isAssignableTo(TypeWrapper type) { + if (type instanceof ForClass) { + return ((ForClass) type).getClazz().isAssignableFrom(clazz); + } + return false; + } + + @Override + public boolean isPrimitive() { + return clazz.isPrimitive(); + } + + @Override + public boolean isArray() { + return clazz.isArray(); + } + + @Override + public boolean isEnum() { + return clazz.isEnum(); + } + + @Override + public boolean is(Class clazz) { + return this.clazz == clazz; + } + + @Override + public boolean is(TypeWrapper type) { + if (type instanceof ForClass) { + return ((ForClass) type).getClazz() == this.clazz; + } + return false; + } + + @Override + public TypeWrapper getComponentType() { + return new TypeWrapper.ForClass(this.clazz.getComponentType()); + } + + @Override + public String getName() { + return this.clazz.getName(); + } + } + } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/AllowNullHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/AllowNullHandler.java index dd170378..340cc833 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/AllowNullHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/AllowNullHandler.java @@ -36,12 +36,12 @@ public final class AllowNullHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(AllowNull annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(AllowNull annotation, MethodWrapper method, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("AllowNull annotation cannot be used on the first parameter"); + throw new HandlerException("AllowNull annotation cannot be used on the first parameter"); } if (parameter.getType().isPrimitive()) { - throw new UnsupportedOperationException("AllowNull annotation cannot be used on primitive types"); + throw new HandlerException("AllowNull annotation cannot be used on primitive types"); } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ArrayLengthHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ArrayLengthHandler.java index 487d13b9..65ff83a4 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ArrayLengthHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ArrayLengthHandler.java @@ -47,15 +47,15 @@ public final class ArrayLengthHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(ArrayLength arrayLength, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(ArrayLength arrayLength, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("ArrayLength annotation cannot be used on first parameter"); + throw new HandlerException("ArrayLength annotation cannot be used on first parameter"); } if (!parameter.getType().isArray()) { - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable().getName() + " is not an array"); + throw new HandlerException("Parameter " + index + " of " + methodWrapper.getName() + " is not an array"); } if (arrayLength.min() > arrayLength.max()) { - throw new UnsupportedOperationException("Min ArrayLength cannot be smaller than Max ArrayLength"); + throw new HandlerException("Min ArrayLength cannot be smaller than Max ArrayLength"); } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/CachedHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/CachedHandler.java index 59ac3522..a72023d8 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/CachedHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/CachedHandler.java @@ -31,12 +31,12 @@ public final class CachedHandler { public static final class Impl implements Handler.HandlerMethod { @Override - public void check(Cached annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(Cached annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("Cached method must have no parameters"); + throw new HandlerException("Cached method must have no parameters"); } - if (!AbstractTypeMapper.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("Cached method must return AbstractTypeMapper"); + if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) { + throw new HandlerException("Cached method must return AbstractTypeMapper"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassMapperHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassMapperHandler.java index ab31acb1..15d7a97d 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassMapperHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassMapperHandler.java @@ -31,12 +31,12 @@ public final class ClassMapperHandler { public static final class Impl implements Handler.HandlerMethod { @Override - public void check(ClassMapper annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(ClassMapper annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("ClassMapper method must have no parameters"); + throw new HandlerException("ClassMapper method must have no parameters"); } - if (!AbstractTypeMapper.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("ClassMapper method must return AbstractTypeMapper"); + if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) { + throw new HandlerException("ClassMapper method must return AbstractTypeMapper"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassValidatorHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassValidatorHandler.java index a8d64e82..2a282cf0 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassValidatorHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ClassValidatorHandler.java @@ -31,12 +31,12 @@ public final class ClassValidatorHandler { public static final class Impl implements Handler.HandlerMethod { @Override - public void check(ClassValidator annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(ClassValidator annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("ClassValidator method must have no parameters"); + throw new HandlerException("ClassValidator method must have no parameters"); } - if (!AbstractTypeValidator.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("ClassValidator method must return AbstractValidator"); + if (!method.getReturnType().isAssignableTo(AbstractTypeValidator.class)) { + throw new HandlerException("ClassValidator method must return AbstractValidator"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/EndsWithHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/EndsWithHandler.java index 37ea29ee..5ea8500f 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/EndsWithHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/EndsWithHandler.java @@ -35,12 +35,12 @@ public final class EndsWithHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(EndsWith annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(EndsWith annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("EndsWith annotation cannot be used on first parameter"); + throw new HandlerException("EndsWith annotation cannot be used on first parameter"); } - if (parameter.getType() != String.class) { - throw new UnsupportedOperationException("EndsWith annotation cannot be used on String parameter"); + if (!parameter.getType().is(String.class)) { + throw new HandlerException("EndsWith annotation cannot be used on String parameter"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ErrorMessageHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ErrorMessageHandler.java index df5a278e..56dd5e0a 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ErrorMessageHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ErrorMessageHandler.java @@ -31,12 +31,12 @@ public final class ErrorMessageHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(ErrorMessage errorMessage, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(ErrorMessage errorMessage, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("ErrorMessage annotation cannot be used on first parameter"); + throw new HandlerException("ErrorMessage annotation cannot be used on first parameter"); } if (!errorMessage.allowEAs() && !(parameter.isVarArgs() || parameter.getType().isArray())) { - throw new UnsupportedOperationException("ErrorMessage allowESs cannot be used on non array or varargs parameter"); + throw new HandlerException("ErrorMessage allowESs cannot be used on non array or varargs parameter"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/GreedyHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/GreedyHandler.java index 1eaa20a0..4d595a8e 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/GreedyHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/GreedyHandler.java @@ -44,9 +44,9 @@ public final class GreedyHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Greedy annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Greedy annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (!parameter.getType().isArray() || parameter.isVarArgs()) { - throw new UnsupportedOperationException("Greedy annotation cannot be used on non array parameters"); + throw new HandlerException("Greedy annotation cannot be used on non array parameters"); } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/LengthHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/LengthHandler.java index 9d6ba906..aedb45c9 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/LengthHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/LengthHandler.java @@ -35,9 +35,9 @@ public final class LengthHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Length annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Length annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Length annotation cannot be used on first parameter"); + throw new HandlerException("Length annotation cannot be used on first parameter"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MapperHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MapperHandler.java index a01392c1..57122912 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MapperHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MapperHandler.java @@ -32,26 +32,29 @@ public final class MapperHandler { public static final class Impl implements Handler.HandlerMethod, Handler.HandlerParameter { @Override - public void check(Mapper annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(Mapper annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("Mapper method must have no parameters"); + throw new HandlerException("Mapper method must have no parameters"); } - if (!AbstractTypeMapper.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("Mapper method must return AbstractTypeMapper"); + if (!method.getReturnType().isAssignableTo(AbstractTypeMapper.class)) { + throw new HandlerException("Mapper method must return AbstractTypeMapper"); } if (annotation.value() != null && !annotation.value().isEmpty()) { return; } - Optional> genericType = getGenericTypeOfReturn(method); - if (annotation.type() == void.class) { - if (genericType.isEmpty()) { - throw new UnsupportedOperationException("Please supply a class type to the Mapper"); - } - } else { - if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { - throw new UnsupportedOperationException("Supplied type does not conform to actual type"); + // TODO: Implement! for AnnotationProcessor as well! + if (method instanceof MethodWrapper.ForMethod) { + Optional> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod()); + if (annotation.type() == void.class) { + if (genericType.isEmpty()) { + throw new HandlerException("Please supply a class type to the Mapper"); + } + } else { + if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { + throw new HandlerException("Supplied type does not conform to actual type"); + } } } } @@ -74,9 +77,9 @@ public final class MapperHandler { } @Override - public void check(Mapper annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Mapper annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Mapper annotation cannot be used on first parameter"); + throw new HandlerException("Mapper annotation cannot be used on first parameter"); } if (!dataCheckable.hasMapper(annotation.value())) { throw new UnsupportedOperationException("Mapper '" + annotation.value() + "' not found"); diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxHandler.java index a44d985c..65d98be1 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxHandler.java @@ -34,15 +34,15 @@ public final class MaxHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Max max, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Max max, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Max annotation cannot be used on first parameter"); + throw new HandlerException("Max annotation cannot be used on first parameter"); } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (parameter.isVarArgs()) type = type.getComponentType(); - if (type != int.class && type != Integer.class && type != long.class && type != Long.class && type != float.class && type != Float.class && type != double.class && type != Double.class) { - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable() + " is not a number."); + 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."); } if (!parameter.isAnnotationPresent(Min.class)) { @@ -52,13 +52,13 @@ public final class MaxHandler { Min min = parameter.getAnnotation(Min.class); Number minValue; - if (type.equals(int.class) || type.equals(Integer.class)) { + if (type.is(int.class) || type.is(Integer.class)) { minValue = min.intValue(); - } else if (type.equals(long.class) || type.equals(Long.class)) { + } else if (type.is(long.class) || type.is(Long.class)) { minValue = min.longValue(); - } else if (type.equals(float.class) || type.equals(Float.class)) { + } else if (type.is(float.class) || type.is(Float.class)) { minValue = min.floatValue(); - } else if (type.equals(double.class) || type.equals(Double.class)) { + } else if (type.is(double.class) || type.is(Double.class)) { minValue = min.doubleValue(); } else { throw new SecurityException(); @@ -66,9 +66,9 @@ public final class MaxHandler { ToIntFunction maxComparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue()); if (!(min.inclusive() && max.inclusive()) && maxComparator.applyAsInt(minValue) == 0) { - throw new UnsupportedOperationException("Min and Max cannot be equal if not both are inclusive"); + throw new HandlerException("Min and Max cannot be equal if not both are inclusive"); } else if (maxComparator.applyAsInt(minValue) > 0) { - throw new UnsupportedOperationException("Max must be bigger then Min"); + throw new HandlerException("Max must be bigger then Min"); } } @@ -83,7 +83,7 @@ public final class MaxHandler { if (parameter.isVarArgs()) type = type.getComponentType(); int compareValue = max.inclusive() ? 0 : -1; - ToIntFunction comparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue()); + ToIntFunction comparator = CommandUtils.createComparator("Max", new TypeWrapper.ForClass(type), max.intValue(), max.longValue(), max.floatValue(), max.doubleValue()); boolean onlyNegative = comparator.applyAsInt(0) >= 0; Min min = parameter.getAnnotation(Min.class); @@ -155,7 +155,7 @@ public final class MaxHandler { } int compareValue = max.inclusive() ? 0 : -1; - ToIntFunction comparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue()); + ToIntFunction comparator = CommandUtils.createComparator("Max", new TypeWrapper.ForClass(type), max.intValue(), max.longValue(), max.floatValue(), max.doubleValue()); return (sender, value, messageSender) -> { if (value == null) return true; diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxReferenceHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxReferenceHandler.java index 05ae49c2..ec2031f8 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxReferenceHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MaxReferenceHandler.java @@ -36,20 +36,20 @@ public final class MaxReferenceHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Max.Reference annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Max.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Max.Reference annotation cannot be used on first parameter"); + throw new HandlerException("Max.Reference annotation cannot be used on first parameter"); } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - if (type != int.class && type != Integer.class && type != long.class && type != Long.class && type != float.class && type != Float.class && type != double.class && type != Double.class) { - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable() + " is not a number."); + 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."); } - Parameter[] parameters = parameter.getDeclaringExecutable().getParameters(); + ParameterWrapper[] parameters = methodWrapper.getParameters(); for (int i = index - 1; i >= 1; i--) { - Parameter toCheck = parameters[i]; + ParameterWrapper toCheck = parameters[i]; Name name = toCheck.getAnnotation(Name.class); String parameterName; if (name == null) { @@ -60,14 +60,14 @@ public final class MaxReferenceHandler { if (!parameterName.equals(annotation.value())) { continue; } - Class parameterType = toCheck.getType(); - if (!type.isAssignableFrom(parameterType)) { - throw new UnsupportedOperationException("Parameter type being referenced cannot be assigned here!"); + TypeWrapper parameterType = toCheck.getType(); + if (!parameterType.isAssignableTo(type)) { + throw new HandlerException("Parameter type being referenced cannot be assigned here!"); } else { return; } } - throw new UnsupportedOperationException("Parameter with name '" + annotation.value() + "' does not exist."); + throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist."); } @Override @@ -79,7 +79,7 @@ public final class MaxReferenceHandler { public AbstractTypeMapper getTypeMapper(Max.Reference maxReference, Parameter parameter, int index, DataReadable dataReadable, AbstractTypeMapper parentTypeMapper) { Class type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - Class finalType = type; + Handler.TypeWrapper finalType = new TypeWrapper.ForClass(type); String name = maxReference.value(); int compareValue = maxReference.inclusive() ? 0 : -1; @@ -119,7 +119,7 @@ public final class MaxReferenceHandler { public AbstractTypeValidator getValidator(Max.Reference maxReference, Parameter parameter, int index, DataReadable dataReadable) { Class type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - Class finalType = type; + Handler.TypeWrapper finalType = new TypeWrapper.ForClass(type); String name = maxReference.value(); int compareValue = maxReference.inclusive() ? 0 : -1; diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinHandler.java index 97ca3bbb..4b2c01bc 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinHandler.java @@ -32,19 +32,18 @@ import java.util.function.ToIntFunction; public final class MinHandler { public static final class Impl implements Handler.HandlerParameter { - @Override - public void check(Min min, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Min annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Min annotation cannot be used on first parameter"); + throw new HandlerException("Min annotation cannot be used on first parameter"); } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (parameter.isVarArgs()) type = type.getComponentType(); - if (type == int.class || type == Integer.class) return; - if (type == long.class || type == Long.class) return; - if (type == float.class || type == Float.class) return; - if (type == double.class || type == Double.class) return; - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable() + " is not a number."); + if (type.is(int.class) || type.is(Integer.class)) return; + 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."); } @Override @@ -58,7 +57,7 @@ public final class MinHandler { if (parameter.isVarArgs()) type = type.getComponentType(); int compareValue = min.inclusive() ? 0 : 1; - ToIntFunction comparator = CommandUtils.createComparator("Min", type, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue()); + ToIntFunction comparator = CommandUtils.createComparator("Min", new TypeWrapper.ForClass(type), min.intValue(), min.longValue(), min.floatValue(), min.doubleValue()); boolean onlyPositive = comparator.applyAsInt(0) < 0; Max max = parameter.getAnnotation(Max.class); @@ -130,7 +129,7 @@ public final class MinHandler { } int compareValue = min.inclusive() ? 0 : 1; - ToIntFunction comparator = CommandUtils.createComparator("Min", type, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue()); + ToIntFunction comparator = CommandUtils.createComparator("Min", new TypeWrapper.ForClass(type), min.intValue(), min.longValue(), min.floatValue(), min.doubleValue()); return (sender, value, messageSender) -> { if (value == null) return true; diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinReferenceHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinReferenceHandler.java index 3b0faaf0..34b2c1c7 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinReferenceHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/MinReferenceHandler.java @@ -36,20 +36,20 @@ public final class MinReferenceHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Min.Reference annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Min.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Min.Reference annotation cannot be used on first parameter"); + throw new HandlerException("Min.Reference annotation cannot be used on first parameter"); } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - if (type != int.class && type != Integer.class && type != long.class && type != Long.class && type != float.class && type != Float.class && type != double.class && type != Double.class) { - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable() + " is not a number."); + 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."); } - Parameter[] parameters = parameter.getDeclaringExecutable().getParameters(); + ParameterWrapper[] parameters = methodWrapper.getParameters(); for (int i = index - 1; i >= 1; i--) { - Parameter toCheck = parameters[i]; + ParameterWrapper toCheck = parameters[i]; Name name = toCheck.getAnnotation(Name.class); String parameterName; if (name == null) { @@ -60,14 +60,14 @@ public final class MinReferenceHandler { if (!parameterName.equals(annotation.value())) { continue; } - Class parameterType = toCheck.getType(); - if (!type.isAssignableFrom(parameterType)) { - throw new UnsupportedOperationException("Parameter type being referenced cannot be assigned here!"); + TypeWrapper parameterType = toCheck.getType(); + if (!parameterType.isAssignableTo(type)) { + throw new HandlerException("Parameter type being referenced cannot be assigned here!"); } else { return; } } - throw new UnsupportedOperationException("Parameter with name '" + annotation.value() + "' does not exist."); + throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist."); } @Override @@ -79,7 +79,7 @@ public final class MinReferenceHandler { public AbstractTypeMapper getTypeMapper(Min.Reference minReference, Parameter parameter, int index, DataReadable dataReadable, AbstractTypeMapper parentTypeMapper) { Class type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - Class finalType = type; + Handler.TypeWrapper finalType = new TypeWrapper.ForClass(type); String name = minReference.value(); int compareValue = minReference.inclusive() ? 0 : 1; @@ -119,7 +119,7 @@ public final class MinReferenceHandler { public AbstractTypeValidator getValidator(Min.Reference minReference, Parameter parameter, int index, DataReadable dataReadable) { Class type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - Class finalType = type; + Handler.TypeWrapper finalType = new TypeWrapper.ForClass(type); String name = minReference.value(); int compareValue = minReference.inclusive() ? 0 : 1; diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/OptionalValueHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/OptionalValueHandler.java index 722300d7..02ae0a1e 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/OptionalValueHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/OptionalValueHandler.java @@ -35,12 +35,12 @@ public final class OptionalValueHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(OptionalValue annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(OptionalValue annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("OptionalValue annotation cannot be used on the first parameter"); + throw new HandlerException("OptionalValue annotation cannot be used on the first parameter"); } if (parameter.isVarArgs() || parameter.getType().isArray()) { - throw new UnsupportedOperationException("OptionalValue annotation cannot be used on varargs or array parameters"); + throw new HandlerException("OptionalValue annotation cannot be used on varargs or array parameters"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegexHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegexHandler.java index 39b16ff7..a66d5e4e 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegexHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegexHandler.java @@ -31,12 +31,12 @@ public final class RegexHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Regex annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Regex annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Regex annotation cannot be used on first parameter"); + throw new HandlerException("Regex annotation cannot be used on first parameter"); } - if (parameter.getType() != String.class) { - throw new UnsupportedOperationException("Regex annotation cannot be used on String parameter"); + if (!parameter.getType().is(String.class)) { + throw new HandlerException("Regex annotation cannot be used on String parameter"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegisterHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegisterHandler.java index 03e26b5a..55b4c133 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegisterHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/RegisterHandler.java @@ -34,52 +34,55 @@ public final class RegisterHandler { public static final class Impl implements Handler.HandlerMethod { @Override - public void check(de.steamwar.command.annotations.Register annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(Register annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() == 0) { - throw new UnsupportedOperationException("Register method must have at least one parameter"); + throw new HandlerException("Register method must have at least one parameter"); } - if (method.getReturnType() != void.class) { - throw new UnsupportedOperationException("Register method must return void"); + if (!method.getReturnType().is(void.class)) { + throw new HandlerException("Register method must return void"); } - if (!dataCheckable.hasExecutorMapper(method.getParameterTypes()[0])) { - throw new UnsupportedOperationException("Register method first parameter must have a executor mapper registered"); + // 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"); + } } - Parameter[] parameters = method.getParameters(); + ParameterWrapper[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { - Parameter parameter = parameters[i]; - List annotationList = CommandUtils.getAnnotations(parameter); + ParameterWrapper parameter = parameters[i]; + List annotationList = parameter.getAnnotations(); if (annotationList.isEmpty()) { if (i == 0) { continue; } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (type.isArray()) { type = type.getComponentType(); } if (!type.isEnum() && !dataCheckable.hasMapper(type.getName())) { - throw new UnsupportedOperationException("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"); } } else { for (Annotation annotation1 : annotationList) { - getParameterHandler(annotation1).check(annotation1, parameter, i, dataCheckable); + getParameterHandler(annotation1).check(annotation1, method, parameter, i, dataCheckable); } } } } - public static HandlerParameter getParameterHandler(Annotation annotation) { + public static HandlerParameter getParameterHandler(Annotation annotation) throws HandlerException { Implementation handler = annotation.annotationType().getAnnotation(Implementation.class); Handler handlerObject; try { handlerObject = handler.value().getConstructor().newInstance(); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new UnsupportedOperationException("Handler " + handler.value().getName() + " cannot be used to check the argument validity", e); + throw new HandlerException("Handler " + handler.value().getName() + " cannot be used to check the argument validity"); } if (!(handlerObject instanceof HandlerParameter)) { - throw new UnsupportedOperationException("Handler " + handlerObject.getClass().getName() + " is not a HandlerParameter"); + throw new HandlerException("Handler " + handlerObject.getClass().getName() + " is not a HandlerParameter"); } return (HandlerParameter) handlerObject; } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StartsWithHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StartsWithHandler.java index 1cdeb6e0..39e39cf5 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StartsWithHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StartsWithHandler.java @@ -35,12 +35,12 @@ public final class StartsWithHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(StartsWith annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(StartsWith annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("StartsWith annotation cannot be used on first parameter"); + throw new HandlerException("StartsWith annotation cannot be used on first parameter"); } - if (parameter.getType() != String.class) { - throw new UnsupportedOperationException("StartsWith annotation cannot be used on String parameter"); + if (!parameter.getType().is(String.class)) { + throw new HandlerException("StartsWith annotation cannot be used on String parameter"); } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StaticValueHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StaticValueHandler.java index 3f0de9dd..4c07ed46 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StaticValueHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/StaticValueHandler.java @@ -34,16 +34,16 @@ public final class StaticValueHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(StaticValue annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(StaticValue annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("StaticValue annotation cannot be used on first parameter"); + throw new HandlerException("StaticValue annotation cannot be used on first parameter"); } - Class type = parameter.getType(); - if (type == String.class) return; - if (type == int.class || type == Integer.class) return; - if (type == long.class || type == Long.class) return; - if (type == boolean.class || type == Boolean.class) return; - throw new UnsupportedOperationException("StaticValue parameter must be String, int, long or boolean"); + 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"); } @Override diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/SupplierHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/SupplierHandler.java index fd203ac8..62160ec4 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/SupplierHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/SupplierHandler.java @@ -19,7 +19,6 @@ package de.steamwar.command.handler; -import de.steamwar.command.AbstractTypeMapper; import de.steamwar.command.AbstractTypeSupplier; import de.steamwar.command.Handler; import de.steamwar.command.annotations.AllowNull; @@ -36,26 +35,29 @@ public final class SupplierHandler { public static final class Impl implements Handler.HandlerMethod, Handler.HandlerParameter { @Override - public void check(Supplier annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(Supplier annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("Supplier method must have no parameters"); + throw new HandlerException("Supplier method must have no parameters"); } - if (!AbstractTypeSupplier.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("Supplier method must return AbstractTypeSupplier"); + if (!method.getReturnType().isAssignableTo(AbstractTypeSupplier.class)) { + throw new HandlerException("Supplier method must return AbstractTypeSupplier"); } if (annotation.value() != null && !annotation.value().isEmpty()) { return; } - Optional> genericType = getGenericTypeOfReturn(method); - if (annotation.type() == void.class) { - if (genericType.isEmpty()) { - throw new UnsupportedOperationException("Please supply a class type to the Supplier"); - } - } else { - if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { - throw new UnsupportedOperationException("Supplied type does not conform to actual type"); + // TODO: Implement! for AnnotationProcessor as well! + if (method instanceof MethodWrapper.ForMethod) { + Optional> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod()); + if (annotation.type() == void.class) { + if (genericType.isEmpty()) { + throw new UnsupportedOperationException("Please supply a class type to the Supplier"); + } + } else { + if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { + throw new UnsupportedOperationException("Supplied type does not conform to actual type"); + } } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/TabFilterHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/TabFilterHandler.java index 8c42ee1b..0b93ac90 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/TabFilterHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/TabFilterHandler.java @@ -40,9 +40,9 @@ public final class TabFilterHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(TabFilter annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(TabFilter annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("TabFilter annotation cannot be used on first parameter"); + throw new HandlerException("TabFilter annotation cannot be used on first parameter"); } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/UniqueHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/UniqueHandler.java index a659ed3b..4f410afb 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/UniqueHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/UniqueHandler.java @@ -36,12 +36,12 @@ public final class UniqueHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Unique annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Unique annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Unique annotation cannot be used on the first parameter"); + throw new HandlerException("Unique annotation cannot be used on the first parameter"); } if (!parameter.getType().isArray() && !parameter.isVarArgs()) { - throw new UnsupportedOperationException("Unique annotation cannot be used on non array types"); + throw new HandlerException("Unique annotation cannot be used on non array types"); } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValidatorHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValidatorHandler.java index ed1f3889..9d1dc80c 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValidatorHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValidatorHandler.java @@ -32,26 +32,29 @@ public final class ValidatorHandler { public static final class Impl implements Handler.HandlerMethod, Handler.HandlerParameter { @Override - public void check(Validator annotation, Method method, DataCheckable dataCheckable) throws Exception { + public void check(Validator annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException { if (method.getParameterCount() != 0) { - throw new UnsupportedOperationException("Validator method must have no parameters"); + throw new HandlerException("Validator method must have no parameters"); } - if (!AbstractTypeValidator.class.isAssignableFrom(method.getReturnType())) { - throw new UnsupportedOperationException("Validator method must return AbstractValidator"); + if (!method.getReturnType().isAssignableTo(AbstractTypeValidator.class)) { + throw new HandlerException("Validator method must return AbstractValidator"); } if (annotation.value() != null && !annotation.value().isEmpty()) { return; } - Optional> genericType = getGenericTypeOfReturn(method); - if (annotation.type() == void.class) { - if (genericType.isEmpty()) { - throw new UnsupportedOperationException("Please supply a class type to the Validator"); - } - } else { - if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { - throw new UnsupportedOperationException("Supplied type does not conform to actual type"); + // TODO: Implement! for AnnotationProcessor as well! + if (method instanceof MethodWrapper.ForMethod) { + Optional> genericType = getGenericTypeOfReturn(((MethodWrapper.ForMethod) method).getMethod()); + if (annotation.type() == void.class) { + if (genericType.isEmpty()) { + throw new HandlerException("Please supply a class type to the Validator"); + } + } else { + if (genericType.isPresent() && !annotation.type().isAssignableFrom(genericType.get())) { + throw new HandlerException("Supplied type does not conform to actual type"); + } } } } diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesHandler.java index 6a50d803..75536fcd 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesHandler.java @@ -33,16 +33,16 @@ public final class ValuesHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Values annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Values annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Values annotation cannot be used on first parameter"); + throw new HandlerException("Values annotation cannot be used on first parameter"); } - Class type = parameter.getType(); - if (type == String.class) return; - if (type == int.class || type == Integer.class) return; - if (type == long.class || type == Long.class) return; - if (type == boolean.class || type == Boolean.class) return; - throw new UnsupportedOperationException("Values parameter must be String, int, long or boolean"); + 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"); } @Override diff --git a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesReferenceHandler.java b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesReferenceHandler.java index 653e723d..b3543dd2 100644 --- a/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesReferenceHandler.java +++ b/CommandFramework/CommandFrameworkBase/src/de/steamwar/command/handler/ValuesReferenceHandler.java @@ -25,7 +25,6 @@ import de.steamwar.command.PreviousArguments; import de.steamwar.command.annotations.Name; import de.steamwar.command.annotations.Values; import de.steamwar.command.mapper.internal.DelegatingMapper; -import de.steamwar.command.utils.ClassEquality; import java.lang.reflect.Parameter; import java.util.Arrays; @@ -37,20 +36,20 @@ public class ValuesReferenceHandler { public static final class Impl implements Handler.HandlerParameter { @Override - public void check(Values.Reference annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { + public void check(Values.Reference annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException { if (index == 0) { - throw new UnsupportedOperationException("Values.Reference annotation cannot be used on first parameter"); + throw new HandlerException("Values.Reference annotation cannot be used on first parameter"); } - Class type = parameter.getType(); + TypeWrapper type = parameter.getType(); if (type.isArray()) type = type.getComponentType(); - if (type != int.class && type != Integer.class && type != long.class && type != Long.class && type != String.class) { - throw new UnsupportedOperationException("Parameter " + index + " of " + parameter.getDeclaringExecutable() + " is not a String or Int or Long."); + 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."); } - Parameter[] parameters = parameter.getDeclaringExecutable().getParameters(); + ParameterWrapper[] parameters = methodWrapper.getParameters(); for (int i = index - 1; i >= 1; i--) { - Parameter toCheck = parameters[i]; + ParameterWrapper toCheck = parameters[i]; Name name = toCheck.getAnnotation(Name.class); String parameterName; if (name == null) { @@ -61,15 +60,15 @@ public class ValuesReferenceHandler { if (!parameterName.equals(annotation.value())) { continue; } - Class toCheckType = toCheck.getType(); + TypeWrapper toCheckType = toCheck.getType(); if (toCheckType.isArray()) toCheckType = toCheckType.getComponentType(); - if (!ClassEquality.classEquals(type, toCheckType)) { - throw new UnsupportedOperationException("Parameter type being referenced cannot be assigned here!"); + if (!toCheckType.is(type)) { + throw new HandlerException("Parameter type being referenced cannot be assigned here!"); } else { return; } } - throw new UnsupportedOperationException("Parameter with name '" + annotation.value() + "' does not exist."); + throw new HandlerException("Parameter with name '" + annotation.value() + "' does not exist."); } @Override diff --git a/CommandFramework/CommandFrameworkTests/build.gradle.kts b/CommandFramework/CommandFrameworkTests/build.gradle.kts index dbe13757..448ba536 100644 --- a/CommandFramework/CommandFrameworkTests/build.gradle.kts +++ b/CommandFramework/CommandFrameworkTests/build.gradle.kts @@ -31,4 +31,6 @@ dependencies { testImplementation(libs.hamcrest) testImplementation(project(":CommandFramework:CommandFrameworkBase", "default")) + + testAnnotationProcessor(project(":CommandFramework:CommandFrameworkAnnotationProcessor", "default")) } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index edcca187..30329a4d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -190,6 +190,7 @@ include( include( "CommandFramework", "CommandFramework:CommandFrameworkBase", + "CommandFramework:CommandFrameworkAnnotationProcessor", "CommandFramework:CommandFrameworkSpigot", "CommandFramework:CommandFrameworkTests", "CommandFramework:CommandFrameworkVelocity",