Compare commits

..

2 Commits

Author SHA1 Message Date
659218682e
add context Object to check methods and create the ability to have a specific method for each type of context or one for all by using the superclass and casting yourself
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 12s
Test / Gradle-Test (push) Successful in 17s
2024-11-29 18:17:33 +01:00
019ba8f552
add getMostSpecificMethod method to simplify Check method parsing.
This Method searches the The method that has the best matching parameters with the fewest inheritance levels as possible. Left sided priority
2024-11-29 18:15:47 +01:00
4 changed files with 102 additions and 10 deletions

@ -2,22 +2,36 @@ package net.tomatentum.marinara.checks;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import net.tomatentum.marinara.util.ReflectionUtil;
public record AppliedCheck(InteractionCheck<?> check, Annotation annotation) {
public boolean pre() {
public boolean pre(Object context) {
Method[] methods = Arrays.stream(check.getClass().getMethods())
.filter(x -> x.getName().equals("preExec"))
.toArray(s -> new Method[s]);
Method method = ReflectionUtil.getMostSpecificMethod(methods, context.getClass());
method.setAccessible(true);
try {
return (boolean) check.getClass().getMethod("preExec", annotation.getClass()).invoke(check, annotation);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
return (boolean) method.invoke(check, annotation);
} catch (IllegalAccessException | InvocationTargetException | SecurityException e) {
e.printStackTrace();
return false;
}
}
public boolean post() {
public boolean post(Object context) {
Method[] methods = Arrays.stream(check.getClass().getMethods())
.filter(x -> x.getName().equals("postExec"))
.toArray(s -> new Method[s]);
Method method = ReflectionUtil.getMostSpecificMethod(methods, context.getClass());
method.setAccessible(true);
try {
return (boolean) check.getClass().getMethod("postExec", annotation.getClass()).invoke(check, annotation);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
return (boolean) method.invoke(check, annotation);
} catch (IllegalAccessException | InvocationTargetException | SecurityException e) {
e.printStackTrace();
return false;
}

@ -4,7 +4,7 @@ import java.lang.annotation.Annotation;
public interface InteractionCheck<A extends Annotation> {
public boolean preExec(A annotation);
public boolean postExec(A annotation);
public boolean preExec(Object context, A annotation);
public boolean postExec(Object context, A annotation);
}

@ -60,7 +60,7 @@ public abstract class InteractionMethod {
public abstract InteractionType getType();
public void run(Object context) {
this.appliedChecks.forEach(AppliedCheck::pre);
this.appliedChecks.forEach(x -> x.pre(context));
method.setAccessible(true);
try {
@ -69,7 +69,7 @@ public abstract class InteractionMethod {
throw new RuntimeException(ex);
}
this.appliedChecks.forEach(AppliedCheck::post);
this.appliedChecks.forEach(x -> x.post(context));
}
public Method getMethod() {

@ -2,6 +2,10 @@ package net.tomatentum.marinara.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
public final class ReflectionUtil {
@ -18,4 +22,78 @@ public final class ReflectionUtil {
method.getDeclaringClass().getAnnotation(annotationClass);
}
public static int getCastDepth(Class<?> child, Class<?> parent) {
if (!parent.isAssignableFrom(child)) {
throw new IllegalArgumentException("The specified class is not a child class of the specified parent.");
}
int depth = 0;
Class<?> curr = child;
List<Class<?>> parents = new ArrayList<>();
while (!curr.equals(parent)) {
depth++;
parents.add(curr.getSuperclass());
parents.addAll(Arrays.asList(curr.getInterfaces()));
for (Class<?> currParent : parents) {
if (currParent != null && parent.isAssignableFrom(currParent)) {
curr = currParent;
break;
}
}
parents.clear();
}
return depth;
}
public static Method getMostSpecificMethod(Method[] methods, Class<?>... parameters) {
List<Method> compatibleMethods = Arrays.stream(methods)
.filter(x -> isMethodCallable(x, parameters))
.toList();
if (compatibleMethods.size() == 0)
throw new IllegalArgumentException("There are no compatible Methods provided");
for (int i = 0; i < parameters.length; i++) {
final int currI = i;
Class<?>[] parameterTypes = compatibleMethods.stream()
.map(x -> x.getParameterTypes()[currI])
.toArray(x -> new Class[x]);
Class<?> mostSpecific = getMostSpecificClass(parameterTypes, parameters[i]);
compatibleMethods = compatibleMethods.stream()
.filter(x -> Objects.equals(x.getParameterTypes()[currI], mostSpecific))
.toList();
}
return compatibleMethods.getFirst();
}
public static Class<?> getMostSpecificClass(Class<?>[] classes, Class<?> base) {
int min = Integer.MAX_VALUE;
Class<?> currMostSpecific = null;
for (Class<?> currClass : classes) {
int currCastDepth = getCastDepth(base, currClass);
if (currCastDepth < min) {
min = currCastDepth;
currMostSpecific = currClass;
}
}
return currMostSpecific;
}
public static boolean isMethodCallable(Method method, Class<?>... parameters) {
if (!Objects.equals(method.getParameterCount(), parameters.length))
return false;
Class<?>[] methodParams = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (!methodParams[i].isAssignableFrom(parameters[i]))
return false;
}
return true;
}
}