From 744a5f395ddfb5963165795f653d7a6fd8287a2f Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 14 Aug 2001 06:48:08 +0000 Subject: [PATCH] Created a utility function for easily looking up methods. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@238 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/presents/util/ClassUtil.java | 74 ++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/src/java/com/threerings/presents/util/ClassUtil.java b/src/java/com/threerings/presents/util/ClassUtil.java index 0d6ebe56c..2d6c1ecb9 100644 --- a/src/java/com/threerings/presents/util/ClassUtil.java +++ b/src/java/com/threerings/presents/util/ClassUtil.java @@ -1,18 +1,21 @@ // -// $Id: ClassUtil.java,v 1.1 2001/07/19 07:09:16 mdb Exp $ +// $Id: ClassUtil.java,v 1.2 2001/08/14 06:48:08 mdb Exp $ package com.threerings.cocktail.cher.util; import java.lang.reflect.Method; import java.util.HashMap; +import com.samskivert.Log; +import com.samskivert.util.StringUtil; + /** * Class related utility functions. */ public class ClassUtil { /** - * Locates and returns teh first method in the supplied class whose + * Locates and returns the first method in the supplied class whose * name is equal to the specified name. If a method is located, it * will be cached in the supplied cache so that subsequent requests * will immediately return the method from the cache rather than @@ -37,6 +40,60 @@ public class ClassUtil return method; } + /** + * Looks up the method on the specified object that has a signature + * that matches the supplied arguments array. This has to create an + * array of class objects correspnding to the types of all of the + * arguments in the args array, so none of them are allowed to be + * null. This is very expensive, so you shouldn't be doing this for + * something that happens frequently. + * + *

Note: primitive types for arguments are preferred. What + * this means is that if an element of the args array is + * an instance of Integer, for example, then this code + * assumes that it is intended for that to be unwrapped into an + * int in calling the actual function. The reason this is + * necessary is that method lookup isn't smart about first checking + * for a method taking the primitive argument and then falling back to + * one taking an Integer object. So we insist that all + * arguments that can be unwrapped, are unwrapped. + * Why would you want to pass Integer objects as + * arguments to your function anyway? + * + * @return the best matching method with the specified name that + * accepts the supplied arguments, or null if no method could be + * found. + */ + public static Method getMethod (String name, Object target, Object[] args) + { + // grab a whole crapload of class objects + Class tclass = target.getClass(); + Class[] aclasses = new Class[args.length]; + for (int i = 0; i < aclasses.length; i++) { + Class aclass = args[i].getClass(); + Class mclass = (Class)_classMap.get(aclass); + // use the massaged class if there is one + aclasses[i] = (mclass == null) ? aclass : mclass; + } + + // now look up the method + Method meth = null; + try { + meth = tclass.getMethod(name, aclasses); + } catch (NoSuchMethodException nsme) { + // nothing to do here but fall through and return null + Log.info("No such method [name=" + name + + ", tclass=" + tclass.getName() + + ", args=" + StringUtil.toString(aclasses) + "]."); + + } catch (SecurityException se) { + Log.warning("Unable to look up method? " + + "[tclass=" + tclass.getName() + + ", mname=" + name + "]."); + } + return meth; + } + /** * Locates and returns the first method in the supplied class whose * name is equal to the specified name. @@ -54,4 +111,17 @@ public class ClassUtil } return null; } + + /** Used when massaging arguments into their primitive type. */ + protected static HashMap _classMap = new HashMap(); + static { + _classMap.put(Boolean.class, Boolean.TYPE); + _classMap.put(Byte.class, Byte.TYPE); + _classMap.put(Character.class, Character.TYPE); + _classMap.put(Short.class, Short.TYPE); + _classMap.put(Integer.class, Integer.TYPE); + _classMap.put(Long.class, Long.TYPE); + _classMap.put(Float.class, Float.TYPE); + _classMap.put(Double.class, Double.TYPE); + } }