Coverage Report - org.mule.util.ClassUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassUtils
69%
134/193
70%
103/148
4.108
ClassUtils$1
100%
3/3
50%
1/2
4.108
ClassUtils$10
100%
4/4
N/A
4.108
ClassUtils$2
100%
2/2
N/A
4.108
ClassUtils$3
100%
2/2
N/A
4.108
ClassUtils$4
60%
3/5
50%
1/2
4.108
ClassUtils$5
0%
0/4
N/A
4.108
ClassUtils$6
0%
0/4
N/A
4.108
ClassUtils$7
100%
5/5
50%
1/2
4.108
ClassUtils$8
100%
4/4
N/A
4.108
ClassUtils$9
100%
4/4
N/A
4.108
 
 1  
 /*
 2  
  * $Id: ClassUtils.java 12253 2008-07-08 04:49:39Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.util;
 12  
 
 13  
 import org.mule.routing.filters.WildcardFilter;
 14  
 
 15  
 import java.io.BufferedReader;
 16  
 import java.io.CharArrayReader;
 17  
 import java.io.IOException;
 18  
 import java.io.Reader;
 19  
 import java.lang.reflect.Constructor;
 20  
 import java.lang.reflect.InvocationTargetException;
 21  
 import java.lang.reflect.Method;
 22  
 import java.lang.reflect.Modifier;
 23  
 import java.net.URL;
 24  
 import java.security.AccessController;
 25  
 import java.security.PrivilegedAction;
 26  
 import java.util.ArrayList;
 27  
 import java.util.Collection;
 28  
 import java.util.Collections;
 29  
 import java.util.Enumeration;
 30  
 import java.util.HashMap;
 31  
 import java.util.List;
 32  
 import java.util.Map;
 33  
 import java.util.Set;
 34  
 
 35  
 /**
 36  
  * Extend the Apache Commons ClassUtils to provide additional functionality.
 37  
  * <p/>
 38  
  * <p>This class is useful for loading resources and classes in a fault tolerant manner
 39  
  * that works across different applications servers. The resource and classloading
 40  
  * methods are SecurityManager friendly.</p>
 41  
  */
 42  
 // @ThreadSafe
 43  0
 public class ClassUtils extends org.apache.commons.lang.ClassUtils
 44  
 {
 45  2
     public static final Object[] NO_ARGS = new Object[]{};
 46  2
     public static final Class[] NO_ARGS_TYPE = new Class[]{};
 47  
 
 48  2
     private static final Map wrapperToPrimitiveMap = new HashMap();
 49  
 
 50  
     static
 51  
     {
 52  2
         wrapperToPrimitiveMap.put(Boolean.class, Boolean.TYPE);
 53  2
         wrapperToPrimitiveMap.put(Byte.class, Byte.TYPE);
 54  2
         wrapperToPrimitiveMap.put(Character.class, Character.TYPE);
 55  2
         wrapperToPrimitiveMap.put(Short.class, Short.TYPE);
 56  2
         wrapperToPrimitiveMap.put(Integer.class, Integer.TYPE);
 57  2
         wrapperToPrimitiveMap.put(Long.class, Long.TYPE);
 58  2
         wrapperToPrimitiveMap.put(Double.class, Double.TYPE);
 59  2
         wrapperToPrimitiveMap.put(Float.class, Float.TYPE);
 60  2
         wrapperToPrimitiveMap.put(Void.TYPE, Void.TYPE);
 61  2
     }
 62  
 
 63  
     public static boolean isConcrete(Class clazz)
 64  
     {
 65  8
         if (clazz == null)
 66  
         {
 67  2
             throw new IllegalArgumentException("clazz may not be null");
 68  
         }
 69  6
         return !(clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()));
 70  
     }
 71  
 
 72  
     /**
 73  
      * Load a given resource. <p/> This method will try to load the resource using
 74  
      * the following methods (in order):
 75  
      * <ul>
 76  
      * <li>From
 77  
      * {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
 78  
      * <li>From
 79  
      * {@link Class#getClassLoader() ClassUtils.class.getClassLoader()}
 80  
      * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
 81  
      * </ul>
 82  
      *
 83  
      * @param resourceName The name of the resource to load
 84  
      * @param callingClass The Class object of the calling object
 85  
      */
 86  
     public static URL getResource(final String resourceName, final Class callingClass)
 87  
     {
 88  1582
         URL url = (URL) AccessController.doPrivileged(new PrivilegedAction()
 89  
         {
 90  1582
             public Object run()
 91  
             {
 92  1582
                 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 93  1582
                 return cl != null ? cl.getResource(resourceName) : null;
 94  
             }
 95  
         });
 96  
 
 97  1582
         if (url == null)
 98  
         {
 99  1176
             url = (URL) AccessController.doPrivileged(new PrivilegedAction()
 100  
             {
 101  1176
                 public Object run()
 102  
                 {
 103  1176
                     return ClassUtils.class.getClassLoader().getResource(resourceName);
 104  
                 }
 105  
             });
 106  
         }
 107  
 
 108  1582
         if (url == null)
 109  
         {
 110  1176
             url = (URL) AccessController.doPrivileged(new PrivilegedAction()
 111  
             {
 112  1176
                 public Object run()
 113  
                 {
 114  1176
                     return callingClass.getClassLoader().getResource(resourceName);
 115  
                 }
 116  
             });
 117  
         }
 118  
 
 119  1582
         return url;
 120  
     }
 121  
 
 122  
     public static Enumeration getResources(final String resourceName, final Class callingClass)
 123  
     {
 124  1150
         Enumeration enumeration = (Enumeration) AccessController.doPrivileged(new PrivilegedAction()
 125  
         {
 126  1150
             public Object run()
 127  
             {
 128  
                 try
 129  
                 {
 130  1150
                     final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 131  1150
                     return cl != null ? cl.getResources(resourceName) : null;
 132  
                 }
 133  0
                 catch (IOException e)
 134  
                 {
 135  0
                     return null;
 136  
                 }
 137  
             }
 138  
         });
 139  
 
 140  1150
         if (enumeration == null)
 141  
         {
 142  0
             enumeration = (Enumeration) AccessController.doPrivileged(new PrivilegedAction()
 143  
             {
 144  0
                 public Object run()
 145  
                 {
 146  
                     try
 147  
                     {
 148  0
                         return ClassUtils.class.getClassLoader().getResources(resourceName);
 149  
                     }
 150  0
                     catch (IOException e)
 151  
                     {
 152  0
                         return null;
 153  
                     }
 154  
                 }
 155  
             });
 156  
         }
 157  
 
 158  1150
         if (enumeration == null)
 159  
         {
 160  0
             enumeration = (Enumeration) AccessController.doPrivileged(new PrivilegedAction()
 161  
             {
 162  0
                 public Object run()
 163  
                 {
 164  
                     try
 165  
                     {
 166  0
                         return callingClass.getClassLoader().getResources(resourceName);
 167  
                     }
 168  0
                     catch (IOException e)
 169  
                     {
 170  0
                         return null;
 171  
                     }
 172  
                 }
 173  
             });
 174  
         }
 175  
 
 176  1150
         return enumeration;
 177  
     }
 178  
 
 179  
     /**
 180  
      * Load a class with a given name. <p/> It will try to load the class in the
 181  
      * following order:
 182  
      * <ul>
 183  
      * <li>From
 184  
      * {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
 185  
      * <li>Using the basic {@link Class#forName(java.lang.String) }
 186  
      * <li>From
 187  
      * {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
 188  
      * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
 189  
      * </ul>
 190  
      *
 191  
      * @param className    The name of the class to load
 192  
      * @param callingClass The Class object of the calling object
 193  
      * @throws ClassNotFoundException If the class cannot be found anywhere.
 194  
      */
 195  
     public static Class loadClass(final String className, final Class callingClass)
 196  
             throws ClassNotFoundException
 197  
     {
 198  20720
         Class clazz = (Class) AccessController.doPrivileged(new PrivilegedAction()
 199  
         {
 200  20720
             public Object run()
 201  
             {
 202  
                 try
 203  
                 {
 204  20720
                     final ClassLoader cl = Thread.currentThread().getContextClassLoader();
 205  20720
                     return cl != null ? cl.loadClass(className) : null;
 206  
 
 207  
                 }
 208  10
                 catch (ClassNotFoundException e)
 209  
                 {
 210  10
                     return null;
 211  
                 }
 212  
             }
 213  
         });
 214  
 
 215  20720
         if (clazz == null)
 216  
         {
 217  10
             clazz = (Class) AccessController.doPrivileged(new PrivilegedAction()
 218  
             {
 219  10
                 public Object run()
 220  
                 {
 221  
                     try
 222  
                     {
 223  10
                         return Class.forName(className);
 224  
                     }
 225  10
                     catch (ClassNotFoundException e)
 226  
                     {
 227  10
                         return null;
 228  
                     }
 229  
                 }
 230  
             });
 231  
         }
 232  
 
 233  20720
         if (clazz == null)
 234  
         {
 235  10
             clazz = (Class) AccessController.doPrivileged(new PrivilegedAction()
 236  
             {
 237  10
                 public Object run()
 238  
                 {
 239  
                     try
 240  
                     {
 241  10
                         return ClassUtils.class.getClassLoader().loadClass(className);
 242  
                     }
 243  10
                     catch (ClassNotFoundException e)
 244  
                     {
 245  10
                         return null;
 246  
                     }
 247  
                 }
 248  
             });
 249  
         }
 250  
 
 251  20720
         if (clazz == null)
 252  
         {
 253  10
             clazz = (Class) AccessController.doPrivileged(new PrivilegedAction()
 254  
             {
 255  10
                 public Object run()
 256  
                 {
 257  
                     try
 258  
                     {
 259  10
                         return callingClass.getClassLoader().loadClass(className);
 260  
                     }
 261  10
                     catch (ClassNotFoundException e)
 262  
                     {
 263  10
                         return null;
 264  
                     }
 265  
                 }
 266  
             });
 267  
         }
 268  
 
 269  20720
         if (clazz == null)
 270  
         {
 271  10
             throw new ClassNotFoundException(className);
 272  
         }
 273  
 
 274  20710
         return clazz;
 275  
     }
 276  
 
 277  
     /** Prints the current classloader hierarchy - useful for debugging. */
 278  
     public static void printClassLoader()
 279  
     {
 280  0
         System.out.println("ClassLoaderUtils.printClassLoader");
 281  0
         printClassLoader(Thread.currentThread().getContextClassLoader());
 282  0
     }
 283  
 
 284  
     /**
 285  
      * Prints the classloader hierarchy from a given classloader - useful for
 286  
      * debugging.
 287  
      */
 288  
     public static void printClassLoader(ClassLoader cl)
 289  
     {
 290  0
         System.out.println("ClassLoaderUtils.printClassLoader(cl = " + cl + ")");
 291  
 
 292  0
         if (cl != null)
 293  
         {
 294  0
             printClassLoader(cl.getParent());
 295  
         }
 296  0
     }
 297  
 
 298  
     /**
 299  
      * Ensure that the given class is properly initialized when the argument is passed in
 300  
      * as .class literal. This method can never fail unless the bytecode is corrupted or
 301  
      * the VM is otherwise seriously confused.
 302  
      * 
 303  
      * @param clazz the Class to be initialized
 304  
      * @return the same class but initialized
 305  
      */
 306  
     public static Class initializeClass(Class clazz)
 307  
     {
 308  
         try
 309  
         {
 310  3484
             return getClass(clazz.getName(), true);
 311  
         }
 312  0
         catch (ClassNotFoundException e)
 313  
         {
 314  0
             IllegalStateException ise = new IllegalStateException();
 315  0
             ise.initCause(e);
 316  0
             throw ise;
 317  
         }
 318  
     }
 319  
 
 320  
     public static Object instanciateClass(Class clazz, Object[] constructorArgs)
 321  
             throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException,
 322  
             IllegalAccessException, InvocationTargetException
 323  
     {
 324  
         Class[] args;
 325  20696
         if (constructorArgs != null)
 326  
         {
 327  20682
             args = new Class[constructorArgs.length];
 328  20686
             for (int i = 0; i < constructorArgs.length; i++)
 329  
             {
 330  4
                 if (constructorArgs[i] == null)
 331  
                 {
 332  0
                     args[i] = null;
 333  
                 }
 334  
                 else
 335  
                 {
 336  4
                     args[i] = constructorArgs[i].getClass();
 337  
                 }
 338  
             }
 339  
         }
 340  
         else
 341  
         {
 342  14
             args = new Class[0];
 343  
         }
 344  
 
 345  
         // try the arguments as given
 346  20696
         Constructor ctor = getConstructor(clazz, args);
 347  
 
 348  20696
         if (ctor == null)
 349  
         {
 350  
             // try again but adapt value classes to primitives
 351  0
             ctor = getConstructor(clazz, wrappersToPrimitives(args));
 352  
         }
 353  
 
 354  20696
         if (ctor == null)
 355  
         {
 356  0
             StringBuffer argsString = new StringBuffer(100);
 357  0
             for (int i = 0; i < args.length; i++)
 358  
             {
 359  0
                 argsString.append(args[i].getName()).append(", ");
 360  
             }
 361  0
             throw new NoSuchMethodException("could not find constructor with matching arg params: "
 362  
                     + argsString);
 363  
         }
 364  
 
 365  20696
         return ctor.newInstance(constructorArgs);
 366  
     }
 367  
 
 368  
     public static Object instanciateClass(String name, Object[] constructorArgs)
 369  
             throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
 370  
             InstantiationException, IllegalAccessException, InvocationTargetException
 371  
     {
 372  19758
         Class clazz = loadClass(name, ClassUtils.class);
 373  19752
         return instanciateClass(clazz, constructorArgs);
 374  
 
 375  
     }
 376  
 
 377  
     public static Object instanciateClass(String name, Object[] constructorArgs, Class callingClass)
 378  
             throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,
 379  
             InstantiationException, IllegalAccessException, InvocationTargetException
 380  
     {
 381  472
         Class clazz = loadClass(name, callingClass);
 382  472
         return instanciateClass(clazz, constructorArgs);
 383  
     }
 384  
 
 385  
     public static Class[] getParameterTypes(Object bean, String methodName)
 386  
     {
 387  4
         if (!methodName.startsWith("set"))
 388  
         {
 389  4
             methodName = "set" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
 390  
         }
 391  
 
 392  4
         Method methods[] = bean.getClass().getMethods();
 393  
 
 394  64
         for (int i = 0; i < methods.length; i++)
 395  
         {
 396  62
             if (methods[i].getName().equals(methodName))
 397  
             {
 398  2
                 return methods[i].getParameterTypes();
 399  
             }
 400  
         }
 401  
 
 402  2
         return new Class[]{};
 403  
     }
 404  
 
 405  
     /**
 406  
      * Returns a matching method for the given name and parameters on the given class
 407  
      * If the parameterTypes arguments is null it will return the first matching
 408  
      * method on the class.
 409  
      *
 410  
      * @param clazz          the class to find the method on
 411  
      * @param name           the method name to find
 412  
      * @param parameterTypes an array of argument types or null
 413  
      * @return the Method object or null if none was found
 414  
      */
 415  
     public static Method getMethod(Class clazz, String name, Class[] parameterTypes)
 416  
     {
 417  48
         Method[] methods = clazz.getMethods();
 418  3100
         for (int i = 0; i < methods.length; i++)
 419  
         {
 420  3062
             if (methods[i].getName().equals(name))
 421  
             {
 422  10
                 if (parameterTypes == null)
 423  
                 {
 424  0
                     return methods[i];
 425  
                 }
 426  10
                 else if (compare(methods[i].getParameterTypes(), parameterTypes, true))
 427  
                 {
 428  10
                     return methods[i];
 429  
                 }
 430  
             }
 431  
         }
 432  38
         return null;
 433  
     }
 434  
 
 435  
     public static Constructor getConstructor(Class clazz, Class[] paramTypes)
 436  
     {
 437  24180
         Constructor[] ctors = clazz.getConstructors();
 438  24184
         for (int i = 0; i < ctors.length; i++)
 439  
         {
 440  24184
             Class[] types = ctors[i].getParameterTypes();
 441  24184
             if (types.length == paramTypes.length)
 442  
             {
 443  24180
                 boolean match = true;
 444  31152
                 for (int x = 0; x < types.length; x++)
 445  
                 {
 446  6972
                     if (paramTypes[x] == null)
 447  
                     {
 448  0
                         match = true;
 449  
                     }
 450  
                     else
 451  
                     {
 452  6972
                         match = types[x].isAssignableFrom(paramTypes[x]);
 453  
                     }
 454  
                 }
 455  24180
                 if (match)
 456  
                 {
 457  24180
                     return ctors[i];
 458  
                 }
 459  
             }
 460  
         }
 461  0
         return null;
 462  
     }
 463  
 
 464  
     /**
 465  
      * A helper method that will find all matching methods on a class with the given
 466  
      * parameter type
 467  
      *
 468  
      * @param implementation     the class to build methods on
 469  
      * @param parameterTypes     the argument param types to look for
 470  
      * @param voidOk             whether void methods shouldbe included in the found list
 471  
      * @param matchOnObject      determines whether parameters of Object type are matched
 472  
      *                           when they are of Object.class type
 473  
      * @param ignoredMethodNames a Set of method names to ignore. Often 'equals' is
 474  
      *                           not a desired match. This argument can be null.
 475  
      * @return a List of methods on the class that match the criteria. If there are
 476  
      *         none, an empty list is returned
 477  
      */
 478  
     public static List getSatisfiableMethods(Class implementation,
 479  
                                              Class[] parameterTypes,
 480  
                                              boolean voidOk,
 481  
                                              boolean matchOnObject,
 482  
                                              Set ignoredMethodNames)
 483  
     {
 484  48
         return getSatisfiableMethods(implementation, parameterTypes, voidOk, matchOnObject, ignoredMethodNames, null);
 485  
     }
 486  
 
 487  
     /**
 488  
      * A helper method that will find all matching methods on a class with the given
 489  
      * parameter type
 490  
      *
 491  
      * @param implementation     the class to build methods on
 492  
      * @param parameterTypes     the argument param types to look for
 493  
      * @param voidOk             whether void methods shouldbe included in the found list
 494  
      * @param matchOnObject      determines whether parameters of Object type are matched
 495  
      *                           when they are of Object.class type
 496  
      * @param ignoredMethodNames a Set of method names to ignore. Often 'equals' is
 497  
      *                           not a desired match. This argument can be null.
 498  
      * @return a List of methods on the class that match the criteria. If there are
 499  
      *         none, an empty list is returned
 500  
      */
 501  
     public static List getSatisfiableMethods(Class implementation,
 502  
                                              Class[] parameterTypes,
 503  
                                              boolean voidOk,
 504  
                                              boolean matchOnObject,
 505  
                                              Collection ignoredMethodNames,
 506  
                                              WildcardFilter filter)
 507  
     {
 508  
 
 509  
 
 510  110
         List result = new ArrayList();
 511  
 
 512  110
         if (ignoredMethodNames == null)
 513  
         {
 514  0
             ignoredMethodNames = Collections.EMPTY_SET;
 515  
         }
 516  
 
 517  110
         Method[] methods = implementation.getMethods();
 518  2078
         for (int i = 0; i < methods.length; i++)
 519  
         {
 520  1968
             Method method = methods[i];
 521  
             //supporting wildcards
 522  1968
             if (filter != null && filter.accept(method.getName()))
 523  
             {
 524  740
                 continue;
 525  
             }
 526  1228
             Class[] methodParams = method.getParameterTypes();
 527  
 
 528  1228
             if (compare(methodParams, parameterTypes, matchOnObject))
 529  
             {
 530  144
                 if (!ignoredMethodNames.contains(method.getName()))
 531  
                 {
 532  98
                     String returnType = method.getReturnType().getName();
 533  98
                     if ((returnType.equals("void") && voidOk) || !returnType.equals("void"))
 534  
                     {
 535  70
                         result.add(method);
 536  
                     }
 537  
                 }
 538  
             }
 539  
         }
 540  
 
 541  110
         return result;
 542  
     }
 543  
 
 544  
     public static List getSatisfiableMethodsWithReturnType(Class implementation,
 545  
                                                            Class returnType,
 546  
                                                            boolean matchOnObject,
 547  
                                                            Set ignoredMethodNames)
 548  
     {
 549  0
         List result = new ArrayList();
 550  
 
 551  0
         if (ignoredMethodNames == null)
 552  
         {
 553  0
             ignoredMethodNames = Collections.EMPTY_SET;
 554  
         }
 555  
 
 556  0
         Method[] methods = implementation.getMethods();
 557  0
         for (int i = 0; i < methods.length; i++)
 558  
         {
 559  0
             Method method = methods[i];
 560  0
             Class returns = method.getReturnType();
 561  
 
 562  0
             if (compare(new Class[]{returns}, new Class[]{returnType}, matchOnObject))
 563  
             {
 564  0
                 if (!ignoredMethodNames.contains(method.getName()))
 565  
                 {
 566  0
                     result.add(method);
 567  
                 }
 568  
             }
 569  
         }
 570  
 
 571  0
         return result;
 572  
     }
 573  
 
 574  
     /**
 575  
      * Can be used by serice endpoints to select which service to use based on what's
 576  
      * loaded on the classpath
 577  
      *
 578  
      * @param className    The class name to look for
 579  
      * @param currentClass the calling class
 580  
      * @return true if the class is on the path
 581  
      */
 582  
     public static boolean isClassOnPath(String className, Class currentClass)
 583  
     {
 584  
         try
 585  
         {
 586  0
             return (loadClass(className, currentClass) != null);
 587  
         }
 588  0
         catch (ClassNotFoundException e)
 589  
         {
 590  0
             return false;
 591  
         }
 592  
     }
 593  
 
 594  
     /**
 595  
      * Used for creating an array of class types for an array or single object
 596  
      *
 597  
      * @param object single object or array. If this parameter is null or a zero length
 598  
      *               array then {@link #NO_ARGS_TYPE} is returned
 599  
      * @return an array of class types for the object
 600  
      */
 601  
     public static Class[] getClassTypes(Object object)
 602  
     {
 603  130
         if (object == null)
 604  
         {
 605  0
             return NO_ARGS_TYPE;
 606  
         }
 607  
 
 608  
         Class[] types;
 609  
 
 610  130
         if (object instanceof Object[])
 611  
         {
 612  130
             Object[] objects = (Object[]) object;
 613  130
             if (objects.length == 0)
 614  
             {
 615  8
                 return NO_ARGS_TYPE;
 616  
             }
 617  122
             types = new Class[objects.length];
 618  278
             for (int i = 0; i < objects.length; i++)
 619  
             {
 620  156
                 types[i] = objects[i].getClass();
 621  
             }
 622  122
         }
 623  
         else
 624  
         {
 625  0
             types = new Class[]{object.getClass()};
 626  
         }
 627  
 
 628  122
         return types;
 629  
     }
 630  
 
 631  
     public static String getClassName(Class clazz)
 632  
     {
 633  13172
         if (clazz == null)
 634  
         {
 635  0
             return null;
 636  
         }
 637  13172
         String name = clazz.getName();
 638  13172
         return name.substring(name.lastIndexOf(".") + 1);
 639  
     }
 640  
 
 641  
     public static boolean compare(Class[] c1, Class[] c2, boolean matchOnObject)
 642  
     {
 643  1242
         if (c1.length != c2.length)
 644  
         {
 645  804
             return false;
 646  
         }
 647  580
         for (int i = 0; i < c1.length; i++)
 648  
         {
 649  422
             if (c1[i].equals(Object.class) && !matchOnObject)
 650  
             {
 651  14
                 return false;
 652  
             }
 653  408
             if (!c1[i].isAssignableFrom(c2[i]))
 654  
             {
 655  
 
 656  266
                 return false;
 657  
             }
 658  
         }
 659  158
         return true;
 660  
     }
 661  
 
 662  
     public static Class wrapperToPrimitive(Class wrapper)
 663  
     {
 664  0
         return (Class) MapUtils.getObject(wrapperToPrimitiveMap, wrapper, wrapper);
 665  
     }
 666  
 
 667  
     public static Class[] wrappersToPrimitives(Class[] wrappers)
 668  
     {
 669  0
         if (wrappers == null)
 670  
         {
 671  0
             return null;
 672  
         }
 673  
 
 674  0
         if (wrappers.length == 0)
 675  
         {
 676  0
             return wrappers;
 677  
         }
 678  
 
 679  0
         Class[] primitives = new Class[wrappers.length];
 680  
 
 681  0
         for (int i = 0; i < wrappers.length; i++)
 682  
         {
 683  0
             primitives[i] = (Class) MapUtils.getObject(wrapperToPrimitiveMap, wrappers[i], wrappers[i]);
 684  
         }
 685  
 
 686  0
         return primitives;
 687  
     }
 688  
 
 689  
     /**
 690  
      * Provide a simple-to-understand class name (with access to only Java 1.4 API).
 691  
      *
 692  
      * @param clazz The class whose name we will generate
 693  
      * @return A readable name for the class
 694  
      */
 695  
     public static String getSimpleName(Class clazz)
 696  
     {
 697  21154
         if (null == clazz)
 698  
         {
 699  2
             return "null";
 700  
         }
 701  
         else
 702  
         {
 703  21152
             return classNameHelper(new BufferedReader(new CharArrayReader(clazz.getName().toCharArray())));
 704  
         }
 705  
     }
 706  
 
 707  
     private static String classNameHelper(Reader encodedName)
 708  
     {
 709  
         // I did consider separating this data from the code, but I could not find a
 710  
         // solution that was as clear to read, or clearly motivated (these data are not
 711  
         // used elsewhere).
 712  
 
 713  
         try
 714  
         {
 715  22338
             encodedName.mark(1);
 716  22338
             switch (encodedName.read())
 717  
             {
 718  
                 case -1:
 719  0
                     return "null";
 720  
                 case 'Z':
 721  0
                     return "boolean";
 722  
                 case 'B':
 723  1176
                     return "byte";
 724  
                 case 'C':
 725  0
                     return "char";
 726  
                 case 'D':
 727  0
                     return "double";
 728  
                 case 'F':
 729  0
                     return "float";
 730  
                 case 'I':
 731  2
                     return "int";
 732  
                 case 'J':
 733  0
                     return "long";
 734  
                 case 'S':
 735  0
                     return "short";
 736  
                 case '[':
 737  1186
                     return classNameHelper(encodedName) + "[]";
 738  
                 case 'L':
 739  6
                     return shorten(new BufferedReader(encodedName).readLine());
 740  
                 default:
 741  19968
                     encodedName.reset();
 742  19968
                     return shorten(new BufferedReader(encodedName).readLine());
 743  
             }
 744  
         }
 745  0
         catch (IOException e)
 746  
         {
 747  0
             return "unknown type: " + e.getMessage();
 748  
         }
 749  
     }
 750  
 
 751  
     /**
 752  
      * @param clazz A class name (with possible package and trailing semicolon)
 753  
      * @return The short name for the class
 754  
      */
 755  
     private static String shorten(String clazz)
 756  
     {
 757  19974
         if (null != clazz && clazz.endsWith(";"))
 758  
         {
 759  6
             clazz = clazz.substring(0, clazz.length() - 1);
 760  
         }
 761  19974
         if (null != clazz && clazz.lastIndexOf(".") > -1)
 762  
         {
 763  19974
             clazz = clazz.substring(clazz.lastIndexOf(".") + 1, clazz.length());
 764  
         }
 765  19974
         return clazz;
 766  
     }
 767  
 
 768  
     /**
 769  
      * Is there a better place for this?  Simple helper for writing object equalities.
 770  
      */
 771  
     public static boolean equal(Object a, Object b)
 772  
     {
 773  300
         if (null == a)
 774  
         {
 775  226
             return null == b;
 776  
         }
 777  
         else
 778  
         {
 779  74
             return null != b && a.equals(b);
 780  
         }
 781  
     }
 782  
 
 783  
     public static int hash(Object[] state)
 784  
     {
 785  6308
         int hash = 0;
 786  44286
         for (int i = 0; i < state.length; ++i)
 787  
         {
 788  37978
             hash = hash * 31 + (null == state[i] ? 0 : state[i].hashCode());
 789  
         }
 790  6308
         return hash;
 791  
     }
 792  
 
 793  
 }