From ff35e7f37d9b1c0e56b07783de52df0757b5f228 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 17 Feb 2021 08:22:48 +0100 Subject: [PATCH] Fix several edge cases in EventProcessor When encountering an event handler with an invalid signature, the processor doesn't crash anymore. Also, event parameters that aren't objects are now reported as errors. --- README.md | 4 +- .../kske/eventbus/proc/EventProcessor.java | 54 ++++++++++++------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8666ba8..48845cd 100644 --- a/README.md +++ b/README.md @@ -157,9 +157,9 @@ If you intend to use event handlers that are inaccessible to Event Bus by means opens my.module to dev.kske.eventbus.core; ``` -## Compile-Time Error Checking with Event Bus AP +## Compile-Time Error Checking with Event Bus Proc -To assist you with writing event listeners, the Event Bus AP (Annotation Processor) module enforces correct usage of the `@Event` annotation during compile time. +To assist you with writing event listeners, the Event Bus Proc (Annotation Processor) module enforces correct usage of the `@Event` annotation during compile time. This reduces difficult-to-debug bugs that occur during runtime to compile-time errors which can be easily fixed. The event annotation processor detects invalid event handlers and event type issues with more to come in future versions. diff --git a/event-bus-proc/src/main/java/dev/kske/eventbus/proc/EventProcessor.java b/event-bus-proc/src/main/java/dev/kske/eventbus/proc/EventProcessor.java index f3ce505..19c670b 100644 --- a/event-bus-proc/src/main/java/dev/kske/eventbus/proc/EventProcessor.java +++ b/event-bus-proc/src/main/java/dev/kske/eventbus/proc/EventProcessor.java @@ -34,9 +34,10 @@ public class EventProcessor extends AbstractProcessor { private void processRound(Set eventHandlers) { for (ExecutableElement eventHandler : eventHandlers) { - Event eventAnnotation = eventHandler.getAnnotation(Event.class); + Event eventAnnotation = eventHandler.getAnnotation(Event.class); + TypeMirror eventType; - // Determine how the event type is defined + // Determine the event type and how it is defined boolean useParameter; try { eventAnnotation.value(); @@ -45,36 +46,49 @@ public class EventProcessor extends AbstractProcessor { } catch (MirroredTypeException e) { // Task failed successfully - useParameter = processingEnv.getTypeUtils().isSameType(e.getTypeMirror(), + eventType = e.getTypeMirror(); + useParameter = processingEnv.getTypeUtils().isSameType(eventType, getTypeMirror(Event.USE_PARAMETER.class)); } - // Check for correct method signature and return type - if (eventHandler.getParameters().size() == 0 && useParameter) + // Check handler signature + boolean pass = false; + if (useParameter && eventHandler.getParameters().size() == 0) error(eventHandler, "The method or the annotation must define the event type"); - - if (eventHandler.getParameters().size() == 1 && !useParameter) + else if (!useParameter && eventHandler.getParameters().size() == 1) error(eventHandler, "Either the method or the annotation must define the event type"); - - if (eventHandler.getParameters().size() > 1) + else if (eventHandler.getParameters().size() > 1) error(eventHandler, "Method must not have more than one parameter"); - - if (eventHandler.getReturnType().getKind() != TypeKind.VOID) + else if (eventHandler.getReturnType().getKind() != TypeKind.VOID) error(eventHandler, "Method must return void"); + else + pass = true; - // Get first parameter as type and element - var paramElement = eventHandler.getParameters().get(0); - var paramType = paramElement.asType(); + // Abort checking if the handler signature is incorrect + if (!pass) + continue; + + // Additional checks if parameter is used + if (useParameter) { + VariableElement paramElement = eventHandler.getParameters().get(0); + eventType = paramElement.asType(); + + // Check if parameter is object + // Abort checking otherwise + if (eventType.getKind() != TypeKind.DECLARED) { + error(paramElement, "Event must be an object"); + continue; + } + } // Check for handlers for abstract types that aren't polymorphic + Element eventElement = ((DeclaredType) eventType).asElement(); if (eventHandler.getAnnotation(Polymorphic.class) == null - && paramType.getKind() == TypeKind.DECLARED) { - var declaredElement = ((DeclaredType) paramType).asElement(); - if (declaredElement.getKind() == ElementKind.INTERFACE - || declaredElement.getModifiers().contains(Modifier.ABSTRACT)) - warning(paramElement, - "Parameter should be instantiable or handler should use @Polymorphic"); + && (eventElement.getKind() == ElementKind.INTERFACE + || eventElement.getModifiers().contains(Modifier.ABSTRACT))) { + warning(eventHandler, + "Parameter should be instantiable or handler should use @Polymorphic"); } } }