rdonkin     2004/09/16 14:01:28

  Modified:    beanutils/src/java/org/apache/commons/beanutils
                        MethodUtils.java
  Log:
  Patch to make method selection more rational. Submitted by Steve Cohen
  
  Revision  Changes    Path
  1.28      +80 -16    
jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/MethodUtils.java
  
  Index: MethodUtils.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/MethodUtils.java,v
  retrieving revision 1.27
  retrieving revision 1.28
  diff -u -r1.27 -r1.28
  --- MethodUtils.java  18 Jul 2004 14:58:22 -0000      1.27
  +++ MethodUtils.java  16 Sep 2004 21:01:28 -0000      1.28
  @@ -27,7 +27,6 @@
   import org.apache.commons.logging.LogFactory;
   
   
  -
   /**
    * <p> Utility reflection methods focussed on methods in general rather than 
properties in particular. </p>
    *
  @@ -46,8 +45,8 @@
    * @author Craig R. McClanahan
    * @author Ralph Schaer
    * @author Chris Audley
  - * @author Rey Fran�ois
  - * @author Gregor Ra�man
  + * @author Rey Fran&#231;ois
  + * @author Gregor Ra&#253;man
    * @author Jan Sorensen
    * @author Robert Burrell Donkin
    */
  @@ -560,22 +559,22 @@
               } catch (SecurityException se) {
                   // log but continue just in case the method.invoke works anyway
                   if (!loggedAccessibleWarning) {
  -                    boolean vunerableJVM = false;
  +                    boolean vulnerableJVM = false;
                       try {
                           String specVersion = 
System.getProperty("java.specification.version");
                           if (specVersion.charAt(0) == '1' && 
  -                                (specVersion.charAt(0) == '0' ||
  -                                 specVersion.charAt(0) == '1' ||
  -                                 specVersion.charAt(0) == '2' ||
  -                                 specVersion.charAt(0) == '3')) {
  +                                (specVersion.charAt(2) == '0' ||
  +                                 specVersion.charAt(2) == '1' ||
  +                                 specVersion.charAt(2) == '2' ||
  +                                 specVersion.charAt(2) == '3')) {
                                    
  -                            vunerableJVM = true;
  +                            vulnerableJVM = true;
                           }
                       } catch (SecurityException e) {
                           // don't know - so display warning
  -                        vunerableJVM = true;
  +                        vulnerableJVM = true;
                       }
  -                    if (vunerableJVM) {
  +                    if (vulnerableJVM) {
                           log.warn(
                               "Current Security Manager restricts use of workarounds 
for reflection bugs "
                               + " in pre-1.4 JVMs.");
  @@ -593,7 +592,10 @@
           
           // 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)) {   
                   // log some trace information
  @@ -648,8 +650,11 @@
               "Cannot setAccessible on method. Therefore cannot use jvm access bug 
workaround.", 
                                           se);
                               }
  -                            cache.put(md, method);
  -                            return method;
  +                            myCost = 
getTotalTransformationCost(parameterTypes,method.getParameterTypes());
  +                            if ( myCost < bestMatchCost ) {
  +                               bestMatch = method;
  +                               bestMatchCost = myCost;
  +                            }
                           }
                           
                           log.trace("Couldn't find accessible method.");
  @@ -657,12 +662,71 @@
                   }
               }
           }
  -        
  +        if ( bestMatch != null ){
  +                 cache.put(md, bestMatch);  
  +        } else {
           // didn't find a match
  -        log.trace("No match found.");
  -        return null;                                        
  +               log.trace("No match found.");
  +        }
  +        
  +        return bestMatch;                                        
       }
   
  +    /**
  +     * Returns the sum of the object transformation cost for each class in the 
source
  +     * argument list.
  +     * @param srcArgs The list of arguments to transform
  +     * @param destArgs 
  +     * @return
  +     */
  +    private static float getTotalTransformationCost(Class[] srcArgs, Class[] 
destArgs) {
  +
  +        float totalCost = 0.0f;
  +        for (int i = 0; i < srcArgs.length; i++) {
  +            Class srcClass, destClass;
  +            srcClass = srcArgs[i];
  +            destClass = destArgs[i];
  +            totalCost += getObjectTransformationCost(srcClass, destClass);
  +        }
  +
  +        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
  +     * @param destClass
  +     * @return
  +     */
  +    private static float getObjectTransformationCost(Class srcClass, Class 
destClass) {
  +        float cost = 0.0f;
  +        while (destClass != null && !destClass.equals(srcClass)) {
  +            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++;
  +            destClass = destClass.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 (destClass == 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>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to