From c5ef196aac41b6b9198c22432a07e38a3ae365ea Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 22 Aug 2023 11:14:17 +0200 Subject: [PATCH] feat: basic listener processing --- .../ftbsc/geb/processor/GEBProcessor.java | 84 +++++++++++++++++++ .../gradle/incremental.annotation.processors | 1 + .../javax.annotation.processing.Processor | 1 + 3 files changed, 86 insertions(+) create mode 100644 src/main/java/ftbsc/geb/processor/GEBProcessor.java create mode 100644 src/main/resources/META-INF/gradle/incremental.annotation.processors create mode 100644 src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/src/main/java/ftbsc/geb/processor/GEBProcessor.java b/src/main/java/ftbsc/geb/processor/GEBProcessor.java new file mode 100644 index 0000000..c72bf8c --- /dev/null +++ b/src/main/java/ftbsc/geb/processor/GEBProcessor.java @@ -0,0 +1,84 @@ +package ftbsc.geb.processor; + +import ftbsc.geb.api.annotations.Event; +import ftbsc.geb.api.annotations.Listen; +import ftbsc.geb.api.annotations.ListenerInstance; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +@SupportedAnnotationTypes({"ftbsc.geb.api.annotations.*"}) +public class GEBProcessor extends AbstractProcessor { + @Override + public boolean process(Set set, RoundEnvironment env) { + boolean claimed = false; + for(TypeElement ann : set) { + BiConsumer processMethod; + if(ann.getQualifiedName().contentEquals(Listen.class.getName())) + processMethod = GEBProcessor::processListener; + else if(ann.getQualifiedName().contentEquals(Event.class.getName())) + processMethod = GEBProcessor::processEvent; + else continue; + + claimed = true; + + for(Element e : env.getElementsAnnotatedWith(ann)) + processMethod.accept(this, e); + } + return claimed; + } + + private final Map> listeners = new HashMap<>(); + + private static List getMembersAnnotatedWith(TypeElement typeElement, Class ann) { + return typeElement.getEnclosedElements() + .stream() + .filter(elem -> elem.getAnnotation(ann) != null) + .collect(Collectors.toList()); + } + + private void processListener(Element target) { + ExecutableElement listener = (ExecutableElement) target; //this will never fail + Listen listenerAnn = target.getAnnotation(Listen.class); + + //ensure the parent is a class + if(!(target.getEnclosingElement() instanceof TypeElement)) + return; //TODO throw error, means the annotated field was in a method + TypeElement parent = (TypeElement) target.getEnclosingElement(); + + //ensure the parent is instance of IListener + TypeElement cursor = parent; + TypeMirror listenerInterface = this.processingEnv.getElementUtils().getTypeElement("ftbsc.geb.api.IListener").asType() +; while(cursor != null) { + if(cursor.getInterfaces().contains(listenerInterface)) + break; + + Element superclass = this.processingEnv.getTypeUtils().asElement(cursor.getSuperclass()); + if(superclass instanceof TypeElement) + cursor = (TypeElement) superclass; + else return; //TODO throw error, parent doesnt implement the interface + } + + List instanceSources = getMembersAnnotatedWith(parent, ListenerInstance.class); + + if(instanceSources.size() != 1) + return; //TODO throw error, there should always be only one per class + + Element instanceSource = instanceSources.get(0); + List listenerList = listeners.computeIfAbsent(instanceSource, k -> new ArrayList<>()); + listenerList.add(listener); + } + + private void processEvent(Element target) { + //TODO + } +} diff --git a/src/main/resources/META-INF/gradle/incremental.annotation.processors b/src/main/resources/META-INF/gradle/incremental.annotation.processors new file mode 100644 index 0000000..269cb9f --- /dev/null +++ b/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -0,0 +1 @@ +ftbsc.geb.processor.GEBProcessor,isolating \ No newline at end of file diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..508b333 --- /dev/null +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +ftbsc.geb.processor.GEBProcessor \ No newline at end of file