Skip to content

Instantly share code, notes, and snippets.

@takawitter
Created July 15, 2013 16:43
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save takawitter/6001449 to your computer and use it in GitHub Desktop.
https://gist.github.com/takawitter/5993155 の続き。パラメータの型のマッチングにも対応してみた。 パラメータの型が一致するメソッドが見つかった場合はそれを、見つからない場合はパラメータの型の祖先を持つもの(f(Integer v)に対するf(Number v)とか)を検索して実行する。どちらの場合もIllegalAccessExceptionが発生した場合はインタフェースから同じメソッドを探して実行する。 但し、パラメータの型の祖先も対象にする場合は、複数のメソッドがマッチする可能性があり、その場合は例外を投げるべきかもしれないが、それを検出するにはメソッド全部調べる必要がありコストが高い。
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;
}
}
}
@takawitter
Copy link
Author

あと、スクリプト言語的に使うんだと値の変換とかもやりたくなる(f("1")でf(int)を実行)けど、まぁ、そういう場合は、20行目前後で頑張ってくだされ。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment