Fixed Java 9+ reflection issue

This commit is contained in:
Ziver Koc 2025-12-24 04:18:01 +01:00
parent c4f7823ba3
commit 2ea486a05d
2 changed files with 49 additions and 10 deletions

View file

@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
* Copyright (c) 2020-2025 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,9 +24,7 @@
package zutil;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -248,4 +246,46 @@ public class ClassUtil {
return fields;
}
/**
* Finds a method definition that is public and accessible for a given method.
* This is required for Java 9+ compatibility when reflecting on internal classes.
*
* @param method the method to search for.
* @return a public Method that can be called by reflection without throwing an exception, or the original method will be returned.
*/
public static Method getAccessibleMethod(Method method) {
if (Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
// The method is already accessible so return it directly
return method;
}
String methodName = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Check implemented interfaces for the method (e.g., finding Map.Entry.getKey())
for (Class<?> interfaceClass : method.getDeclaringClass().getInterfaces()) {
try {
Method interfaceMethod = interfaceClass.getMethod(methodName, paramTypes);
if (Modifier.isPublic(interfaceMethod.getDeclaringClass().getModifiers())) {
return interfaceMethod;
}
} catch (NoSuchMethodException e) {
// Interface does not have this method, continue loop
}
}
// Check if superclass has the method
Class<?> superClass = method.getDeclaringClass().getSuperclass();
if (superClass != null) {
try {
Method superMethod = superClass.getMethod(methodName, paramTypes);
return getAccessibleMethod(superMethod);
} catch (NoSuchMethodException e) {}
}
// No public version was found, return original
return method;
}
}

View file

@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
* Copyright (c) 2020-2025 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -152,7 +152,7 @@ public class Templator {
}
/**
* Will parse or re-parse the source template.
* Will parse or reparse the source template.
*/
private void parseTemplate(String tmpl) {
tmplRoot = parseTemplate(new TemplateNode(), tmpl, new MutableInt(), null);
@ -396,11 +396,11 @@ public class Templator {
if (attrib.endsWith("()")) { // Is this a function call?
if (attrib.length() > 2) {
String funcName = attrib.substring(0, attrib.length()-2);
// Using a loop as the direct lookup throws a exception if no field was found
// Using a loop as the direct lookup throws an exception if no field was found
// So this is probably a bit faster
for (Method m : obj.getClass().getMethods()) {
if (m.getParameterTypes().length == 0 && m.getName().equals(funcName)) {
m.setAccessible(true);
m = ClassUtil.getAccessibleMethod(m);
return m.invoke(obj);
}
}
@ -411,11 +411,10 @@ public class Templator {
else if (obj instanceof Collection && "length".equals(attrib))
return ((Collection) obj).size();
else {
// Using a loop as the direct lookup throws a exception if no field was found
// Using a loop as the direct lookup throws an exception if no field was found
// So this is probably a bit faster
for (Field field : ClassUtil.getAllDeclaredFields(obj.getClass())) { // Only look for public fields
if (field.getName().equals(attrib)) {
field.setAccessible(true);
return field.get(obj);
}
}