Mercurial > lasercutter
view src/clojure/lang/Reflector.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 /**2 * Copyright (c) Rich Hickey. All rights reserved.3 * The use and distribution terms for this software are covered by the4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)5 * which can be found in the file epl-v10.html at the root of this distribution.6 * By using this software in any fashion, you are agreeing to be bound by7 * the terms of this license.8 * You must not remove this notice, or any other, from this software.9 **/11 /* rich Apr 19, 2006 */13 package clojure.lang;15 import java.lang.reflect.*;16 import java.util.ArrayList;17 import java.util.Iterator;18 import java.util.List;19 import java.util.Arrays;21 public class Reflector{23 public static Object invokeInstanceMethod(Object target, String methodName, Object[] args) throws Exception{24 try25 {26 Class c = target.getClass();27 List methods = getMethods(c, args.length, methodName, false);28 return invokeMatchingMethod(methodName, methods, target, args);29 }30 catch(InvocationTargetException e)31 {32 if(e.getCause() instanceof Exception)33 throw (Exception) e.getCause();34 else if(e.getCause() instanceof Error)35 throw (Error) e.getCause();36 throw e;37 }38 }40 private static String noMethodReport(String methodName, Object target){41 return "No matching method found: " + methodName42 + (target==null?"":" for " + target.getClass());43 }44 static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args)45 throws Exception{46 Method m = null;47 Object[] boxedArgs = null;48 if(methods.isEmpty())49 {50 throw new IllegalArgumentException(noMethodReport(methodName,target));51 }52 else if(methods.size() == 1)53 {54 m = (Method) methods.get(0);55 boxedArgs = boxArgs(m.getParameterTypes(), args);56 }57 else //overloaded w/same arity58 {59 Method foundm = null;60 for(Iterator i = methods.iterator(); i.hasNext();)61 {62 m = (Method) i.next();64 Class[] params = m.getParameterTypes();65 if(isCongruent(params, args))66 {67 if(foundm == null || Compiler.subsumes(params, foundm.getParameterTypes()))68 {69 foundm = m;70 boxedArgs = boxArgs(params, args);71 }72 }73 }74 m = foundm;75 }76 if(m == null)77 throw new IllegalArgumentException(noMethodReport(methodName,target));79 if(!Modifier.isPublic(m.getDeclaringClass().getModifiers()))80 {81 //public method of non-public class, try to find it in hierarchy82 Method oldm = m;83 m = getAsMethodOfPublicBase(m.getDeclaringClass(), m);84 if(m == null)85 throw new IllegalArgumentException("Can't call public method of non-public class: " +86 oldm.toString());87 }88 try89 {90 return prepRet(m.invoke(target, boxedArgs));91 }92 catch(InvocationTargetException e)93 {94 if(e.getCause() instanceof Exception)95 throw (Exception) e.getCause();96 else if(e.getCause() instanceof Error)97 throw (Error) e.getCause();98 throw e;99 }101 }103 public static Method getAsMethodOfPublicBase(Class c, Method m){104 for(Class iface : c.getInterfaces())105 {106 for(Method im : iface.getMethods())107 {108 if(im.getName().equals(m.getName())109 && Arrays.equals(m.getParameterTypes(), im.getParameterTypes()))110 {111 return im;112 }113 }114 }115 Class sc = c.getSuperclass();116 if(sc == null)117 return null;118 for(Method scm : sc.getMethods())119 {120 if(scm.getName().equals(m.getName())121 && Arrays.equals(m.getParameterTypes(), scm.getParameterTypes())122 && Modifier.isPublic(scm.getDeclaringClass().getModifiers()))123 {124 return scm;125 }126 }127 return getAsMethodOfPublicBase(sc, m);128 }130 public static Object invokeConstructor(Class c, Object[] args) throws Exception{131 try132 {133 Constructor[] allctors = c.getConstructors();134 ArrayList ctors = new ArrayList();135 for(int i = 0; i < allctors.length; i++)136 {137 Constructor ctor = allctors[i];138 if(ctor.getParameterTypes().length == args.length)139 ctors.add(ctor);140 }141 if(ctors.isEmpty())142 {143 throw new IllegalArgumentException("No matching ctor found"144 + " for " + c);145 }146 else if(ctors.size() == 1)147 {148 Constructor ctor = (Constructor) ctors.get(0);149 return ctor.newInstance(boxArgs(ctor.getParameterTypes(), args));150 }151 else //overloaded w/same arity152 {153 for(Iterator iterator = ctors.iterator(); iterator.hasNext();)154 {155 Constructor ctor = (Constructor) iterator.next();156 Class[] params = ctor.getParameterTypes();157 if(isCongruent(params, args))158 {159 Object[] boxedArgs = boxArgs(params, args);160 return ctor.newInstance(boxedArgs);161 }162 }163 throw new IllegalArgumentException("No matching ctor found"164 + " for " + c);165 }166 }167 catch(InvocationTargetException e)168 {169 if(e.getCause() instanceof Exception)170 throw (Exception) e.getCause();171 else if(e.getCause() instanceof Error)172 throw (Error) e.getCause();173 throw e;174 }175 }177 public static Object invokeStaticMethodVariadic(String className, String methodName, Object... args) throws Exception{178 return invokeStaticMethod(className, methodName, args);180 }182 public static Object invokeStaticMethod(String className, String methodName, Object[] args) throws Exception{183 Class c = RT.classForName(className);184 try185 {186 return invokeStaticMethod(c, methodName, args);187 }188 catch(InvocationTargetException e)189 {190 if(e.getCause() instanceof Exception)191 throw (Exception) e.getCause();192 else if(e.getCause() instanceof Error)193 throw (Error) e.getCause();194 throw e;195 }196 }198 public static Object invokeStaticMethod(Class c, String methodName, Object[] args) throws Exception{199 if(methodName.equals("new"))200 return invokeConstructor(c, args);201 List methods = getMethods(c, args.length, methodName, true);202 return invokeMatchingMethod(methodName, methods, null, args);203 }205 public static Object getStaticField(String className, String fieldName) throws Exception{206 Class c = RT.classForName(className);207 return getStaticField(c, fieldName);208 }210 public static Object getStaticField(Class c, String fieldName) throws Exception{211 // if(fieldName.equals("class"))212 // return c;213 Field f = getField(c, fieldName, true);214 if(f != null)215 {216 return prepRet(f.get(null));217 }218 throw new IllegalArgumentException("No matching field found: " + fieldName219 + " for " + c);220 }222 public static Object setStaticField(String className, String fieldName, Object val) throws Exception{223 Class c = RT.classForName(className);224 return setStaticField(c, fieldName, val);225 }227 public static Object setStaticField(Class c, String fieldName, Object val) throws Exception{228 Field f = getField(c, fieldName, true);229 if(f != null)230 {231 f.set(null, boxArg(f.getType(), val));232 return val;233 }234 throw new IllegalArgumentException("No matching field found: " + fieldName235 + " for " + c);236 }238 public static Object getInstanceField(Object target, String fieldName) throws Exception{239 Class c = target.getClass();240 Field f = getField(c, fieldName, false);241 if(f != null)242 {243 return prepRet(f.get(target));244 }245 throw new IllegalArgumentException("No matching field found: " + fieldName246 + " for " + target.getClass());247 }249 public static Object setInstanceField(Object target, String fieldName, Object val) throws Exception{250 Class c = target.getClass();251 Field f = getField(c, fieldName, false);252 if(f != null)253 {254 f.set(target, boxArg(f.getType(), val));255 return val;256 }257 throw new IllegalArgumentException("No matching field found: " + fieldName258 + " for " + target.getClass());259 }261 public static Object invokeNoArgInstanceMember(Object target, String name) throws Exception{262 //favor method over field263 List meths = getMethods(target.getClass(), 0, name, false);264 if(meths.size() > 0)265 return invokeMatchingMethod(name, meths, target, RT.EMPTY_ARRAY);266 else267 return getInstanceField(target, name);268 }270 public static Object invokeInstanceMember(Object target, String name) throws Exception{271 //check for field first272 Class c = target.getClass();273 Field f = getField(c, name, false);274 if(f != null) //field get275 {276 return prepRet(f.get(target));277 }278 return invokeInstanceMethod(target, name, RT.EMPTY_ARRAY);279 }281 public static Object invokeInstanceMember(String name, Object target, Object arg1) throws Exception{282 //check for field first283 Class c = target.getClass();284 Field f = getField(c, name, false);285 if(f != null) //field set286 {287 f.set(target, boxArg(f.getType(), arg1));288 return arg1;289 }290 return invokeInstanceMethod(target, name, new Object[]{arg1});291 }293 public static Object invokeInstanceMember(String name, Object target, Object... args) throws Exception{294 return invokeInstanceMethod(target, name, args);295 }298 static public Field getField(Class c, String name, boolean getStatics){299 Field[] allfields = c.getFields();300 for(int i = 0; i < allfields.length; i++)301 {302 if(name.equals(allfields[i].getName())303 && Modifier.isStatic(allfields[i].getModifiers()) == getStatics)304 return allfields[i];305 }306 return null;307 }309 static public List getMethods(Class c, int arity, String name, boolean getStatics){310 Method[] allmethods = c.getMethods();311 ArrayList methods = new ArrayList();312 ArrayList bridgeMethods = new ArrayList();313 for(int i = 0; i < allmethods.length; i++)314 {315 Method method = allmethods[i];316 if(name.equals(method.getName())317 && Modifier.isStatic(method.getModifiers()) == getStatics318 && method.getParameterTypes().length == arity)319 {320 try321 {322 if(method.isBridge()323 && c.getMethod(method.getName(), method.getParameterTypes())324 .equals(method))325 bridgeMethods.add(method);326 else327 methods.add(method);328 }329 catch(NoSuchMethodException e)330 {331 }332 }333 // && (!method.isBridge()334 // || (c == StringBuilder.class &&335 // c.getMethod(method.getName(), method.getParameterTypes())336 // .equals(method))))337 // {338 // methods.add(allmethods[i]);339 // }340 }342 if(methods.isEmpty())343 methods.addAll(bridgeMethods);345 if(!getStatics && c.isInterface())346 {347 allmethods = Object.class.getMethods();348 for(int i = 0; i < allmethods.length; i++)349 {350 if(name.equals(allmethods[i].getName())351 && Modifier.isStatic(allmethods[i].getModifiers()) == getStatics352 && allmethods[i].getParameterTypes().length == arity)353 {354 methods.add(allmethods[i]);355 }356 }357 }358 return methods;359 }362 static Object boxArg(Class paramType, Object arg){363 if(!paramType.isPrimitive())364 return paramType.cast(arg);365 else if(paramType == boolean.class)366 return Boolean.class.cast(arg);367 else if(paramType == char.class)368 return Character.class.cast(arg);369 else if(arg instanceof Number)370 {371 Number n = (Number) arg;372 if(paramType == int.class)373 return n.intValue();374 else if(paramType == float.class)375 return n.floatValue();376 else if(paramType == double.class)377 return n.doubleValue();378 else if(paramType == long.class)379 return n.longValue();380 else if(paramType == short.class)381 return n.shortValue();382 else if(paramType == byte.class)383 return n.byteValue();384 }385 throw new IllegalArgumentException("Unexpected param type, expected: " + paramType +386 ", given: " + arg.getClass().getName());387 }389 static Object[] boxArgs(Class[] params, Object[] args){390 if(params.length == 0)391 return null;392 Object[] ret = new Object[params.length];393 for(int i = 0; i < params.length; i++)394 {395 Object arg = args[i];396 Class paramType = params[i];397 ret[i] = boxArg(paramType, arg);398 }399 return ret;400 }402 static public boolean paramArgTypeMatch(Class paramType, Class argType){403 if(argType == null)404 return !paramType.isPrimitive();405 if(paramType == argType || paramType.isAssignableFrom(argType))406 return true;407 if(paramType == int.class)408 return argType == Integer.class;// || argType == FixNum.class;409 else if(paramType == float.class)410 return argType == Float.class;411 else if(paramType == double.class)412 return argType == Double.class;// || argType == DoubleNum.class;413 else if(paramType == long.class)414 return argType == Long.class;// || argType == BigNum.class;415 else if(paramType == char.class)416 return argType == Character.class;417 else if(paramType == short.class)418 return argType == Short.class;419 else if(paramType == byte.class)420 return argType == Byte.class;421 else if(paramType == boolean.class)422 return argType == Boolean.class;423 return false;424 }426 static boolean isCongruent(Class[] params, Object[] args){427 boolean ret = false;428 if(args == null)429 return params.length == 0;430 if(params.length == args.length)431 {432 ret = true;433 for(int i = 0; ret && i < params.length; i++)434 {435 Object arg = args[i];436 Class argType = (arg == null) ? null : arg.getClass();437 Class paramType = params[i];438 ret = paramArgTypeMatch(paramType, argType);439 }440 }441 return ret;442 }444 public static Object prepRet(Object x){445 // if(c == boolean.class)446 // return ((Boolean) x).booleanValue() ? RT.T : null;447 if(x instanceof Boolean)448 return ((Boolean) x)?Boolean.TRUE:Boolean.FALSE;449 return x;450 }451 }