Files
TeleJ/annotation-processor/src/main/java/EventHandlersProcessor.java
2025-11-03 21:17:46 +03:00

173 lines
7.7 KiB
Java

import com.google.auto.service.AutoService;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import java.util.*;
import java.util.stream.Collectors;
import hdvtdev.telegram.handler.annotations.*;
@AutoService(Processor.class)
@SupportedAnnotationTypes({
"hdvtdev.telegram.handler.annotations.OnChosenInlineResult",
"hdvtdev.telegram.handler.annotations.OnChatMemberUpdated",
"hdvtdev.telegram.handler.annotations.OnChatBoostRemoved",
"hdvtdev.telegram.handler.annotations.OnPreCheckoutQuery",
"hdvtdev.telegram.handler.annotations.OnBusinessConnection",
"hdvtdev.telegram.handler.annotations.OnPaidMediaPurchased",
"hdvtdev.telegram.handler.annotations.OnUpdate",
"hdvtdev.telegram.handler.annotations.BotCommand",
"hdvtdev.telegram.handler.annotations.OnPoll",
"hdvtdev.telegram.handler.annotations.OnMessage",
"hdvtdev.telegram.handler.annotations.OnChatJoinRequest",
"hdvtdev.telegram.handler.annotations.OnChatBoostUpdated",
"hdvtdev.telegram.handler.annotations.OnCallbackQuery",
"hdvtdev.telegram.handler.annotations.OnShippingQuery",
"hdvtdev.telegram.handler.annotations.OnInlineQuery",
"hdvtdev.telegram.handler.annotations.OnPollAnswer"})
@SupportedSourceVersion(SourceVersion.RELEASE_21)
public class EventHandlersProcessor extends AbstractProcessor {
private final StringBuilder sb = new StringBuilder();
private static final String PACKAGE = "hdvtdev.telegram.handler.annotations.";
private static final String HANDLER_PACKAGE = "hdvtdev.telegram.handler.";
private static final Set<String> SUPPORTED_ANNOTATIONS = Set.of(
OnChosenInlineResult.class,
OnChatMemberUpdated.class,
OnChatBoostRemoved.class,
OnPreCheckoutQuery.class,
OnBusinessConnection.class,
OnPaidMediaPurchased.class,
OnUpdate.class,
OnPoll.class,
OnMessage.class,
OnChatJoinRequest.class,
OnChatBoostUpdated.class,
OnCallbackQuery.class,
OnShippingQuery.class,
OnInlineQuery.class,
OnPollAnswer.class
).stream().map(Class::getName).collect(Collectors.toSet());
private static final Map<String, String> SUPPORTED_PARAMETERS = Map.ofEntries(
Map.entry("Update", "hdvtdev.telegram.core.objects.Update"),
Map.entry("InlineQuery", "hdvtdev.telegram.core.objects.InlineQuery"),
Map.entry("ChatMemberUpdated", "hdvtdev.telegram.core.objects.chat.ChatMemberUpdated"),
Map.entry("ChatBoostRemoved", "hdvtdev.telegram.core.objects.chatboost.ChatBoostRemoved"),
Map.entry("PreCheckoutQuery", "hdvtdev.telegram.core.objects.payment.PreCheckoutQuery"),
Map.entry("BusinessConnection", "hdvtdev.telegram.core.objects.business.BusinessConnection"),
Map.entry("PaidMediaPurchased", "hdvtdev.telegram.core.objects.media.paidmedia.PaidMediaPurchased"),
Map.entry("Poll", "hdvtdev.telegram.core.objects.poll.Poll"),
Map.entry("Message", "hdvtdev.telegram.core.objects.Message"),
Map.entry("ChatJoinRequest", "hdvtdev.telegram.core.objects.chat.ChatJoinRequest"),
Map.entry("ChatBoostUpdated", "hdvtdev.telegram.core.objects.chatboost.ChatBoostUpdated"),
Map.entry("CallbackQuery", "hdvtdev.telegram.core.objects.callback.CallbackQuery"),
Map.entry("ShippingQuery", "hdvtdev.telegram.core.objects.payment.ShippingQuery"),
Map.entry("PollAnswer", "hdvtdev.telegram.core.objects.poll.PollAnswer"),
Map.entry("ChosenInlineResult", "hdvtdev.telegram.core.objects.ChosenInlineResult")
);
public static String getFullParameterName(String simpleName) {
return SUPPORTED_PARAMETERS.get(simpleName);
}
private Messager messager;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
messager = processingEnv.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
messager.printNote("Called");
for (Element element : roundEnvironment.getRootElements()) {
for (Element enclosedElement : element.getEnclosedElements()) {
if (enclosedElement.getKind() == ElementKind.METHOD) {
processMethod((ExecutableElement) enclosedElement);
}
}
}
if (roundEnvironment.processingOver()) {
write();
}
return true;
}
private void write() {
}
private void processMethod(ExecutableElement methodElement) {
String methodName = methodElement.getSimpleName().toString();
List<AnnotationMirror> foundAnnotations = new ArrayList<>();
for (AnnotationMirror mirror : methodElement.getAnnotationMirrors()) {
String mirrorAnnotationName = Util.getAnnotationMirrorName(mirror);
if (SUPPORTED_ANNOTATIONS.contains(PACKAGE + mirrorAnnotationName)) {
foundAnnotations.add(mirror);
}
}
if (foundAnnotations.size() > 1) {
List<String> annotationNames = new ArrayList<>();
for (AnnotationMirror mirror : foundAnnotations) {
annotationNames.add("@" + Util.getAnnotationMirrorName(mirror));
}
messager.printError(String.format("Method %s cannot have multiple mutually exclusive annotations. Found: %s. Please leave only one.",
methodName, String.join(", ", annotationNames)), methodElement);
return;
}
if (foundAnnotations.size() == 1) {
AnnotationMirror annotation = foundAnnotations.getFirst();
String annotationSimpleName = Util.getAnnotationMirrorName(annotation);
var params = methodElement.getParameters();
if (params.isEmpty()) {
messager.printError(String.format("Method %s, annotated with @%s, must have at least one parameter.",
methodName, annotationSimpleName), methodElement);
return;
}
String firstParameterType = Util.getParameterClassName(params.getFirst().asType());
String requiredParameter = Util.checkParameter(annotationSimpleName, firstParameterType);
if (!requiredParameter.isEmpty()) {
messager.printError(String.format("Incorrect parameter type for method %s. Annotation @%s requires %s, but found %s.",
methodName, annotationSimpleName, requiredParameter, firstParameterType), params.getFirst());
return;
}
if (!annotationSimpleName.equals("BotCommand")) {
String paramName = params.getFirst().getSimpleName().toString();
Set<String> filters = new HashSet<>();
AnnotationValue vv = Util.getAnnotationValue(annotation, "filters");
@SuppressWarnings("unchecked")
List<? extends AnnotationValue> enumValues = vv == null ? List.of() : (List<? extends AnnotationValue>) vv.getValue();
for (AnnotationValue v : enumValues) {
if (v.getValue() instanceof VariableElement enumConstant) {
filters.add(enumConstant.getSimpleName().toString());
}
}
sb.append(Generator.generateVoid(methodName, String.format("%s %s", firstParameterType, paramName),
Generator.generateFilterBlock(filters, paramName)));
}
}
}
}