forked from SteamWar/SteamWar
Add Annotation Processor for compile time checks
This commit is contained in:
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
steamwar.java
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":CommandFramework:CommandFrameworkBase", "default"))
|
||||
annotationProcessor(project(":CommandFramework:CommandFrameworkBase", "default"))
|
||||
}
|
||||
+5
@@ -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
|
||||
+65
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends VariableElement> 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;
|
||||
}
|
||||
}
|
||||
+107
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
+77
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> annotation) {
|
||||
return parameter.getAnnotation(annotation) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
|
||||
return parameter.getAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return parameter.getSimpleName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> getAnnotations() {
|
||||
parameter.getAnnotationMirrors().forEach(annotationMirror -> {
|
||||
System.out.println(annotationMirror);
|
||||
});
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+176
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> 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<String> getSupportedAnnotationTypes() {
|
||||
return Collections.singleton(this.getAnnotationClass().getCanonicalName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
List<ExecutableElement> 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<? extends VariableElement> 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<? extends Annotation>) 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> getAnnotationClass() {
|
||||
return Cached.class;
|
||||
}
|
||||
}
|
||||
+33
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> getAnnotationClass() {
|
||||
return Mapper.class;
|
||||
}
|
||||
}
|
||||
+33
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> getAnnotationClass() {
|
||||
return Register.class;
|
||||
}
|
||||
}
|
||||
+33
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> getAnnotationClass() {
|
||||
return Supplier.class;
|
||||
}
|
||||
}
|
||||
+33
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<? extends Annotation> getAnnotationClass() {
|
||||
return Validator.class;
|
||||
}
|
||||
}
|
||||
@@ -132,14 +132,14 @@ public class CommandUtils {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public static ToIntFunction<Number> createComparator(String type, Class<?> clazz, int iValue, long lValue, float fValue, double dValue) {
|
||||
if (clazz == int.class || clazz == Integer.class) {
|
||||
public static ToIntFunction<Number> 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);
|
||||
|
||||
@@ -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<? extends Handler> 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);
|
||||
|
||||
<A, B> AbstractTypeMapper<A, B> getMapper(String key);
|
||||
|
||||
<A, B> AbstractTypeValidator<A, B> getValidator(String key);
|
||||
|
||||
<A, B> AbstractTypeSupplier<A, B> getSupplier(String key);
|
||||
}
|
||||
|
||||
@@ -76,17 +92,26 @@ public interface Handler {
|
||||
Function<?, ?> getExecutorMapper(Class<?> clazz);
|
||||
|
||||
<A, B> void addMapper(String key, boolean local, AbstractTypeMapper<A, B> mapper);
|
||||
|
||||
<A, B> void addValidator(String key, boolean local, AbstractTypeValidator<A, B> validator);
|
||||
|
||||
<A, B> void addSupplier(String key, boolean local, AbstractTypeSupplier<A, B> supplier);
|
||||
|
||||
/**
|
||||
* Invoking the same method twice will result in the exact same result.
|
||||
*/
|
||||
<T> T invoke(Method method);
|
||||
|
||||
void addCommand(Method method, String[] subCommand, String[] description, boolean noTabComplete);
|
||||
}
|
||||
|
||||
interface HandlerMethod<T extends Annotation> 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<T extends Annotation, A, B> 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<? extends Annotation> annotation);
|
||||
|
||||
<A extends Annotation> A getAnnotation(Class<A> annotation);
|
||||
|
||||
String getName();
|
||||
|
||||
List<Annotation> 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<? extends Annotation> annotation) {
|
||||
return parameter.isAnnotationPresent(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
|
||||
return parameter.getAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return parameter.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -31,12 +31,12 @@ public final class CachedHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<Cached> {
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -31,12 +31,12 @@ public final class ClassMapperHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<ClassMapper> {
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -31,12 +31,12 @@ public final class ClassValidatorHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<ClassValidator> {
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-14
@@ -32,26 +32,29 @@ public final class MapperHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<Mapper>, Handler.HandlerParameter<Mapper, Object, Object> {
|
||||
|
||||
@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<Class<?>> 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<Class<?>> 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");
|
||||
|
||||
+13
-13
@@ -34,15 +34,15 @@ public final class MaxHandler {
|
||||
public static final class Impl implements Handler.HandlerParameter<Max, Object, Number> {
|
||||
|
||||
@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<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 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<Number> comparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue());
|
||||
ToIntFunction<Number> 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<Number> comparator = CommandUtils.createComparator("Max", type, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue());
|
||||
ToIntFunction<Number> 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;
|
||||
|
||||
+13
-13
@@ -36,20 +36,20 @@ public final class MaxReferenceHandler {
|
||||
public static final class Impl implements Handler.HandlerParameter<Max.Reference, Object, Number> {
|
||||
|
||||
@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<Object, Number> getTypeMapper(Max.Reference maxReference, Parameter parameter, int index, DataReadable dataReadable, AbstractTypeMapper<Object, Number> 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<Object, Number> 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;
|
||||
|
||||
+10
-11
@@ -32,19 +32,18 @@ import java.util.function.ToIntFunction;
|
||||
public final class MinHandler {
|
||||
|
||||
public static final class Impl implements Handler.HandlerParameter<Min, Object, Number> {
|
||||
|
||||
@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<Number> comparator = CommandUtils.createComparator("Min", type, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue());
|
||||
ToIntFunction<Number> 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<Number> comparator = CommandUtils.createComparator("Min", type, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue());
|
||||
ToIntFunction<Number> 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;
|
||||
|
||||
+13
-13
@@ -36,20 +36,20 @@ public final class MinReferenceHandler {
|
||||
public static final class Impl implements Handler.HandlerParameter<Min.Reference, Object, Number> {
|
||||
|
||||
@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<Object, Number> getTypeMapper(Min.Reference minReference, Parameter parameter, int index, DataReadable dataReadable, AbstractTypeMapper<Object, Number> 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<Object, Number> 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;
|
||||
|
||||
+3
-3
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-15
@@ -34,52 +34,55 @@ public final class RegisterHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<Register> {
|
||||
|
||||
@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<Annotation> annotationList = CommandUtils.getAnnotations(parameter);
|
||||
ParameterWrapper parameter = parameters[i];
|
||||
List<Annotation> 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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -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, 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
|
||||
|
||||
+15
-13
@@ -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<Supplier>, Handler.HandlerParameter<Supplier, Object, Object> {
|
||||
|
||||
@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<Class<?>> 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<Class<?>> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -32,26 +32,29 @@ public final class ValidatorHandler {
|
||||
public static final class Impl implements Handler.HandlerMethod<Validator>, Handler.HandlerParameter<Validator, Object, Object> {
|
||||
|
||||
@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<Class<?>> 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<Class<?>> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -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, 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
|
||||
|
||||
+11
-12
@@ -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<Values.Reference, Object, Object> {
|
||||
|
||||
@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
|
||||
|
||||
@@ -31,4 +31,6 @@ dependencies {
|
||||
testImplementation(libs.hamcrest)
|
||||
|
||||
testImplementation(project(":CommandFramework:CommandFrameworkBase", "default"))
|
||||
|
||||
testAnnotationProcessor(project(":CommandFramework:CommandFrameworkAnnotationProcessor", "default"))
|
||||
}
|
||||
@@ -190,6 +190,7 @@ include(
|
||||
include(
|
||||
"CommandFramework",
|
||||
"CommandFramework:CommandFrameworkBase",
|
||||
"CommandFramework:CommandFrameworkAnnotationProcessor",
|
||||
"CommandFramework:CommandFrameworkSpigot",
|
||||
"CommandFramework:CommandFrameworkTests",
|
||||
"CommandFramework:CommandFrameworkVelocity",
|
||||
|
||||
Reference in New Issue
Block a user