feat: proper error handling

This commit is contained in:
zaaarf 2023-08-24 01:50:14 +02:00
parent 17398e89db
commit ca13fffd0e
No known key found for this signature in database
GPG key ID: 6445A5CD15E5B40C
3 changed files with 94 additions and 7 deletions

View file

@ -0,0 +1,52 @@
package ftbsc.geb.exceptions;
/**
* Thrown when there is something wrong with a listener method.
*/
public class BadListenerArgumentsException extends RuntimeException {
/**
* The constructor. It's not meant to be used as is, refer to the subclasses
* @param message the message to pass along to the superclass
*/
protected BadListenerArgumentsException(String message) {
super(message);
}
/**
* Thrown when the number of arguments is off.
*/
public static class Count extends BadListenerArgumentsException {
/**
* The public constructor.
* @param clazz the fully-qualified name of the parent class
* @param method the annotated listener method
* @param count the number of arguments found
*/
public Count(String clazz, String method, int count) {
super(String.format(
"An error occurred while evaluating method %s::%s: found %d arguments, expected 1!",
clazz, method, count));
}
}
/**
* Thrown when the argument is of the wrong type.
*/
public static class Type extends BadListenerArgumentsException {
/**
* The public constructor.
* @param clazz the fully-qualified name of the parent class
* @param method the annotated listener method
* @param parameterName the name of the parameter
*/
public Type(String clazz, String method, String parameterName) {
super(String.format(
"The parameter %s of %s::%s does not implement the IEvent interface!",
parameterName, clazz, method
));
}
}
}

View file

@ -0,0 +1,17 @@
package ftbsc.geb.exceptions;
/**
* Thrown when a parent of a listener method does not implement the
* appropriate interface,
*/
public class MissingInterfaceException extends RuntimeException {
/**
* The public constructor.
* @param clazz the fully-qualified name of the parent class
* @param method the annotated listener method
*/
public MissingInterfaceException(String clazz, String method) {
super(String.format("The parent of %s::%s does not implement the IListener interface!", clazz, method));
}
}

View file

@ -5,12 +5,16 @@ import ftbsc.geb.api.IEvent;
import ftbsc.geb.api.IEventDispatcher; import ftbsc.geb.api.IEventDispatcher;
import ftbsc.geb.api.IListener; import ftbsc.geb.api.IListener;
import ftbsc.geb.api.annotations.Listen; import ftbsc.geb.api.annotations.Listen;
import ftbsc.geb.exceptions.BadListenerArgumentsException;
import ftbsc.geb.exceptions.MissingInterfaceException;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.FileObject; import javax.tools.FileObject;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import javax.tools.StandardLocation; import javax.tools.StandardLocation;
@ -88,23 +92,37 @@ public class GEBProcessor extends AbstractProcessor {
* @param target the {@link Element} that was annotated with {@link Listen} * @param target the {@link Element} that was annotated with {@link Listen}
*/ */
private void processListener(Element target) { private void processListener(Element target) {
if(!(target instanceof ExecutableElement))
return; //TODO throw error
ExecutableElement listener = (ExecutableElement) target; //this cast will never fail ExecutableElement listener = (ExecutableElement) target; //this cast will never fail
//ensure the parent is instance of IListener //ensure the parent is instance of IListener
TypeMirror parentType = listener.getEnclosingElement().asType(); TypeMirror parentType = listener.getEnclosingElement().asType();
if(!this.processingEnv.getTypeUtils().isAssignable(parentType, this.listenerInterface)) if(!this.processingEnv.getTypeUtils().isAssignable(parentType, this.listenerInterface))
return; //TODO throw error, parent doesn't implement the interface throw new MissingInterfaceException(
listener.getEnclosingElement().getSimpleName().toString(),
listener.getSimpleName().toString());
//ensure the listener method has only a single IEvent parameter //ensure the listener method has only one parameter
List<? extends VariableElement> params = listener.getParameters(); List<? extends VariableElement> params = listener.getParameters();
if(listener.getParameters().size() != 1) if(listener.getParameters().size() != 1)
return; //TODO throw error, bad parameter amount throw new BadListenerArgumentsException.Count(
listener.getEnclosingElement().getSimpleName().toString(),
listener.getSimpleName().toString(),
params.size());
//ensure said parameter implements IEvent
TypeMirror event = params.get(0).asType(); TypeMirror event = params.get(0).asType();
if(!this.processingEnv.getTypeUtils().isAssignable(event, this.eventInterface)) if(!this.processingEnv.getTypeUtils().isAssignable(event, this.eventInterface))
return; //TODO throw error, bad parameter type throw new BadListenerArgumentsException.Type(
listener.getEnclosingElement().getSimpleName().toString(),
listener.getSimpleName().toString(),
params.get(0).getSimpleName().toString());
//warn about return type
if(!listener.getReturnType().getKind().equals(TypeKind.VOID))
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, String.format(
"The method %s::%s has a return type: please note that it will be ignored.",
listener.getEnclosingElement().getSimpleName().toString(),
listener.getSimpleName().toString()));
if(!this.listenerMap.containsKey(event)) if(!this.listenerMap.containsKey(event))
this.listenerMap.put(event, new HashSet<>()); this.listenerMap.put(event, new HashSet<>());