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.
This commit is contained in:
Kai S. K. Engelbart 2021-02-17 08:22:48 +01:00
parent 1dd9e05c38
commit ff35e7f37d
Signed by: kske
GPG Key ID: 8BEB13EC5DF7EF13
2 changed files with 36 additions and 22 deletions

View File

@ -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; 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. 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. The event annotation processor detects invalid event handlers and event type issues with more to come in future versions.

View File

@ -35,8 +35,9 @@ public class EventProcessor extends AbstractProcessor {
private void processRound(Set<ExecutableElement> eventHandlers) { private void processRound(Set<ExecutableElement> eventHandlers) {
for (ExecutableElement eventHandler : 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; boolean useParameter;
try { try {
eventAnnotation.value(); eventAnnotation.value();
@ -45,35 +46,48 @@ public class EventProcessor extends AbstractProcessor {
} catch (MirroredTypeException e) { } catch (MirroredTypeException e) {
// Task failed successfully // Task failed successfully
useParameter = processingEnv.getTypeUtils().isSameType(e.getTypeMirror(), eventType = e.getTypeMirror();
useParameter = processingEnv.getTypeUtils().isSameType(eventType,
getTypeMirror(Event.USE_PARAMETER.class)); getTypeMirror(Event.USE_PARAMETER.class));
} }
// Check for correct method signature and return type // Check handler signature
if (eventHandler.getParameters().size() == 0 && useParameter) boolean pass = false;
if (useParameter && eventHandler.getParameters().size() == 0)
error(eventHandler, "The method or the annotation must define the event type"); error(eventHandler, "The method or the annotation must define the event type");
else if (!useParameter && eventHandler.getParameters().size() == 1)
if (eventHandler.getParameters().size() == 1 && !useParameter)
error(eventHandler, error(eventHandler,
"Either the method or the annotation must define the event type"); "Either the method or the annotation must define the event type");
else if (eventHandler.getParameters().size() > 1)
if (eventHandler.getParameters().size() > 1)
error(eventHandler, "Method must not have more than one parameter"); error(eventHandler, "Method must not have more than one parameter");
else if (eventHandler.getReturnType().getKind() != TypeKind.VOID)
if (eventHandler.getReturnType().getKind() != TypeKind.VOID)
error(eventHandler, "Method must return void"); error(eventHandler, "Method must return void");
else
pass = true;
// Get first parameter as type and element // Abort checking if the handler signature is incorrect
var paramElement = eventHandler.getParameters().get(0); if (!pass)
var paramType = paramElement.asType(); 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 // Check for handlers for abstract types that aren't polymorphic
Element eventElement = ((DeclaredType) eventType).asElement();
if (eventHandler.getAnnotation(Polymorphic.class) == null if (eventHandler.getAnnotation(Polymorphic.class) == null
&& paramType.getKind() == TypeKind.DECLARED) { && (eventElement.getKind() == ElementKind.INTERFACE
var declaredElement = ((DeclaredType) paramType).asElement(); || eventElement.getModifiers().contains(Modifier.ABSTRACT))) {
if (declaredElement.getKind() == ElementKind.INTERFACE warning(eventHandler,
|| declaredElement.getModifiers().contains(Modifier.ABSTRACT))
warning(paramElement,
"Parameter should be instantiable or handler should use @Polymorphic"); "Parameter should be instantiable or handler should use @Polymorphic");
} }
} }