package hdvtdev.telegram.core.objects; import hdvtdev.telegram.annotations.handlers.CallbackQueryHandler; import hdvtdev.telegram.annotations.handlers.TextMessageHandler; import hdvtdev.telegram.objects.CallbackQuery; import hdvtdev.telegram.objects.Message; import hdvtdev.telegram.objects.Update; import java.io.File; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.security.CodeSource; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; public abstract class ClassFinder { private static final Set> annotationsToSearch = Set.of(TextMessageHandler.class, CallbackQueryHandler.class); private static final Set> methodsArgumentType = Set.of(Message.class, Update.class, CallbackQuery.class); private static ErrorHandler errorHandler; public static Map, Map> getClasses() { Map, Map> allMethods = new HashMap<>(); annotationsToSearch.forEach(annotation -> allMethods.put(annotation, new HashMap<>())); CodeSource codeSource = ClassFinder.class.getProtectionDomain().getCodeSource(); if (codeSource != null) { try { String path = codeSource.getLocation().toURI().getPath(); File file = new File(URLDecoder.decode(path, StandardCharsets.UTF_8)); if (file.isFile() && file.getName().endsWith(".jar")) { processJar(file, allMethods); } else if (file.isDirectory()) { processDirectory(file, "", allMethods); } } catch (Exception e) { return Map.of(); } } return Collections.unmodifiableMap(allMethods); } private static void processDirectory(File directory, String packageName, Map, Map> methods) { File[] files = directory.listFiles(); if (files == null) return; for (File file : files) { if (file.isDirectory()) { processDirectory(file, packageName + file.getName() + ".", methods); } else if (file.getName().endsWith(".class")) { String className = packageName + file.getName().replace(".class", ""); loadClass(className, methods); } } } private static void processJar(File jarFile, Map, Map> methods) { try (JarFile jar = new JarFile(jarFile)) { Enumeration entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (entry.getName().endsWith(".class")) { String className = entry.getName() .replace("/", ".") .replace(".class", ""); loadClass(className, methods); } } } catch (IOException ignored) { } } public static Map, Map> localScan(Class cls) { Map, Map> allMethods = new HashMap<>(); annotationsToSearch.forEach(annotation -> allMethods.put(annotation, new HashMap<>())); loadClass(cls.getName(), allMethods); return allMethods; } private static void loadClass(String className, Map, Map> methods) { try { Class c = Class.forName(className); for (Method method : c.getDeclaredMethods()) { Class[] parameters = method.getParameterTypes(); if (parameters.length != 0 && !methodsArgumentType.contains(parameters[0])) { continue; } if (method.isAnnotationPresent(CallbackQueryHandler.class)) { if (Modifier.isStatic(method.getModifiers())) { for (String value : method.getAnnotation(CallbackQueryHandler.class).value()) { methods.get(CallbackQueryHandler.class).put(value, new InvokeMethod(method, parameters[0])); } } else System.err.println(method + " is annotated with @CallbackQueryHandler, but it is not static. For the annotation to work, the method must be static."); } if (method.isAnnotationPresent(TextMessageHandler.class)) { if (Modifier.isStatic(method.getModifiers())) { for (String value : method.getAnnotation(TextMessageHandler.class).value()) { methods.get(TextMessageHandler.class).put(value, new InvokeMethod(method, parameters[0])); } } else System.err.println(method + " is annotated with @TextMessageHandler, but it is not static. For the annotation to work, the method must be static."); } } } catch (NoClassDefFoundError | UnsupportedClassVersionError | ClassNotFoundException e) { if (errorHandler != null) errorHandler.onError(e); } } public void setErrorHandler(ErrorHandler errorHandler) { ClassFinder.errorHandler = errorHandler; } public interface ErrorHandler { void onError(Throwable throwable); } //tod }