package com.qrokodial.sparkle.utilities.reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflectionUtils {
    /**
     * Gets a list of all methods within a class that are marked with an annotation.
     *
     * @param type       the class to search
     * @param annotation the annotation to match
     * @return the relevant list of methods
     */
    public static List<Method> getMethodsWithAnnotation(Class<?> type, Class<? extends Annotation> annotation) {
        List<Method> methods = new ArrayList<>();

        Class<?> clazz = type;
        while (clazz != Object.class) {
            for (Method method : clazz.getDeclaredMethods()) {
                if (method.isAnnotationPresent(annotation)) {
                    methods.add(method);
                }
            }

            clazz = clazz.getSuperclass();
        }

        return methods;
    }
}

@@ -57,72 +57,210 @@
 ort 
-java.lang.annotation.Annotation;%0Aimport java.lang.reflect.Method
+com.qrokodial.sparkle.utilities.collections.ArrayUtils;%0A%0Aimport java.lang.annotation.Annotation;%0Aimport java.lang.reflect.Constructor;%0Aimport java.lang.reflect.Method;%0Aimport java.lang.reflect.Parameter
 ;%0Aim
@@ -307,16 +307,43 @@
 il.List;
+%0Aimport java.util.Optional;
 %0A%0Apublic
@@ -1130,11 +1130,2294 @@
 s;%0A    %7D
+%0A%0A    /**%0A     * Attempts to get the constructor of a class that fulfills the requirements of the provided parameters.%0A     *%0A     * @param constructorClass the class that owns the constructors%0A     * @param parameters       the parameters that the constructor must satisfy%0A     * @return an %7B@link Optional%7D containing the relevant constructor, if one exists%0A     */%0A    public static %3CT%3E Optional%3CConstructor%3CT%3E%3E getConstructorMatching(Class%3CT%3E constructorClass, Object... parameters) %7B%0A        Class%5B%5D classes = ArrayUtils.getTypes(parameters);%0A%0A        for (Constructor constructor : constructorClass.getDeclaredConstructors()) %7B%0A            Parameter%5B%5D cParams = constructor.getParameters();%0A%0A            if (cParams.length == 0 && parameters.length == 0) %7B%0A                return Optional.of((Constructor%3CT%3E)constructor);%0A            %7D%0A%0A            if (classes.length != cParams.length && !constructor.isVarArgs()) %7B%0A                continue;%0A            %7D%0A%0A            for (int i = 0; i %3C classes.length; i++) %7B%0A                if (!cParams%5Bi%5D.getType().isAssignableFrom(classes%5Bi%5D)) %7B%0A                    break;%0A                %7D%0A%0A                if (cParams%5Bi%5D.isVarArgs() && !isAssignableFromClasses(cParams%5Bi%5D.getType(), classes, i, classes.length - 1)) %7B%0A                    break;%0A                %7D%0A%0A                if (i + 1 == cParams.length) %7B%0A                    return Optional.of((Constructor%3CT%3E)constructor);%0A                %7D%0A            %7D%0A        %7D%0A%0A        return Optional.empty();%0A    %7D%0A%0A    /**%0A     * Checks to see if a main class is assignable from multiple other classes.%0A     *%0A     * @param mainClass  the main class%0A     * @param classes    the other classes%0A     * @param startIndex the index of the array of the other classes to check%0A     * @param endIndex   the end index of the array of the other classes to check%0A     * @return true of the main class is assignable from all of the relevant other classes, false otherwise%0A     */%0A    public static boolean isAssignableFromClasses(Class%3C?%3E mainClass, Class%3C?%3E%5B%5D classes, int startIndex, int endIndex) %7B%0A        for (int i = startIndex; i %3C= endIndex; i++) %7B%0A            if (!mainClass.isAssignableFrom(classes%5Bi%5D)) %7B%0A                return false;%0A            %7D%0A        %7D%0A%0A        return true;%0A    %7D
 %0A%7D%0A

Add methods for constructor fuzzy matching