Mercurial > lasercutter
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/lang/Reflector.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,451 @@ 1.4 +/** 1.5 + * Copyright (c) Rich Hickey. All rights reserved. 1.6 + * The use and distribution terms for this software are covered by the 1.7 + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.8 + * which can be found in the file epl-v10.html at the root of this distribution. 1.9 + * By using this software in any fashion, you are agreeing to be bound by 1.10 + * the terms of this license. 1.11 + * You must not remove this notice, or any other, from this software. 1.12 + **/ 1.13 + 1.14 +/* rich Apr 19, 2006 */ 1.15 + 1.16 +package clojure.lang; 1.17 + 1.18 +import java.lang.reflect.*; 1.19 +import java.util.ArrayList; 1.20 +import java.util.Iterator; 1.21 +import java.util.List; 1.22 +import java.util.Arrays; 1.23 + 1.24 +public class Reflector{ 1.25 + 1.26 +public static Object invokeInstanceMethod(Object target, String methodName, Object[] args) throws Exception{ 1.27 + try 1.28 + { 1.29 + Class c = target.getClass(); 1.30 + List methods = getMethods(c, args.length, methodName, false); 1.31 + return invokeMatchingMethod(methodName, methods, target, args); 1.32 + } 1.33 + catch(InvocationTargetException e) 1.34 + { 1.35 + if(e.getCause() instanceof Exception) 1.36 + throw (Exception) e.getCause(); 1.37 + else if(e.getCause() instanceof Error) 1.38 + throw (Error) e.getCause(); 1.39 + throw e; 1.40 + } 1.41 +} 1.42 + 1.43 +private static String noMethodReport(String methodName, Object target){ 1.44 + return "No matching method found: " + methodName 1.45 + + (target==null?"":" for " + target.getClass()); 1.46 +} 1.47 +static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args) 1.48 + throws Exception{ 1.49 + Method m = null; 1.50 + Object[] boxedArgs = null; 1.51 + if(methods.isEmpty()) 1.52 + { 1.53 + throw new IllegalArgumentException(noMethodReport(methodName,target)); 1.54 + } 1.55 + else if(methods.size() == 1) 1.56 + { 1.57 + m = (Method) methods.get(0); 1.58 + boxedArgs = boxArgs(m.getParameterTypes(), args); 1.59 + } 1.60 + else //overloaded w/same arity 1.61 + { 1.62 + Method foundm = null; 1.63 + for(Iterator i = methods.iterator(); i.hasNext();) 1.64 + { 1.65 + m = (Method) i.next(); 1.66 + 1.67 + Class[] params = m.getParameterTypes(); 1.68 + if(isCongruent(params, args)) 1.69 + { 1.70 + if(foundm == null || Compiler.subsumes(params, foundm.getParameterTypes())) 1.71 + { 1.72 + foundm = m; 1.73 + boxedArgs = boxArgs(params, args); 1.74 + } 1.75 + } 1.76 + } 1.77 + m = foundm; 1.78 + } 1.79 + if(m == null) 1.80 + throw new IllegalArgumentException(noMethodReport(methodName,target)); 1.81 + 1.82 + if(!Modifier.isPublic(m.getDeclaringClass().getModifiers())) 1.83 + { 1.84 + //public method of non-public class, try to find it in hierarchy 1.85 + Method oldm = m; 1.86 + m = getAsMethodOfPublicBase(m.getDeclaringClass(), m); 1.87 + if(m == null) 1.88 + throw new IllegalArgumentException("Can't call public method of non-public class: " + 1.89 + oldm.toString()); 1.90 + } 1.91 + try 1.92 + { 1.93 + return prepRet(m.invoke(target, boxedArgs)); 1.94 + } 1.95 + catch(InvocationTargetException e) 1.96 + { 1.97 + if(e.getCause() instanceof Exception) 1.98 + throw (Exception) e.getCause(); 1.99 + else if(e.getCause() instanceof Error) 1.100 + throw (Error) e.getCause(); 1.101 + throw e; 1.102 + } 1.103 + 1.104 +} 1.105 + 1.106 +public static Method getAsMethodOfPublicBase(Class c, Method m){ 1.107 + for(Class iface : c.getInterfaces()) 1.108 + { 1.109 + for(Method im : iface.getMethods()) 1.110 + { 1.111 + if(im.getName().equals(m.getName()) 1.112 + && Arrays.equals(m.getParameterTypes(), im.getParameterTypes())) 1.113 + { 1.114 + return im; 1.115 + } 1.116 + } 1.117 + } 1.118 + Class sc = c.getSuperclass(); 1.119 + if(sc == null) 1.120 + return null; 1.121 + for(Method scm : sc.getMethods()) 1.122 + { 1.123 + if(scm.getName().equals(m.getName()) 1.124 + && Arrays.equals(m.getParameterTypes(), scm.getParameterTypes()) 1.125 + && Modifier.isPublic(scm.getDeclaringClass().getModifiers())) 1.126 + { 1.127 + return scm; 1.128 + } 1.129 + } 1.130 + return getAsMethodOfPublicBase(sc, m); 1.131 +} 1.132 + 1.133 +public static Object invokeConstructor(Class c, Object[] args) throws Exception{ 1.134 + try 1.135 + { 1.136 + Constructor[] allctors = c.getConstructors(); 1.137 + ArrayList ctors = new ArrayList(); 1.138 + for(int i = 0; i < allctors.length; i++) 1.139 + { 1.140 + Constructor ctor = allctors[i]; 1.141 + if(ctor.getParameterTypes().length == args.length) 1.142 + ctors.add(ctor); 1.143 + } 1.144 + if(ctors.isEmpty()) 1.145 + { 1.146 + throw new IllegalArgumentException("No matching ctor found" 1.147 + + " for " + c); 1.148 + } 1.149 + else if(ctors.size() == 1) 1.150 + { 1.151 + Constructor ctor = (Constructor) ctors.get(0); 1.152 + return ctor.newInstance(boxArgs(ctor.getParameterTypes(), args)); 1.153 + } 1.154 + else //overloaded w/same arity 1.155 + { 1.156 + for(Iterator iterator = ctors.iterator(); iterator.hasNext();) 1.157 + { 1.158 + Constructor ctor = (Constructor) iterator.next(); 1.159 + Class[] params = ctor.getParameterTypes(); 1.160 + if(isCongruent(params, args)) 1.161 + { 1.162 + Object[] boxedArgs = boxArgs(params, args); 1.163 + return ctor.newInstance(boxedArgs); 1.164 + } 1.165 + } 1.166 + throw new IllegalArgumentException("No matching ctor found" 1.167 + + " for " + c); 1.168 + } 1.169 + } 1.170 + catch(InvocationTargetException e) 1.171 + { 1.172 + if(e.getCause() instanceof Exception) 1.173 + throw (Exception) e.getCause(); 1.174 + else if(e.getCause() instanceof Error) 1.175 + throw (Error) e.getCause(); 1.176 + throw e; 1.177 + } 1.178 +} 1.179 + 1.180 +public static Object invokeStaticMethodVariadic(String className, String methodName, Object... args) throws Exception{ 1.181 + return invokeStaticMethod(className, methodName, args); 1.182 + 1.183 +} 1.184 + 1.185 +public static Object invokeStaticMethod(String className, String methodName, Object[] args) throws Exception{ 1.186 + Class c = RT.classForName(className); 1.187 + try 1.188 + { 1.189 + return invokeStaticMethod(c, methodName, args); 1.190 + } 1.191 + catch(InvocationTargetException e) 1.192 + { 1.193 + if(e.getCause() instanceof Exception) 1.194 + throw (Exception) e.getCause(); 1.195 + else if(e.getCause() instanceof Error) 1.196 + throw (Error) e.getCause(); 1.197 + throw e; 1.198 + } 1.199 +} 1.200 + 1.201 +public static Object invokeStaticMethod(Class c, String methodName, Object[] args) throws Exception{ 1.202 + if(methodName.equals("new")) 1.203 + return invokeConstructor(c, args); 1.204 + List methods = getMethods(c, args.length, methodName, true); 1.205 + return invokeMatchingMethod(methodName, methods, null, args); 1.206 +} 1.207 + 1.208 +public static Object getStaticField(String className, String fieldName) throws Exception{ 1.209 + Class c = RT.classForName(className); 1.210 + return getStaticField(c, fieldName); 1.211 +} 1.212 + 1.213 +public static Object getStaticField(Class c, String fieldName) throws Exception{ 1.214 +// if(fieldName.equals("class")) 1.215 +// return c; 1.216 + Field f = getField(c, fieldName, true); 1.217 + if(f != null) 1.218 + { 1.219 + return prepRet(f.get(null)); 1.220 + } 1.221 + throw new IllegalArgumentException("No matching field found: " + fieldName 1.222 + + " for " + c); 1.223 +} 1.224 + 1.225 +public static Object setStaticField(String className, String fieldName, Object val) throws Exception{ 1.226 + Class c = RT.classForName(className); 1.227 + return setStaticField(c, fieldName, val); 1.228 +} 1.229 + 1.230 +public static Object setStaticField(Class c, String fieldName, Object val) throws Exception{ 1.231 + Field f = getField(c, fieldName, true); 1.232 + if(f != null) 1.233 + { 1.234 + f.set(null, boxArg(f.getType(), val)); 1.235 + return val; 1.236 + } 1.237 + throw new IllegalArgumentException("No matching field found: " + fieldName 1.238 + + " for " + c); 1.239 +} 1.240 + 1.241 +public static Object getInstanceField(Object target, String fieldName) throws Exception{ 1.242 + Class c = target.getClass(); 1.243 + Field f = getField(c, fieldName, false); 1.244 + if(f != null) 1.245 + { 1.246 + return prepRet(f.get(target)); 1.247 + } 1.248 + throw new IllegalArgumentException("No matching field found: " + fieldName 1.249 + + " for " + target.getClass()); 1.250 +} 1.251 + 1.252 +public static Object setInstanceField(Object target, String fieldName, Object val) throws Exception{ 1.253 + Class c = target.getClass(); 1.254 + Field f = getField(c, fieldName, false); 1.255 + if(f != null) 1.256 + { 1.257 + f.set(target, boxArg(f.getType(), val)); 1.258 + return val; 1.259 + } 1.260 + throw new IllegalArgumentException("No matching field found: " + fieldName 1.261 + + " for " + target.getClass()); 1.262 +} 1.263 + 1.264 +public static Object invokeNoArgInstanceMember(Object target, String name) throws Exception{ 1.265 + //favor method over field 1.266 + List meths = getMethods(target.getClass(), 0, name, false); 1.267 + if(meths.size() > 0) 1.268 + return invokeMatchingMethod(name, meths, target, RT.EMPTY_ARRAY); 1.269 + else 1.270 + return getInstanceField(target, name); 1.271 +} 1.272 + 1.273 +public static Object invokeInstanceMember(Object target, String name) throws Exception{ 1.274 + //check for field first 1.275 + Class c = target.getClass(); 1.276 + Field f = getField(c, name, false); 1.277 + if(f != null) //field get 1.278 + { 1.279 + return prepRet(f.get(target)); 1.280 + } 1.281 + return invokeInstanceMethod(target, name, RT.EMPTY_ARRAY); 1.282 +} 1.283 + 1.284 +public static Object invokeInstanceMember(String name, Object target, Object arg1) throws Exception{ 1.285 + //check for field first 1.286 + Class c = target.getClass(); 1.287 + Field f = getField(c, name, false); 1.288 + if(f != null) //field set 1.289 + { 1.290 + f.set(target, boxArg(f.getType(), arg1)); 1.291 + return arg1; 1.292 + } 1.293 + return invokeInstanceMethod(target, name, new Object[]{arg1}); 1.294 +} 1.295 + 1.296 +public static Object invokeInstanceMember(String name, Object target, Object... args) throws Exception{ 1.297 + return invokeInstanceMethod(target, name, args); 1.298 +} 1.299 + 1.300 + 1.301 +static public Field getField(Class c, String name, boolean getStatics){ 1.302 + Field[] allfields = c.getFields(); 1.303 + for(int i = 0; i < allfields.length; i++) 1.304 + { 1.305 + if(name.equals(allfields[i].getName()) 1.306 + && Modifier.isStatic(allfields[i].getModifiers()) == getStatics) 1.307 + return allfields[i]; 1.308 + } 1.309 + return null; 1.310 +} 1.311 + 1.312 +static public List getMethods(Class c, int arity, String name, boolean getStatics){ 1.313 + Method[] allmethods = c.getMethods(); 1.314 + ArrayList methods = new ArrayList(); 1.315 + ArrayList bridgeMethods = new ArrayList(); 1.316 + for(int i = 0; i < allmethods.length; i++) 1.317 + { 1.318 + Method method = allmethods[i]; 1.319 + if(name.equals(method.getName()) 1.320 + && Modifier.isStatic(method.getModifiers()) == getStatics 1.321 + && method.getParameterTypes().length == arity) 1.322 + { 1.323 + try 1.324 + { 1.325 + if(method.isBridge() 1.326 + && c.getMethod(method.getName(), method.getParameterTypes()) 1.327 + .equals(method)) 1.328 + bridgeMethods.add(method); 1.329 + else 1.330 + methods.add(method); 1.331 + } 1.332 + catch(NoSuchMethodException e) 1.333 + { 1.334 + } 1.335 + } 1.336 +// && (!method.isBridge() 1.337 +// || (c == StringBuilder.class && 1.338 +// c.getMethod(method.getName(), method.getParameterTypes()) 1.339 +// .equals(method)))) 1.340 +// { 1.341 +// methods.add(allmethods[i]); 1.342 +// } 1.343 + } 1.344 + 1.345 + if(methods.isEmpty()) 1.346 + methods.addAll(bridgeMethods); 1.347 + 1.348 + if(!getStatics && c.isInterface()) 1.349 + { 1.350 + allmethods = Object.class.getMethods(); 1.351 + for(int i = 0; i < allmethods.length; i++) 1.352 + { 1.353 + if(name.equals(allmethods[i].getName()) 1.354 + && Modifier.isStatic(allmethods[i].getModifiers()) == getStatics 1.355 + && allmethods[i].getParameterTypes().length == arity) 1.356 + { 1.357 + methods.add(allmethods[i]); 1.358 + } 1.359 + } 1.360 + } 1.361 + return methods; 1.362 +} 1.363 + 1.364 + 1.365 +static Object boxArg(Class paramType, Object arg){ 1.366 + if(!paramType.isPrimitive()) 1.367 + return paramType.cast(arg); 1.368 + else if(paramType == boolean.class) 1.369 + return Boolean.class.cast(arg); 1.370 + else if(paramType == char.class) 1.371 + return Character.class.cast(arg); 1.372 + else if(arg instanceof Number) 1.373 + { 1.374 + Number n = (Number) arg; 1.375 + if(paramType == int.class) 1.376 + return n.intValue(); 1.377 + else if(paramType == float.class) 1.378 + return n.floatValue(); 1.379 + else if(paramType == double.class) 1.380 + return n.doubleValue(); 1.381 + else if(paramType == long.class) 1.382 + return n.longValue(); 1.383 + else if(paramType == short.class) 1.384 + return n.shortValue(); 1.385 + else if(paramType == byte.class) 1.386 + return n.byteValue(); 1.387 + } 1.388 + throw new IllegalArgumentException("Unexpected param type, expected: " + paramType + 1.389 + ", given: " + arg.getClass().getName()); 1.390 +} 1.391 + 1.392 +static Object[] boxArgs(Class[] params, Object[] args){ 1.393 + if(params.length == 0) 1.394 + return null; 1.395 + Object[] ret = new Object[params.length]; 1.396 + for(int i = 0; i < params.length; i++) 1.397 + { 1.398 + Object arg = args[i]; 1.399 + Class paramType = params[i]; 1.400 + ret[i] = boxArg(paramType, arg); 1.401 + } 1.402 + return ret; 1.403 +} 1.404 + 1.405 +static public boolean paramArgTypeMatch(Class paramType, Class argType){ 1.406 + if(argType == null) 1.407 + return !paramType.isPrimitive(); 1.408 + if(paramType == argType || paramType.isAssignableFrom(argType)) 1.409 + return true; 1.410 + if(paramType == int.class) 1.411 + return argType == Integer.class;// || argType == FixNum.class; 1.412 + else if(paramType == float.class) 1.413 + return argType == Float.class; 1.414 + else if(paramType == double.class) 1.415 + return argType == Double.class;// || argType == DoubleNum.class; 1.416 + else if(paramType == long.class) 1.417 + return argType == Long.class;// || argType == BigNum.class; 1.418 + else if(paramType == char.class) 1.419 + return argType == Character.class; 1.420 + else if(paramType == short.class) 1.421 + return argType == Short.class; 1.422 + else if(paramType == byte.class) 1.423 + return argType == Byte.class; 1.424 + else if(paramType == boolean.class) 1.425 + return argType == Boolean.class; 1.426 + return false; 1.427 +} 1.428 + 1.429 +static boolean isCongruent(Class[] params, Object[] args){ 1.430 + boolean ret = false; 1.431 + if(args == null) 1.432 + return params.length == 0; 1.433 + if(params.length == args.length) 1.434 + { 1.435 + ret = true; 1.436 + for(int i = 0; ret && i < params.length; i++) 1.437 + { 1.438 + Object arg = args[i]; 1.439 + Class argType = (arg == null) ? null : arg.getClass(); 1.440 + Class paramType = params[i]; 1.441 + ret = paramArgTypeMatch(paramType, argType); 1.442 + } 1.443 + } 1.444 + return ret; 1.445 +} 1.446 + 1.447 +public static Object prepRet(Object x){ 1.448 +// if(c == boolean.class) 1.449 +// return ((Boolean) x).booleanValue() ? RT.T : null; 1.450 + if(x instanceof Boolean) 1.451 + return ((Boolean) x)?Boolean.TRUE:Boolean.FALSE; 1.452 + return x; 1.453 +} 1.454 +}