From 023acb917208b9b0be59e8d9238b3716bf86e562 Mon Sep 17 00:00:00 2001 From: kske Date: Sun, 14 Feb 2021 14:34:19 +0100 Subject: [PATCH] Add simple annotation processor, generate shaded processor JAR --- event-bus-ap/pom.xml | 26 +++++++ .../dev/kske/eventbus/ap/EventProcessor.java | 78 +++++++++++++++++++ .../dev/kske/eventbus/ap/package-info.java | 7 ++ event-bus-ap/src/main/java/module-info.java | 12 +++ .../javax.annotation.processing.Processor | 1 + 5 files changed, 124 insertions(+) create mode 100644 event-bus-ap/src/main/java/dev/kske/eventbus/ap/EventProcessor.java create mode 100644 event-bus-ap/src/main/java/dev/kske/eventbus/ap/package-info.java create mode 100644 event-bus-ap/src/main/java/module-info.java create mode 100644 event-bus-ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/event-bus-ap/pom.xml b/event-bus-ap/pom.xml index 4b0ec76..e2e253f 100644 --- a/event-bus-ap/pom.xml +++ b/event-bus-ap/pom.xml @@ -27,5 +27,31 @@ + + + maven-compiler-plugin + + -proc:none + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + true + + + + + + \ No newline at end of file diff --git a/event-bus-ap/src/main/java/dev/kske/eventbus/ap/EventProcessor.java b/event-bus-ap/src/main/java/dev/kske/eventbus/ap/EventProcessor.java new file mode 100644 index 0000000..6fb5da3 --- /dev/null +++ b/event-bus-ap/src/main/java/dev/kske/eventbus/ap/EventProcessor.java @@ -0,0 +1,78 @@ +package dev.kske.eventbus.ap; + +import java.util.Set; + +import javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; + +import dev.kske.eventbus.core.*; + +/** + * This annotation processor checks event handlers for common mistakes which can only be detected + * during runtime otherwise. + * + * @author Kai S. K. Engelbart + * @since 1.0.0 + */ +@SupportedAnnotationTypes("dev.kske.eventbus.core.Event") +@SupportedSourceVersion(SourceVersion.RELEASE_11) +public class EventProcessor extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(Event.class)) { + ExecutableElement method = (ExecutableElement) annotatedElement; + Event eventAnnotation = method.getAnnotation(Event.class); + boolean useParameter = false; + + // Determine how the event type is defined + try { + eventAnnotation.eventType(); + } catch (MirroredTypeException e) { + + // Task failed successfully + useParameter = processingEnv.getTypeUtils().isSameType(e.getTypeMirror(), + processingEnv.getElementUtils() + .getTypeElement(Event.USE_PARAMETER.class.getCanonicalName()).asType()); + } + + // Check for correct method signature and return type + if (method.getParameters().size() == 0 && useParameter) + error(method, "The method or the annotation should define the event type"); + + if (method.getParameters().size() == 1 && !useParameter) + error(method, "Either the method or the annotation should define the event type"); + + if (method.getParameters().size() > 1) + error(method, "Method should not have more than one parameter"); + + if (!method.getReturnType().getKind().equals(TypeKind.VOID)) + error(method, "Method needs a return type of void"); + + // Check event type + var paramType = ((ExecutableType) method.asType()).getParameterTypes().get(0); + if (useParameter && !processingEnv.getTypeUtils().isAssignable(paramType, + processingEnv.getElementUtils() + .getTypeElement(IEvent.class.getCanonicalName()).asType())) + error(method.getParameters().get(0), "Parameter should implement IEvent"); + + // Check listener for interface implementation + if (!((TypeElement) method.getEnclosingElement()).getInterfaces().contains(processingEnv + .getElementUtils().getTypeElement(EventListener.class.getCanonicalName()).asType())) + warning(method.getEnclosingElement(), + "Class should implement EventListener interface"); + } + return true; + } + + private void warning(Element e, String msg, Object... args) { + processingEnv.getMessager().printMessage(Kind.WARNING, String.format(msg, args), e); + } + + private void error(Element e, String msg, Object... args) { + processingEnv.getMessager().printMessage(Kind.ERROR, String.format(msg, args), e); + } +} diff --git a/event-bus-ap/src/main/java/dev/kske/eventbus/ap/package-info.java b/event-bus-ap/src/main/java/dev/kske/eventbus/ap/package-info.java new file mode 100644 index 0000000..3a09965 --- /dev/null +++ b/event-bus-ap/src/main/java/dev/kske/eventbus/ap/package-info.java @@ -0,0 +1,7 @@ +/** + * Contains the Event Bus annotation processor. + * + * @author Kai S. K. Engelbart + * @since 1.0.0 + */ +package dev.kske.eventbus.ap; diff --git a/event-bus-ap/src/main/java/module-info.java b/event-bus-ap/src/main/java/module-info.java new file mode 100644 index 0000000..e09c4be --- /dev/null +++ b/event-bus-ap/src/main/java/module-info.java @@ -0,0 +1,12 @@ +/** + * Contains an annotation processor for checking for errors related to the + * {@link dev.kske.eventbus.core.Event} annotation from Event Bus. + * + * @author Kai S. K. Engelbart + * @since 1.0.0 + */ +module dev.kske.eventbus.ap { + + requires java.compiler; + requires dev.kske.eventbus.core; +} diff --git a/event-bus-ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/event-bus-ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..13befff --- /dev/null +++ b/event-bus-ap/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +dev.kske.eventbus.ap.EventProcessor \ No newline at end of file