Fix MapperHandler, SupplierHandler, ValidatorHandler

Improve HandlerForVariableElement.getAnnotations()
Improve HandlerForTypeMirror.isEnum
Add HandlerForTypeMirror.getTypeName
This commit is contained in:
2025-11-23 21:14:09 +01:00
parent b6bad4e78e
commit ef61cf455d
7 changed files with 69 additions and 29 deletions
@@ -19,7 +19,10 @@
package de.steamwar.command; package de.steamwar.command;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.ArrayType; import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
@@ -64,8 +67,14 @@ public class HandlerForTypeMirror implements Handler.TypeWrapper {
@Override @Override
public boolean isEnum() { public boolean isEnum() {
System.out.println(type); if (type.getKind() != TypeKind.DECLARED) {
return false; return false;
}
DeclaredType declaredType = (DeclaredType) type;
Element element = declaredType.asElement();
return element.getKind() == ElementKind.ENUM;
} }
@Override @Override
@@ -104,4 +113,9 @@ public class HandlerForTypeMirror implements Handler.TypeWrapper {
public String getName() { public String getName() {
return type.toString(); return type.toString();
} }
@Override
public String getTypeName() {
return type.toString();
}
} }
@@ -24,8 +24,9 @@ import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -74,10 +75,39 @@ public class HandlerForVariableElement implements Handler.ParameterWrapper {
for (AnnotationMirror annotationMirror : parameter.getAnnotationMirrors()) { for (AnnotationMirror annotationMirror : parameter.getAnnotationMirrors()) {
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString()); Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
if (clazz == null) continue; if (clazz == null) continue;
annotations.addAll(Arrays.asList(parameter.getAnnotationsByType((Class<? extends Annotation>) clazz))); annotations.add(parameter.getAnnotation((Class<? extends Annotation>) clazz));
} }
annotations.removeIf(annotation -> !annotation.annotationType().isAnnotationPresent(Handler.Implementation.class)); List<Annotation> annotationList = new ArrayList<>();
return annotations; for (Annotation annotation : annotations) {
try {
Method method = annotation.annotationType().getMethod("value");
Class<?> returnType = method.getReturnType();
if (!returnType.isArray()) {
annotationList.add(annotation);
continue;
}
Class<?> innerReturnType = returnType.getComponentType();
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
annotationList.add(annotation);
continue;
}
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
Class<? extends Annotation> containerType = repeatable.value();
if (containerType == returnType) {
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
}
try {
Annotation[] innerAnnotations = (Annotation[]) method.invoke(annotation);
Collections.addAll(annotationList, innerAnnotations);
} catch (Exception e) {
annotationList.add(annotation);
}
} catch (NoSuchMethodException e) {
annotationList.add(annotation);
}
}
annotationList.removeIf(annotation -> !annotation.annotationType().isAnnotationPresent(Handler.Implementation.class));
return annotationList;
} }
private Class<?> getClass(String name) { private Class<?> getClass(String name) {
@@ -185,7 +185,7 @@ public abstract class AbstractCommand<T> {
handlerMap.get(runPriority).forEach((dataMethodAnnotationTriple, handlerMethods) -> { handlerMap.get(runPriority).forEach((dataMethodAnnotationTriple, handlerMethods) -> {
handlerMethods.forEach(annotationHandlerMethod -> { handlerMethods.forEach(annotationHandlerMethod -> {
try { try {
annotationHandlerMethod.check(dataMethodAnnotationTriple.c, dataMethodAnnotationTriple.b, dataMethodAnnotationTriple.a); annotationHandlerMethod.check(dataMethodAnnotationTriple.c, new Handler.MethodWrapper.ForMethod(dataMethodAnnotationTriple.b), dataMethodAnnotationTriple.a);
} catch (Exception e) { } catch (Exception e) {
throw new UnsupportedOperationException("Method check failed for " + dataMethodAnnotationTriple.b.getName(), e); throw new UnsupportedOperationException("Method check failed for " + dataMethodAnnotationTriple.b.getName(), e);
} }
@@ -106,12 +106,7 @@ public interface Handler {
} }
interface HandlerMethod<T extends Annotation> extends Handler { interface HandlerMethod<T extends Annotation> extends Handler {
default void check(T annotation, Method method, DataCheckable dataCheckable) throws Exception { void check(T annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException;
check(annotation, new MethodWrapper.ForMethod(method), dataCheckable);
}
default void check(T annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException {
}
int getRunPriority(); int getRunPriority();
@@ -119,12 +114,7 @@ public interface Handler {
} }
interface HandlerParameter<T extends Annotation, A, B> extends Handler { interface HandlerParameter<T extends Annotation, A, B> extends Handler {
default void check(T annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { void check(T annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException;
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() { default boolean needsParentTypeMapper() {
return false; return false;
@@ -263,6 +253,8 @@ public interface Handler {
String getName(); String getName();
String getTypeName();
class ForClass implements TypeWrapper { class ForClass implements TypeWrapper {
@Getter @Getter
private final Class<?> clazz; private final Class<?> clazz;
@@ -321,6 +313,11 @@ public interface Handler {
public String getName() { public String getName() {
return this.clazz.getName(); return this.clazz.getName();
} }
@Override
public String getTypeName() {
return this.clazz.getTypeName();
}
} }
} }
} }
@@ -82,7 +82,7 @@ public final class MapperHandler {
throw new HandlerException("Mapper annotation cannot be used on first parameter"); throw new HandlerException("Mapper annotation cannot be used on first parameter");
} }
if (!dataCheckable.hasMapper(annotation.value())) { if (!dataCheckable.hasMapper(annotation.value())) {
throw new UnsupportedOperationException("Mapper '" + annotation.value() + "' not found"); throw new HandlerException("Mapper '" + annotation.value() + "' not found");
} }
} }
@@ -26,8 +26,6 @@ import de.steamwar.command.annotations.Name;
import de.steamwar.command.annotations.Supplier; import de.steamwar.command.annotations.Supplier;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
public final class SupplierHandler { public final class SupplierHandler {
@@ -80,21 +78,22 @@ public final class SupplierHandler {
} }
@Override @Override
public void check(Supplier annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { public void check(Supplier annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
if (index == 0) { if (index == 0) {
throw new UnsupportedOperationException("Supplier annotation cannot be used on the first parameter"); throw new HandlerException("Supplier annotation cannot be used on the first parameter");
} }
String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName(); String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName();
if (!dataCheckable.hasSupplier(s)) { if (!dataCheckable.hasSupplier(s)) {
throw new UnsupportedOperationException("Supplier '" + annotation.value() + "' not found"); throw new HandlerException("Supplier '" + annotation.value() + "' not found");
} }
boolean hasDisallowedAnnotations = Arrays.stream(parameter.getAnnotations()) boolean hasDisallowedAnnotations = parameter.getAnnotations()
.stream()
.filter(anno -> !(anno instanceof Supplier)) .filter(anno -> !(anno instanceof Supplier))
.filter(anno -> !(anno instanceof AllowNull)) .filter(anno -> !(anno instanceof AllowNull))
.filter(anno -> !(anno instanceof Name)) .filter(anno -> !(anno instanceof Name))
.anyMatch(anno -> anno.getClass().isAnnotationPresent(Implementation.class)); .anyMatch(anno -> anno.getClass().isAnnotationPresent(Implementation.class));
if (hasDisallowedAnnotations) { if (hasDisallowedAnnotations) {
throw new UnsupportedOperationException("Only AllowNull or Name can be used in conjunction with Supplier annotation"); throw new HandlerException("Only AllowNull or Name can be used in conjunction with Supplier annotation");
} }
} }
} }
@@ -77,10 +77,10 @@ public final class ValidatorHandler {
} }
@Override @Override
public void check(Validator annotation, Parameter parameter, int index, DataCheckable dataCheckable) throws Exception { public void check(Validator annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException {
String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName(); String s = annotation.value() != null && !annotation.value().isEmpty() ? annotation.value() : parameter.getType().getTypeName();
if (!dataCheckable.hasValidator(s)) { if (!dataCheckable.hasValidator(s)) {
throw new UnsupportedOperationException("Validator '" + annotation.value() + "' not found"); throw new HandlerException("Validator '" + annotation.value() + "' not found");
} }
} }