forked from SteamWar/SteamWar
Improve error messages
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.command;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class HandlerForAnnotationMirror<A extends Annotation> implements Handler.AnnotationWrapper<A> {
|
||||
|
||||
private A annotation;
|
||||
|
||||
@Getter
|
||||
private AnnotationMirror annotationMirror;
|
||||
|
||||
public HandlerForAnnotationMirror(A annotation, AnnotationMirror annotationMirror) {
|
||||
this.annotation = annotation;
|
||||
this.annotationMirror = annotationMirror;
|
||||
}
|
||||
|
||||
@Override
|
||||
public A getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
+3
@@ -19,6 +19,8 @@
|
||||
|
||||
package de.steamwar.command;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.util.Elements;
|
||||
@@ -27,6 +29,7 @@ import java.util.List;
|
||||
|
||||
public class HandlerForExecutableElement implements Handler.MethodWrapper {
|
||||
|
||||
@Getter
|
||||
private final ExecutableElement method;
|
||||
private final Types types;
|
||||
private final Elements elements;
|
||||
|
||||
+63
-42
@@ -19,6 +19,9 @@
|
||||
|
||||
package de.steamwar.command;
|
||||
|
||||
import de.steamwar.command.utils.Pair;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.util.Elements;
|
||||
@@ -26,12 +29,15 @@ import javax.lang.model.util.Types;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HandlerForVariableElement implements Handler.ParameterWrapper {
|
||||
|
||||
@Getter
|
||||
private final VariableElement parameter;
|
||||
private final Types types;
|
||||
private final Elements elements;
|
||||
@@ -60,8 +66,14 @@ public class HandlerForVariableElement implements Handler.ParameterWrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotation) {
|
||||
return parameter.getAnnotation(annotation);
|
||||
public <A extends Annotation> Handler.AnnotationWrapper<A> getAnnotation(Class<A> annotation) {
|
||||
A ann = parameter.getAnnotation(annotation);
|
||||
AnnotationMirror annMirror = parameter.getAnnotationMirrors()
|
||||
.stream()
|
||||
.filter(am -> new HandlerForTypeMirror(am.getAnnotationType(), types, elements).is(annotation))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
return new HandlerForAnnotationMirror<>(ann, annMirror);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,44 +82,53 @@ public class HandlerForVariableElement implements Handler.ParameterWrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> getAnnotations() {
|
||||
List<Annotation> annotations = new ArrayList<>();
|
||||
for (AnnotationMirror annotationMirror : parameter.getAnnotationMirrors()) {
|
||||
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
|
||||
if (clazz == null) continue;
|
||||
annotations.add(parameter.getAnnotation((Class<? extends Annotation>) clazz));
|
||||
}
|
||||
List<Annotation> annotationList = new ArrayList<>();
|
||||
for (Annotation annotation : annotations) {
|
||||
try {
|
||||
Method method = annotation.annotationType().getMethod("value");
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!returnType.isArray()) {
|
||||
annotationList.add(annotation);
|
||||
continue;
|
||||
}
|
||||
Class<?> innerReturnType = returnType.getComponentType();
|
||||
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
|
||||
annotationList.add(annotation);
|
||||
continue;
|
||||
}
|
||||
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
|
||||
Class<? extends Annotation> containerType = repeatable.value();
|
||||
if (containerType == returnType) {
|
||||
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
|
||||
}
|
||||
try {
|
||||
Annotation[] innerAnnotations = (Annotation[]) method.invoke(annotation);
|
||||
Collections.addAll(annotationList, innerAnnotations);
|
||||
} catch (Exception e) {
|
||||
annotationList.add(annotation);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
annotationList.add(annotation);
|
||||
}
|
||||
}
|
||||
annotationList.removeIf(annotation -> !annotation.annotationType().isAnnotationPresent(Handler.Implementation.class));
|
||||
return annotationList;
|
||||
public List<Handler.AnnotationWrapper<?>> getAnnotations() {
|
||||
return parameter.getAnnotationMirrors()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Function.identity(), annotationMirror -> {
|
||||
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
|
||||
if (clazz == null) return null;
|
||||
return parameter.getAnnotation((Class<? extends Annotation>) clazz);
|
||||
}))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> entry.getValue() != null)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
|
||||
Annotation annotation = entry.getValue();
|
||||
try {
|
||||
Method method = annotation.annotationType().getMethod("value");
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!returnType.isArray()) {
|
||||
return List.of(annotation);
|
||||
}
|
||||
Class<?> innerReturnType = returnType.getComponentType();
|
||||
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
|
||||
return List.of(annotation);
|
||||
}
|
||||
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
|
||||
Class<? extends Annotation> containerType = repeatable.value();
|
||||
if (containerType == returnType) {
|
||||
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
|
||||
}
|
||||
try {
|
||||
return Arrays.asList((Annotation[]) method.invoke(annotation));
|
||||
} catch (Exception e) {
|
||||
return List.of(annotation);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
return List.of(annotation);
|
||||
}
|
||||
}))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.flatMap(entry -> {
|
||||
return entry.getValue()
|
||||
.stream()
|
||||
.map(annotation -> new Pair<AnnotationMirror, Annotation>(entry.getKey(), annotation));
|
||||
})
|
||||
.filter(pair -> pair.b.annotationType().isAnnotationPresent(Handler.Implementation.class))
|
||||
.map(pair -> new HandlerForAnnotationMirror<>(pair.b, pair.a))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Class<?> getClass(String name) {
|
||||
|
||||
+27
-6
@@ -20,22 +20,22 @@
|
||||
package de.steamwar.command.annotationprocessor;
|
||||
|
||||
import de.steamwar.command.Handler;
|
||||
import de.steamwar.command.HandlerForAnnotationMirror;
|
||||
import de.steamwar.command.HandlerForExecutableElement;
|
||||
import de.steamwar.command.HandlerForVariableElement;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -102,9 +102,30 @@ public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
|
||||
}
|
||||
Handler.HandlerMethod handlerMethod = (Handler.HandlerMethod) handler;
|
||||
try {
|
||||
handlerMethod.check(annotation, new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE);
|
||||
handlerMethod.check(new HandlerForAnnotationMirror(annotation, null), new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE);
|
||||
} catch (Handler.HandlerException e) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), method);
|
||||
Handler.CodePlace codePlace = e.getCodePlace();
|
||||
AnnotationMirror[] annotationMirrors = new AnnotationMirror[0];
|
||||
if (codePlace.getAnnotations().length > 0) {
|
||||
annotationMirrors = Arrays.stream(codePlace.getAnnotations())
|
||||
.map(annotationWrapper -> (HandlerForAnnotationMirror) annotationWrapper)
|
||||
.map(HandlerForAnnotationMirror::getAnnotationMirror)
|
||||
.toArray(AnnotationMirror[]::new);
|
||||
}
|
||||
Element element = null;
|
||||
if (codePlace.getMethod() != null) {
|
||||
element = ((HandlerForExecutableElement) codePlace.getMethod()).getMethod();
|
||||
} else if (codePlace.getParameter() != null) {
|
||||
element = ((HandlerForVariableElement) codePlace.getParameter()).getParameter();
|
||||
}
|
||||
|
||||
if (annotationMirrors.length > 0) {
|
||||
for (int i = 0; i < annotationMirrors.length; i++) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element, annotationMirrors[i]);
|
||||
}
|
||||
} else {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user