Author: simonetripodi
Date: Sat Jan 29 20:37:28 2011
New Revision: 1065103

URL: http://svn.apache.org/viewvc?rev=1065103&view=rev
Log:
imported a tidy version of MethodUtils from commons-beanutils, that uses more 
Java5 features (Digester 2.X requires Java5)

Added:
    commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/
    
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
   (with props)

Added: 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java?rev=1065103&view=auto
==============================================================================
--- 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
 (added)
+++ 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
 Sat Jan 29 20:37:28 2011
@@ -0,0 +1,832 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * <p> Utility reflection methods focussed on methods in general rather than 
properties in particular. </p>
+ *
+ * <h3>Known Limitations</h3>
+ * <h4>Accessing Public Methods In A Default Access Superclass</h4>
+ * <p>There is an issue when invoking public methods contained in a default 
access superclass.
+ * Reflection locates these methods fine and correctly assigns them as public.
+ * However, an <code>IllegalAccessException</code> is thrown if the method is 
invoked.</p>
+ *
+ * <p><code>MethodUtils</code> contains a workaround for this situation. 
+ * It will attempt to call <code>setAccessible</code> on this method.
+ * If this call succeeds, then the method can be invoked as normal.
+ * This call will only succeed when the application has sufficient security 
privilages. 
+ * If this call fails then a warning will be logged and the method may 
fail.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey Fran&#231;ois
+ * @author Gregor Ra&#253;man
+ * @author Jan Sorensen
+ * @author Robert Burrell Donkin
+ */
+public class MethodUtils {
+
+    /** An empty class array */
+    private static final Class<?>[] EMPTY_CLASS_PARAMETERS = new Class[0];
+
+    /** An empty object array */
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    /**
+     * Stores a cache of MethodDescriptor -> Method in a WeakHashMap.
+     * <p>
+     * The keys into this map only ever exist as temporary variables within
+     * methods of this class, and are never exposed to users of this class.
+     * This means that the WeakHashMap is used only as a mechanism for 
+     * limiting the size of the cache, ie a way to tell the garbage collector
+     * that the contents of the cache can be completely garbage-collected 
+     * whenever it needs the memory. Whether this is a good approach to
+     * this problem is doubtful; something like the commons-collections
+     * LRUMap may be more appropriate (though of course selecting an
+     * appropriate size is an issue).
+     * <p>
+     * This static variable is safe even when this code is deployed via a
+     * shared classloader because it is keyed via a MethodDescriptor object
+     * which has a Class as one of its members and that member is used in
+     * the MethodDescriptor.equals method. So two components that load the same
+     * class via different classloaders will generate non-equal 
MethodDescriptor
+     * objects and hence end up with different entries in the map.
+     */
+    private static final Map<MethodDescriptor, Reference<Method>> CACHE =
+        Collections.synchronizedMap(new WeakHashMap<MethodDescriptor, 
Reference<Method>>());
+
+    /**
+     * Clear the method cache.
+     * @return the number of cached methods cleared
+     * @since 1.8.0
+     */
+    public static synchronized int clearCache() {
+        int size = CACHE.size();
+        CACHE.clear();
+        return size;
+    }
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod(Object object,String methodName,Object 
[] args)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeMethod(Object object,String methodName,Object [] 
args,Class[] parameterTypes)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(Object object,
+            String methodName,
+            Object...args) throws NoSuchMethodException, 
IllegalAccessException, InvocationTargetException {
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }
+
+        int arguments = args.length;
+        Class<?>[] parameterTypes = new Class<?>[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+
+        return invokeMethod(object, methodName, args, parameterTypes);
+    }
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link 
+     * #invokeExactMethod(Object object,String methodName,Object [] 
args,Class[] parameterTypes)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(Object object,
+            String methodName,
+            Object[] args,
+            Class<?>[] parameterTypes) throws NoSuchMethodException, 
IllegalAccessException, InvocationTargetException {
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }
+
+        Method method = getMatchingAccessibleMethod(object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException(String.format("No such accessible 
method: %s() on object: ",
+                    methodName,
+                    object.getClass().getName()));
+        }
+
+        return method.invoke(object, args);
+    }
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the object
+     * types.</p>
+     *
+     * <p> This uses reflection to invoke the method obtained from a call to
+     * <code>getAccessibleMethod()</code>.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object...args) throws NoSuchMethodException, 
IllegalAccessException, InvocationTargetException {
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }
+        int arguments = args.length;
+        Class<?>[] parameterTypes = new Class<?>[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeExactMethod(object, methodName, args, parameterTypes);
+    }
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the parameter
+     * types given.</p>
+     *
+     * <p>This uses reflection to invoke the method obtained from a call to
+     * <code>getAccessibleMethod()</code>.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(Object object,
+            String methodName,
+            Object[] args,
+            Class<?>[] parameterTypes) throws NoSuchMethodException, 
IllegalAccessException, InvocationTargetException {
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }
+
+        Method method = getAccessibleMethod(object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException(String.format("No such accessible 
method: %s() on object: %s",
+                    methodName,
+                    object.getClass().getName()));
+        }
+        return method.invoke(object, args);
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) with given name and parameters.  If no such method
+     * can be found, return <code>null</code>.
+     * This is just a convenient wrapper for
+     * {@link #getAccessibleMethod(Method method)}.</p>
+     *
+     * @param clazz get method from this class
+     * @param methodName get method with this name
+     * @param parameterTypes with these parameters types
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(Class<?> clazz, String 
methodName, Class<?>...parameterTypes) {
+        try {
+            MethodDescriptor md = new MethodDescriptor(clazz, methodName, 
parameterTypes, true);
+            // Check the cache first
+            Method method = getCachedMethod(md);
+            if (method != null) {
+                return method;
+            }
+
+            method =  getAccessibleMethod(clazz, clazz.getMethod(methodName, 
parameterTypes));
+            cacheMethod(md, method);
+            return method;
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified Method.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param method The method that we wish to call
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(Method method) {
+        // Make sure we have a method to check
+        if (method == null) {
+            return (null);
+        }
+
+        return getAccessibleMethod(method.getDeclaringClass(), method);
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified Method.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param clazz The class of the object
+     * @param method The method that we wish to call
+     * @return The accessible method
+     * @since 1.8.0
+     */
+    public static Method getAccessibleMethod(Class<?> clazz, Method method) {
+        // Make sure we have a method to check
+        if (method == null) {
+            return (null);
+        }
+
+        // If the requested method is not public we cannot call it
+        if (!Modifier.isPublic(method.getModifiers())) {
+            return (null);
+        }
+
+        boolean sameClass = true;
+        if (clazz == null) {
+            clazz = method.getDeclaringClass();
+        } else {
+            sameClass = clazz.equals(method.getDeclaringClass());
+            if (!method.getDeclaringClass().isAssignableFrom(clazz)) {
+                throw new IllegalArgumentException(String.format("%s is not 
assignable from %s",
+                        clazz.getName(),
+                        method.getDeclaringClass().getName()));
+            }
+        }
+
+        // If the class is public, we are done
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            if (!sameClass && 
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
+                setMethodAccessible(method); // Default access superclass 
workaround
+            }
+            return (method);
+        }
+
+        String methodName = method.getName();
+        Class<?>[] parameterTypes = method.getParameterTypes();
+
+        // Check the implemented interfaces and subinterfaces
+        method = getAccessibleMethodFromInterfaceNest(clazz, methodName, 
parameterTypes);
+
+        // Check the superclass chain
+        if (method == null) {
+            method = getAccessibleMethodFromSuperclass(clazz, methodName, 
parameterTypes);
+        }
+
+        return method;
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) by scanning through the superclasses. If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param clazz Class to be checked
+     * @param methodName Method name of the method we wish to call
+     * @param parameterTypes The parameter type signatures
+     */
+    private static Method getAccessibleMethodFromSuperclass(Class<?> clazz,
+            String methodName,
+            Class<?>...parameterTypes) {
+        Class<?> parentClazz = clazz.getSuperclass();
+        while (parentClazz != null) {
+            if (Modifier.isPublic(parentClazz.getModifiers())) {
+                try {
+                    return parentClazz.getMethod(methodName, parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    // swallow it
+                }
+            }
+            parentClazz = parentClazz.getSuperclass();
+        }
+        return null;
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified method, by scanning through
+     * all implemented interfaces and subinterfaces.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * <p> There isn't any good reason why this method must be private.
+     * It is because there doesn't seem any reason why other classes should
+     * call this rather than the higher level methods.</p>
+     *
+     * @param clazz Parent class for the interfaces to be checked
+     * @param methodName Method name of the method we wish to call
+     * @param parameterTypes The parameter type signatures
+     */
+    private static Method getAccessibleMethodFromInterfaceNest(Class<?> clazz,
+            String methodName,
+            Class<?>...parameterTypes) {
+        Method method = null;
+
+        // Search up the superclass chain
+        Class<?> parentClazz = clazz.getSuperclass();
+        while (parentClazz != null) {
+            // Check the implemented interfaces of the parent class
+            for (Class<?> interfaceType : clazz.getInterfaces()) {
+                // Is this interface public?
+                if (!Modifier.isPublic(interfaceType.getModifiers())) {
+                    continue;
+                }
+
+                // Does the method exist on this interface?
+                try {
+                    method = interfaceType.getDeclaredMethod(methodName, 
parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    /* Swallow, if no method is found after the loop then this
+                     * method returns null.
+                     */
+                }
+                if (method != null) {
+                    return method;
+                }
+
+                // Recursively check our parent interfaces
+                method = getAccessibleMethodFromInterfaceNest(interfaceType, 
methodName, parameterTypes);
+                if (method != null) {
+                    return method;
+                }
+            }
+
+            parentClazz = parentClazz.getSuperclass();
+        }
+
+        // We did not find anything
+        return null;
+    }
+
+    /**
+     * <p>Find an accessible method that matches the given name and has 
compatible parameters.
+     * Compatible parameters mean that every method parameter is assignable 
from 
+     * the given parameters.
+     * In other words, it finds a method with the given name 
+     * that will take the parameters given.<p>
+     *
+     * <p>This method is slightly undeterminstic since it loops 
+     * through methods names and return the first matching method.</p>
+     * 
+     * <p>This method is used by 
+     * {@link 
+     * #invokeMethod(Object object,String methodName,Object [] args,Class<?>[] 
parameterTypes)}.
+     *
+     * <p>This method can match primitive parameter by passing in wrapper 
classes.
+     * For example, a <code>Boolean</code> will match a primitive 
<code>boolean</code>
+     * parameter.
+     *
+     * @param clazz find method in this class
+     * @param methodName find method with this name
+     * @param parameterTypes find method with compatible parameters 
+     * @return The accessible method
+     */
+    public static Method getMatchingAccessibleMethod(Class<?> clazz, String 
methodName, Class<?>...parameterTypes) {
+        MethodDescriptor md = new MethodDescriptor(clazz, methodName, 
parameterTypes, false);
+
+        // see if we can find the method directly
+        // most of the time this works and it's much faster
+        try {
+            // Check the cache first
+            Method method = getCachedMethod(md);
+            if (method != null) {
+                return method;
+            }
+
+            method = clazz.getMethod(methodName, parameterTypes);
+            setMethodAccessible(method); // Default access superclass 
workaround
+
+            cacheMethod(md, method);
+            return method;
+
+        } catch (NoSuchMethodException e) {
+            /* SWALLOW */
+        }
+
+        // search through all methods 
+        int paramSize = parameterTypes.length;
+        Method bestMatch = null;
+        Method[] methods = clazz.getMethods();
+        float bestMatchCost = Float.MAX_VALUE;
+        float myCost = Float.MAX_VALUE;
+        for (int i = 0, size = methods.length; i < size ; i++) {
+            if (methods[i].getName().equals(methodName)) {
+                // compare parameters
+                Class<?>[] methodsParams = methods[i].getParameterTypes();
+                int methodParamSize = methodsParams.length;
+                if (methodParamSize == paramSize) {
+                    boolean match = true;
+                    for (int n = 0 ; n < methodParamSize; n++) {
+                        if (!isAssignmentCompatible(methodsParams[n], 
parameterTypes[n])) {
+                            match = false;
+                            break;
+                        }
+                    }
+
+                    if (match) {
+                        // get accessible version of method
+                        Method method = getAccessibleMethod(clazz, methods[i]);
+                        if (method != null) {
+                            setMethodAccessible(method); // Default access 
superclass workaround
+                            myCost = 
getTotalTransformationCost(parameterTypes,method.getParameterTypes());
+                            if ( myCost < bestMatchCost ) {
+                               bestMatch = method;
+                               bestMatchCost = myCost;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (bestMatch != null) {
+            cacheMethod(md, bestMatch);
+        } else {
+            // didn't find a match
+        }
+
+        return bestMatch;
+    }
+
+    /**
+     * Try to make the method accessible
+     * @param method The source arguments
+     */
+    private static void setMethodAccessible(Method method) {
+        try {
+            //
+            // XXX Default access superclass workaround
+            //
+            // When a public class has a default access superclass
+            // with public methods, these methods are accessible.
+            // Calling them from compiled code works fine.
+            //
+            // Unfortunately, using reflection to invoke these methods
+            // seems to (wrongly) to prevent access even when the method
+            // modifer is public.
+            //
+            // The following workaround solves the problem but will only
+            // work from sufficiently privilages code. 
+            //
+            // Better workarounds would be greatfully accepted.
+            //
+            if (!method.isAccessible()) {
+                method.setAccessible(true);
+            }
+        } catch (SecurityException se) {
+            // log but continue just in case the method.invoke works anyway
+        }
+    }
+
+    /**
+     * Returns the sum of the object transformation cost for each class in the 
source
+     * argument list.
+     * @param srcArgs The source arguments
+     * @param destArgs The destination arguments
+     * @return The total transformation cost
+     */
+    private static float getTotalTransformationCost(Class<?>[] srcArgs, 
Class<?>[] destArgs) {
+        float totalCost = 0.0f;
+        for (int i = 0; i < srcArgs.length; i++) {
+            totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]);
+        }
+        return totalCost;
+    }
+
+    /**
+     * Gets the number of steps required needed to turn the source class into 
the
+     * destination class. This represents the number of steps in the object 
hierarchy
+     * graph.
+     *
+     * @param srcClass The source class
+     * @param destClass The destination class
+     * @return The cost of transforming an object
+     */
+    private static float getObjectTransformationCost(Class<?> srcClass, 
Class<?> destClass) {
+        float cost = 0.0f;
+        while (srcClass != null && !destClass.equals(srcClass)) {
+            if (destClass.isPrimitive()) {
+                Class<?> destClassWrapperClazz = 
getPrimitiveWrapper(destClass);
+                if (destClassWrapperClazz != null && 
destClassWrapperClazz.equals(srcClass)) {
+                    cost += 0.25f;
+                    break;
+                }
+            }
+            if (destClass.isInterface() && 
isAssignmentCompatible(destClass,srcClass)) {
+                // slight penalty for interface match. 
+                // we still want an exact match to override an interface 
match, but  
+                // an interface match should override anything where we have 
to get a 
+                // superclass.
+                cost += 0.25f;
+                break;
+            }
+            cost++;
+            srcClass = srcClass.getSuperclass();
+        }
+
+        /*
+         * If the destination class is null, we've travelled all the way up to 
+         * an Object match. We'll penalize this by adding 1.5 to the cost.
+         */
+        if (srcClass == null) {
+            cost += 1.5f;
+        }
+
+        return cost;
+    }
+
+    /**
+     * <p>Determine whether a type can be used as a parameter in a method 
invocation.
+     * This method handles primitive conversions correctly.</p>
+     *
+     * <p>In order words, it will match a <code>Boolean</code> to a 
<code>boolean</code>,
+     * a <code>Long</code> to a <code>long</code>,
+     * a <code>Float</code> to a <code>float</code>,
+     * a <code>Integer</code> to a <code>int</code>,
+     * and a <code>Double</code> to a <code>double</code>.
+     * Now logic widening matches are allowed.
+     * For example, a <code>Long</code> will not match a <code>int</code>.
+     *
+     * @param parameterType the type of parameter accepted by the method
+     * @param parameterization the type of parameter being tested 
+     *
+     * @return true if the assignement is compatible.
+     */
+    public static final boolean isAssignmentCompatible(Class<?> parameterType, 
Class<?> parameterization) {
+        // try plain assignment
+        if (parameterType.isAssignableFrom(parameterization)) {
+            return true;
+        }
+
+        if (parameterType.isPrimitive()) {
+            // this method does *not* do widening - you must specify exactly
+            // is this the right behaviour?
+            Class<?> parameterWrapperClazz = 
getPrimitiveWrapper(parameterType);
+            if (parameterWrapperClazz != null) {
+                return parameterWrapperClazz.equals(parameterization);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets the wrapper object class for the given primitive type class.
+     * For example, passing <code>boolean.class</code> returns 
<code>Boolean.class</code>
+     * @param primitiveType the primitive type class for which a match is to 
be found
+     * @return the wrapper type associated with the given primitive 
+     * or null if no match is found
+     */
+    public static Class<?> getPrimitiveWrapper(Class<?> primitiveType) {
+        // does anyone know a better strategy than comparing names?
+        if (boolean.class.equals(primitiveType)) {
+            return Boolean.class;
+        } else if (float.class.equals(primitiveType)) {
+            return Float.class;
+        } else if (long.class.equals(primitiveType)) {
+            return Long.class;
+        } else if (int.class.equals(primitiveType)) {
+            return Integer.class;
+        } else if (short.class.equals(primitiveType)) {
+            return Short.class;
+        } else if (byte.class.equals(primitiveType)) {
+            return Byte.class;
+        } else if (double.class.equals(primitiveType)) {
+            return Double.class;
+        } else if (char.class.equals(primitiveType)) {
+            return Character.class;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the class for the primitive type corresponding to the primitive 
wrapper class given.
+     * For example, an instance of <code>Boolean.class</code> returns a 
<code>boolean.class</code>.
+     *
+     * @param wrapperType the 
+     * @return the primitive type class corresponding to the given wrapper 
class,
+     * null if no match is found
+     */
+    public static Class<?> getPrimitiveType(Class<?> wrapperType) {
+        // does anyone know a better strategy than comparing names?
+        if (Boolean.class.equals(wrapperType)) {
+            return boolean.class;
+        } else if (Float.class.equals(wrapperType)) {
+            return float.class;
+        } else if (Long.class.equals(wrapperType)) {
+            return long.class;
+        } else if (Integer.class.equals(wrapperType)) {
+            return int.class;
+        } else if (Short.class.equals(wrapperType)) {
+            return short.class;
+        } else if (Byte.class.equals(wrapperType)) {
+            return byte.class;
+        } else if (Double.class.equals(wrapperType)) {
+            return double.class;
+        } else if (Character.class.equals(wrapperType)) {
+            return char.class;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Find a non primitive representation for given primitive class.
+     *
+     * @param clazz the class to find a representation for, not null
+     * @return the original class if it not a primitive. Otherwise the wrapper 
class. Not null
+     */
+    public static Class<?> toNonPrimitiveClass(Class<?> clazz) {
+        if (clazz.isPrimitive()) {
+            Class<?> primitiveClazz = getPrimitiveWrapper(clazz);
+            // the above method returns 
+            if (primitiveClazz != null) {
+                return primitiveClazz;
+            }
+            return clazz;
+        }
+        return clazz;
+    }
+
+    /**
+     * Return the method from the cache, if present.
+     *
+     * @param md The method descriptor
+     * @return The cached method
+     */
+    private static Method getCachedMethod(MethodDescriptor md) {
+        Reference<Method> methodRef = CACHE.get(md);
+        if (methodRef != null) {
+            return methodRef.get();
+        }
+        return null;
+    }
+
+    /**
+     * Add a method to the cache.
+     *
+     * @param md The method descriptor
+     * @param method The method to cache
+     */
+    private static void cacheMethod(MethodDescriptor md, Method method) {
+        if (method != null) {
+            CACHE.put(md, new WeakReference<Method>(method));
+        }
+    }
+
+    /**
+     * Represents the key to looking up a Method by reflection.
+     */
+    private static class MethodDescriptor {
+
+        private final Class<?> cls;
+
+        private final String methodName;
+
+        private final Class<?>[] paramTypes;
+
+        private final boolean exact;
+
+        private final int hashCode;
+
+        /**
+         * The sole constructor.
+         *
+         * @param cls  the class to reflect, must not be null
+         * @param methodName  the method name to obtain
+         * @param paramTypes the array of classes representing the paramater 
types
+         * @param exact whether the match has to be exact.
+         */
+        public MethodDescriptor(Class<?> cls, String methodName, Class<?>[] 
paramTypes, boolean exact) {
+            if (cls == null) {
+                throw new IllegalArgumentException("Class cannot be null");
+            }
+            if (methodName == null) {
+                throw new IllegalArgumentException("Method Name cannot be 
null");
+            }
+            if (paramTypes == null) {
+                paramTypes = EMPTY_CLASS_PARAMETERS;
+            }
+
+            this.cls = cls;
+            this.methodName = methodName;
+            this.paramTypes = paramTypes;
+            this.exact= exact;
+
+            this.hashCode = methodName.length();
+        }
+
+        /**
+         * Checks for equality.
+         *
+         * @param obj object to be tested for equality
+         * @return true, if the object describes the same Method.
+         */
+        public boolean equals(Object obj) {
+            if (!(obj instanceof MethodDescriptor)) {
+                return false;
+            }
+            MethodDescriptor md = (MethodDescriptor) obj;
+
+            return (this.exact == md.exact
+                    && this.methodName.equals(md.methodName)
+                    && this.cls.equals(md.cls)
+                    && Arrays.equals(this.paramTypes, md.paramTypes));
+        }
+
+        /**
+         * Returns the string length of method name. I.e. if the
+         * hashcodes are different, the objects are different. If the
+         * hashcodes are the same, need to use the equals method to
+         * determine equality.
+         *
+         * @return the string length of method name.
+         */
+        public int hashCode() {
+            return this.hashCode;
+        }
+
+    }
+
+}

Propchange: 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/beanutils/MethodUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to