Merge pull request #429 from benwoo1110/feat/recursive-annotations

Add support for getting annotation from parent class/method/parameter
This commit is contained in:
chickeneer
2025-04-12 17:27:08 -05:00
committed by GitHub
@@ -27,6 +27,8 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -52,6 +54,16 @@ class Annotations<M extends CommandManager> extends AnnotationLookups {
String getAnnotationValue(AnnotatedElement object, Class<? extends Annotation> annoClass, int options) {
Annotation annotation = getAnnotationRecursive(object, annoClass, new HashSet<>());
if (annotation == null) {
if (object instanceof Class) {
annotation = getAnnotationFromParentClasses((Class<?>) object, annoClass);
} else if (object instanceof Method) {
annotation = getAnnotationFromParentMethods((Method) object, annoClass);
} else if (object instanceof Parameter) {
annotation = getAnnotationFromParentParameters((Parameter) object, annoClass);
}
}
String value = null;
if (annotation != null) {
@@ -104,6 +116,60 @@ class Annotations<M extends CommandManager> extends AnnotationLookups {
return value;
}
private static Annotation getAnnotationFromParentClasses(Class<?> clazz, Class<? extends Annotation> annoClass) {
Class<?> parent = clazz.getSuperclass();
while (parent != null && !parent.equals(BaseCommand.class) && !parent.equals(Object.class)) {
Annotation annotation = getAnnotationRecursive(parent, annoClass, new HashSet<>());
if (annotation != null) {
return annotation;
}
parent = parent.getSuperclass();
}
return null;
}
private static Annotation getAnnotationFromParentMethods(Method method, Class<? extends Annotation> annoClass) {
Class<?> clazz = method.getDeclaringClass().getSuperclass();
while (clazz != null && !clazz.equals(BaseCommand.class) && !clazz.equals(Object.class)) {
try {
Method parentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
Annotation parentAnnotation = getAnnotationRecursive(parentMethod, annoClass, new HashSet<>());
if (parentAnnotation != null) {
return parentAnnotation;
}
} catch (NoSuchMethodException e) {
// No parent method
return null;
}
clazz = clazz.getSuperclass();
}
return null;
}
private static Annotation getAnnotationFromParentParameters(Parameter parameter, Class<? extends Annotation> annoClass) {
Class<?> clazz = parameter.getDeclaringExecutable().getDeclaringClass().getSuperclass();
while (clazz != null && !clazz.equals(BaseCommand.class) && !clazz.equals(Object.class)) {
try {
Method parentMethod = clazz.getDeclaredMethod(parameter.getDeclaringExecutable().getName(), parameter.getDeclaringExecutable().getParameterTypes());
Annotation parentAnnotation = Arrays.stream(parentMethod.getParameters())
.filter(parentParameter -> parentParameter.getName().equals(parameter.getName())
&& parentParameter.getType().equals(parameter.getType()))
.findFirst()
.map(parentParameter -> getAnnotationRecursive(parentParameter, annoClass, new HashSet<>()))
.orElse(null);
if (parentAnnotation != null) {
return parentAnnotation;
}
} catch (NoSuchMethodException e) {
// No parent method
return null;
}
clazz = clazz.getSuperclass();
}
return null;
}
private static Annotation getAnnotationRecursive(AnnotatedElement object, Class<? extends Annotation> annoClass, Collection<Annotation> checked) {
if (object.isAnnotationPresent(annoClass)) {
return object.getAnnotation(annoClass);