package jscheme; import java.lang.reflect.*; /** @author Peter Norvig, peter@norvig.com http://www.norvig.com * Copyright 1998 Peter Norvig, see http://www.norvig.com/license.html */ public class JavaMethod extends Procedure { Class[] argClasses; Method method; boolean isStatic; public JavaMethod(String methodName, Object targetClassName, Object argClassNames) { this.name = targetClassName + "." + methodName; try { argClasses = classArray(argClassNames); method = toClass(targetClassName).getMethod(methodName, argClasses); isStatic = Modifier.isStatic(method.getModifiers()); } catch (ClassNotFoundException e) { error("Bad class, can't get method " + name); } catch (NoSuchMethodException e) { error("Can't get method " + name); } } /** Apply the method to a list of arguments. **/ public Object apply(Scheme interpreter, Object args) { try { if (isStatic) return method.invoke(null, toArray(args)); else return method.invoke(first(args), toArray(rest(args))); } catch (IllegalAccessException e) { ; } catch (IllegalArgumentException e) { ; } catch (InvocationTargetException e) { ; } catch (NullPointerException e) { ; } return error("Bad Java Method application:" + this + stringify(args) + ", "); } public static Class toClass(Object arg) throws ClassNotFoundException { if (arg instanceof Class) return (Class)arg; arg = stringify(arg, false); if (arg.equals("void")) return java.lang.Void.TYPE; else if (arg.equals("boolean")) return java.lang.Boolean.TYPE; else if (arg.equals("char")) return java.lang.Character.TYPE; else if (arg.equals("byte")) return java.lang.Byte.TYPE; else if (arg.equals("short")) return java.lang.Short.TYPE; else if (arg.equals("int")) return java.lang.Integer.TYPE; else if (arg.equals("long")) return java.lang.Long.TYPE; else if (arg.equals("float")) return java.lang.Float.TYPE; else if (arg.equals("double")) return java.lang.Double.TYPE; else return Class.forName((String)arg); } /** Convert a list of Objects into an array. Peek at the argClasses * array to see what's expected. That enables us to convert between * Double and Integer, something Java won't do automatically. **/ public Object[] toArray(Object args) { int n = length(args); int diff = n - argClasses.length; if (diff != 0) error(Math.abs(diff) + " too " + ((diff>0) ? "many" : "few") + " args to " + name); Object[] array = new Object[n]; for(int i = 0; i < n && i < argClasses.length; i++) { if (argClasses[i] == java.lang.Integer.TYPE) array[i] = new Integer((int)num(first(args))); else array[i] = first(args); args = rest(args); } return array; } /** Convert a list of class names into an array of Classes. **/ public Class[] classArray(Object args) throws ClassNotFoundException { int n = length(args); Class[] array = new Class[n]; for(int i = 0; i < n; i++) { array[i] = toClass(first(args)); args = rest(args); } return array; } }