https://gist.github.com/takawitter/5993155 の続き。パラメータの型のマッチングにも対応してみた。
パラメータの型が一致するメソッドが見つかった場合はそれを、見つからない場合はパラメータの型の祖先を持つもの(f(Integer v)に対するf(Number v)とか)を検索して実行する。どちらの場合もIllegalAccessExceptionが発生した場合はインタフェースから同じメソッドを探して実行する。 但し、パラメータの型の祖先も対象にする場合は、複数のメソッドがマッチする可能性があり、その場合は例外を投げるべきかもしれないが、それを検出するにはメソッド全部調べる必要がありコストが高い。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MethodInvoker{ | |
public static Object invoke( | |
Object instance, String methodName, Object... args) | |
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{ | |
Class<?> clazz = instance.getClass(); | |
Class<?>[] argTypes = new Class<?>[args.length]; | |
for(int i = 0; i < args.length; i++){ | |
argTypes[i] = args[i].getClass(); | |
} | |
try{ | |
return invokeSafely(instance, clazz.getMethod(methodName, argTypes), args); | |
} catch(NoSuchMethodException e){ | |
} | |
for(Method m : clazz.getMethods()){ | |
if(!m.getName().equals(methodName)) continue; | |
Class<?>[] types = m.getParameterTypes(); | |
if(types.length != argTypes.length) continue; | |
boolean matched = true; | |
for(int i = 0; i < argTypes.length; i++){ | |
if(types[i].isAssignableFrom(argTypes[i])){ | |
matched = false; | |
break; | |
} | |
} | |
if(!matched) continue; | |
return invokeSafely(instance, m, args); | |
} | |
throw new NoSuchMethodException(methodName); | |
} | |
public static Object invokeSafely(Object instance, Method method, Object... args) | |
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{ | |
try{ | |
return method.invoke(instance, args); | |
} catch(IllegalAccessException e){ | |
Class<?> clazz = instance.getClass(); | |
String name = method.getName(); | |
Class<?>[] ptypes = method.getParameterTypes(); | |
while(clazz != null){ | |
for(Class<?> i : clazz.getInterfaces()){ | |
try{ | |
return i.getMethod(name, ptypes).invoke(instance, args); | |
} catch(NoSuchMethodException e2){ | |
} | |
} | |
clazz = clazz.getSuperclass(); | |
} | |
throw e; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
あと、スクリプト言語的に使うんだと値の変換とかもやりたくなる(f("1")でf(int)を実行)けど、まぁ、そういう場合は、20行目前後で頑張ってくだされ。