mirror of
https://github.com/EsotericSoftware/reflectasm.git
synced 2025-01-19 08:10:24 +08:00
Add support to invoking interfaces in MethodAccess
- Use INVOKEINTERFACE instead of INVOKEVIRTUAL in case of accessed interface types. - Also, in the method invoke(Object, String, Object...), better suppor for overloaded methods by checking the number of expected arguments.
This commit is contained in:
parent
c63db34fa7
commit
a8e2c96928
@ -20,9 +20,9 @@ public abstract class MethodAccess {
|
||||
|
||||
abstract public Object invoke (Object object, int methodIndex, Object... args);
|
||||
|
||||
/** Invokes the first method with the specified name. */
|
||||
/** Invokes the first method with the specified name and the specified number of arguments. */
|
||||
public Object invoke (Object object, String methodName, Object... args) {
|
||||
return invoke(object, getIndex(methodName), args);
|
||||
return invoke(object, getIndex(methodName, args.length), args);
|
||||
}
|
||||
|
||||
/** Returns the index of the first method with the specified name. */
|
||||
@ -32,10 +32,18 @@ public abstract class MethodAccess {
|
||||
throw new IllegalArgumentException("Unable to find public method: " + methodName);
|
||||
}
|
||||
|
||||
/** Returns the index of the first method with the specified name and param types. */
|
||||
public int getIndex (String methodName, Class... paramTypes) {
|
||||
for (int i = 0, n = methodNames.length; i < n; i++)
|
||||
if (methodNames[i].equals(methodName) && Arrays.equals(paramTypes, parameterTypes[i])) return i;
|
||||
throw new IllegalArgumentException("Unable to find public method: " + methodName + " " + Arrays.toString(parameterTypes));
|
||||
throw new IllegalArgumentException("Unable to find public method: " + methodName + " " + Arrays.toString(paramTypes));
|
||||
}
|
||||
|
||||
/** Returns the index of the first method with the specified name and the specified number of arguments. */
|
||||
public int getIndex (String methodName, int paramsCount) {
|
||||
for (int i = 0, n = methodNames.length; i < n; i++)
|
||||
if (methodNames[i].equals(methodName) && parameterTypes[i].length==paramsCount) return i;
|
||||
throw new IllegalArgumentException("Unable to find public method: " + methodName + " with " + paramsCount + " params.");
|
||||
}
|
||||
|
||||
public String[] getMethodNames () {
|
||||
@ -47,18 +55,17 @@ public abstract class MethodAccess {
|
||||
}
|
||||
|
||||
static public MethodAccess get (Class type) {
|
||||
ArrayList<Method> methods = new ArrayList();
|
||||
Class nextClass = type;
|
||||
while (nextClass != Object.class) {
|
||||
Method[] declaredMethods = nextClass.getDeclaredMethods();
|
||||
for (int i = 0, n = declaredMethods.length; i < n; i++) {
|
||||
Method method = declaredMethods[i];
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isStatic(modifiers)) continue;
|
||||
if (Modifier.isPrivate(modifiers)) continue;
|
||||
methods.add(method);
|
||||
ArrayList<Method> methods = new ArrayList<Method>();
|
||||
boolean isInterface = type.isInterface();
|
||||
if (!isInterface) {
|
||||
Class nextClass = type;
|
||||
while (nextClass != Object.class) {
|
||||
addDeclaredMethodsToList(nextClass, methods);
|
||||
nextClass = nextClass.getSuperclass();
|
||||
}
|
||||
nextClass = nextClass.getSuperclass();
|
||||
}
|
||||
else {
|
||||
recursiveAddInterfaceMethodsToList(type, methods);
|
||||
}
|
||||
|
||||
Class[][] parameterTypes = new Class[methods.size()][];
|
||||
@ -72,7 +79,7 @@ public abstract class MethodAccess {
|
||||
String className = type.getName();
|
||||
String accessClassName = className + "MethodAccess";
|
||||
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
|
||||
Class accessClass = null;
|
||||
Class accessClass;
|
||||
|
||||
AccessClassLoader loader = AccessClassLoader.get(type);
|
||||
synchronized (loader) {
|
||||
@ -176,7 +183,7 @@ public abstract class MethodAccess {
|
||||
|
||||
buffer.append(')');
|
||||
buffer.append(Type.getDescriptor(method.getReturnType()));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, classNameInternal, method.getName(), buffer.toString());
|
||||
mv.visitMethodInsn(isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL, classNameInternal, method.getName(), buffer.toString());
|
||||
|
||||
switch (Type.getType(method.getReturnType()).getSort()) {
|
||||
case Type.VOID:
|
||||
@ -242,4 +249,22 @@ public abstract class MethodAccess {
|
||||
throw new RuntimeException("Error constructing method access class: " + accessClassName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addDeclaredMethodsToList(Class type, ArrayList<Method> methods) {
|
||||
Method[] declaredMethods = type.getDeclaredMethods();
|
||||
for (int i = 0, n = declaredMethods.length; i < n; i++) {
|
||||
Method method = declaredMethods[i];
|
||||
int modifiers = method.getModifiers();
|
||||
if (Modifier.isStatic(modifiers)) continue;
|
||||
if (Modifier.isPrivate(modifiers)) continue;
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
private static void recursiveAddInterfaceMethodsToList(Class interfaceType, ArrayList<Method> methods) {
|
||||
addDeclaredMethodsToList(interfaceType, methods);
|
||||
for (Class nextInterface : interfaceType.getInterfaces()) {
|
||||
recursiveAddInterfaceMethodsToList(nextInterface, methods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user