Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 2,314   Methods: 80
NCLOC: 1,659   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
MetaClass.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: MetaClass.java,v 1.82 2004/07/26 20:51:54 glaforge Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 46   
 package groovy.lang;
 47   
 
 48   
 import java.beans.BeanInfo;
 49   
 import java.beans.EventSetDescriptor;
 50   
 import java.beans.IntrospectionException;
 51   
 import java.beans.Introspector;
 52   
 import java.beans.PropertyDescriptor;
 53   
 import java.lang.reflect.Array;
 54   
 import java.lang.reflect.Constructor;
 55   
 import java.lang.reflect.Field;
 56   
 import java.lang.reflect.InvocationHandler;
 57   
 import java.lang.reflect.InvocationTargetException;
 58   
 import java.lang.reflect.Method;
 59   
 import java.lang.reflect.Modifier;
 60   
 import java.lang.reflect.Proxy;
 61   
 import java.math.BigDecimal;
 62   
 import java.math.BigInteger;
 63   
 import java.net.URL;
 64   
 import java.security.AccessControlException;
 65   
 import java.security.AccessController;
 66   
 import java.security.PrivilegedAction;
 67   
 import java.security.PrivilegedActionException;
 68   
 import java.security.PrivilegedExceptionAction;
 69   
 import java.util.ArrayList;
 70   
 import java.util.Arrays;
 71   
 import java.util.Collection;
 72   
 import java.util.Collections;
 73   
 import java.util.HashMap;
 74   
 import java.util.Iterator;
 75   
 import java.util.List;
 76   
 import java.util.Map;
 77   
 import java.util.logging.Logger;
 78   
 
 79   
 import org.codehaus.groovy.ast.ClassNode;
 80   
 import org.codehaus.groovy.classgen.ReflectorGenerator;
 81   
 import org.codehaus.groovy.control.CompilationUnit;
 82   
 import org.codehaus.groovy.control.Phases;
 83   
 import org.codehaus.groovy.runtime.ClosureListener;
 84   
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 85   
 import org.codehaus.groovy.runtime.GroovyCategorySupport;
 86   
 import org.codehaus.groovy.runtime.InvokerHelper;
 87   
 import org.codehaus.groovy.runtime.InvokerInvocationException;
 88   
 import org.codehaus.groovy.runtime.MethodClosure;
 89   
 import org.codehaus.groovy.runtime.MethodHelper;
 90   
 import org.codehaus.groovy.runtime.MethodKey;
 91   
 import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
 92   
 import org.codehaus.groovy.runtime.NewStaticMetaMethod;
 93   
 import org.codehaus.groovy.runtime.ReflectionMetaMethod;
 94   
 import org.codehaus.groovy.runtime.Reflector;
 95   
 import org.codehaus.groovy.runtime.TemporaryMethodKey;
 96   
 import org.codehaus.groovy.runtime.TransformMetaMethod;
 97   
 import org.objectweb.asm.ClassVisitor;
 98   
 import org.objectweb.asm.ClassWriter;
 99   
 
 100   
 /**
 101   
  * Allows methods to be dynamically added to existing classes at runtime
 102   
  * 
 103   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 104   
  * @author Guillaume Laforge
 105   
  * @version $Revision: 1.82 $
 106   
  */
 107   
 public class MetaClass {
 108   
 
 109   
     private static final Logger log = Logger.getLogger(MetaClass.class.getName());
 110   
 
 111   
     public static final Object[] EMPTY_ARRAY = {
 112   
     };
 113   
     public static Class[] EMPTY_TYPE_ARRAY = {
 114   
     };
 115   
     protected static final Object[] ARRAY_WITH_NULL = { null };
 116   
 
 117   
     private static boolean useReflection = false;
 118   
 
 119   
     private MetaClassRegistry registry;
 120   
     private Class theClass;
 121   
     private ClassNode classNode;
 122   
     private Map methodIndex = new HashMap();
 123   
     private Map staticMethodIndex = new HashMap();
 124   
     private List newGroovyMethodsList = new ArrayList();
 125   
     //private Map propertyDescriptors = Collections.synchronizedMap(new HashMap());
 126   
     private Map propertyMap = Collections.synchronizedMap(new HashMap());
 127   
     private Map listeners = new HashMap();
 128   
     private Map methodCache = Collections.synchronizedMap(new HashMap());
 129   
     private Map staticMethodCache = Collections.synchronizedMap(new HashMap());
 130   
     private MetaMethod genericGetMethod;
 131   
     private MetaMethod genericSetMethod;
 132   
     private List constructors;
 133   
     private List allMethods = new ArrayList();
 134   
     private List interfaceMethods;
 135   
     private Reflector reflector;
 136   
     private boolean initialised;
 137   
     // we only need one of these that can be reused over and over.
 138   
     private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
 139   
     
 140  0
     public MetaClass(MetaClassRegistry registry, final Class theClass) throws IntrospectionException {
 141  0
         this.registry = registry;
 142  0
         this.theClass = theClass;
 143   
 
 144  0
         constructors = Arrays.asList(theClass.getDeclaredConstructors());
 145  0
         addMethods(theClass);
 146   
 
 147   
         // introspect
 148  0
         BeanInfo info = null;
 149  0
         try {
 150  0
             info =(BeanInfo) AccessController.doPrivileged(new PrivilegedExceptionAction() {
 151  0
                 public Object run() throws IntrospectionException {
 152  0
                     return Introspector.getBeanInfo(theClass);
 153   
                 }
 154   
             });
 155   
         } catch (PrivilegedActionException pae) {
 156  0
             if (pae.getException() instanceof IntrospectionException) {
 157  0
                 throw (IntrospectionException) pae.getException();
 158   
             } else {
 159  0
                 throw new RuntimeException(pae.getException());
 160   
             }
 161   
         }
 162   
 
 163  0
         PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
 164   
         
 165   
         // build up the metaproperties based on the public fields, property descriptors,
 166   
         // and the getters and setters
 167  0
         setupProperties(descriptors);
 168   
         
 169   
         /* old code
 170   
         for (int i = 0; i < descriptors.length; i++) {
 171   
             PropertyDescriptor descriptor = descriptors[i];
 172   
             propertyDescriptors.put(descriptor.getName(), descriptor);
 173   
         }
 174   
         */
 175   
         
 176  0
         EventSetDescriptor[] eventDescriptors = info.getEventSetDescriptors();
 177  0
         for (int i = 0; i < eventDescriptors.length; i++) {
 178  0
             EventSetDescriptor descriptor = eventDescriptors[i];
 179  0
             Method[] listenerMethods = descriptor.getListenerMethods();
 180  0
             for (int j = 0; j < listenerMethods.length; j++) {
 181  0
                 Method listenerMethod = listenerMethods[j];
 182  0
                 MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod());
 183  0
                 listeners.put(listenerMethod.getName(), metaMethod);
 184   
             }
 185   
         }
 186   
     }
 187   
 
 188  0
     public static boolean isUseReflection() {
 189  0
         return useReflection;
 190   
     }
 191   
 
 192   
     /**
 193   
      * Allows reflection to be enabled in situations where bytecode generation
 194   
      * of method invocations causes issues.
 195   
      * 
 196   
      * @param useReflection
 197   
      */
 198  0
     public static void setUseReflection(boolean useReflection) {
 199  0
         MetaClass.useReflection = useReflection;
 200   
     }
 201   
 
 202  0
     private void addInheritedMethods(Class theClass) {
 203   
         // lets add all the base class methods
 204  0
         Class c = theClass;
 205  0
         if (c != Object.class) {
 206  0
             while (true) {
 207  0
                 c = c.getSuperclass();
 208  0
                 if (c == Object.class || c == null) {
 209  0
                     break;
 210   
                 }
 211  0
                 addMethods(c);
 212  0
                 addNewStaticMethodsFrom(c);
 213   
 
 214   
             }
 215   
         }
 216   
 
 217   
         // now lets see if there are any methods on one of my interfaces
 218  0
         Class[] interfaces = theClass.getInterfaces();
 219  0
         for (int i = 0; i < interfaces.length; i++) {
 220  0
             addNewStaticMethodsFrom(interfaces[i]);
 221   
         }
 222   
 
 223   
         // lets add Object methods after interfaces, as all interfaces derive from Object. 
 224   
         // this ensures List and Collection methods come before Object etc
 225  0
         if (theClass != Object.class) {
 226  0
             addMethods(Object.class);
 227  0
             addNewStaticMethodsFrom(Object.class);
 228   
         }
 229   
 
 230  0
         if (theClass.isArray() && !theClass.equals(Object[].class)) {
 231  0
             addNewStaticMethodsFrom(Object[].class);
 232   
         }
 233   
     }
 234   
 
 235   
     /**
 236   
      * @return all the normal instance methods avaiable on this class for the
 237   
      *         given name
 238   
      */
 239  0
     public List getMethods(String name) {
 240  0
         List answer = (List) methodIndex.get(name);
 241  0
         List used = GroovyCategorySupport.getCategoryMethods(theClass, name);
 242  0
         if (used != null) {
 243  0
             if (answer != null) {
 244  0
                 answer.addAll(used);
 245   
             } else{
 246  0
                 answer = used;
 247   
             }
 248   
         }
 249  0
         if (answer == null) {
 250  0
             answer = Collections.EMPTY_LIST;
 251   
         }
 252  0
         return answer;
 253   
     }
 254   
 
 255   
     /**
 256   
      * @return all the normal static methods avaiable on this class for the
 257   
      *         given name
 258   
      */
 259  0
     public List getStaticMethods(String name) {
 260  0
         List answer = (List) staticMethodIndex.get(name);
 261  0
         if (answer == null) {
 262  0
             return Collections.EMPTY_LIST;
 263   
         }
 264  0
         return answer;
 265   
     }
 266   
 
 267   
     /**
 268   
      * Allows static method definitions to be added to a meta class as if it
 269   
      * was an instance method
 270   
      * 
 271   
      * @param method
 272   
      */
 273  0
     protected void addNewInstanceMethod(Method method) {
 274  0
         if (initialised) {
 275  0
             throw new RuntimeException("Already initialized, cannot add new method: " + method);
 276   
         }
 277   
         else {
 278  0
             NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method));
 279  0
             addMethod(newMethod);
 280  0
             addNewInstanceMethod(newMethod);
 281   
         }
 282   
     }
 283   
 
 284  0
     protected void addNewInstanceMethod(MetaMethod method) {
 285  0
         newGroovyMethodsList.add(method);
 286   
     }
 287   
 
 288  0
     protected void addNewStaticMethod(Method method) {
 289  0
         if (initialised) {
 290  0
             throw new RuntimeException("Already initialized, cannot add new method: " + method);
 291   
         }
 292   
         else {
 293  0
             NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method));
 294  0
             addMethod(newMethod);
 295  0
             addNewStaticMethod(newMethod);
 296   
         }
 297   
     }
 298   
 
 299  0
     protected void addNewStaticMethod(MetaMethod method) {
 300  0
         newGroovyMethodsList.add(method);
 301   
     }
 302   
 
 303  0
     public Object invokeMethod(Object object, String methodName, Object arguments) {
 304  0
         return invokeMethod(object, methodName, asArray(arguments));
 305   
     }
 306   
 
 307   
     /**
 308   
      * Invokes the given method on the object.
 309   
      *  
 310   
      */
 311  0
     public Object invokeMethod(Object object, String methodName, Object[] arguments) {
 312  0
         if (object == null) {
 313  0
             throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
 314   
         }
 315   
 
 316  0
         MetaMethod method = retrieveMethod(object, methodName, arguments);
 317   
 
 318  0
         if (method != null) {
 319  0
             return doMethodInvoke(object, method, arguments);
 320   
         } else {
 321   
             // if no method was found, try to find a closure defined as a field of the class and run it
 322  0
             try {
 323  0
                 Object value = this.getProperty(object, methodName);
 324  0
                 if (value instanceof Closure) {
 325  0
                     Closure closure = (Closure) value;
 326  0
                     closure.setDelegate(this);
 327  0
                     return closure.call(arguments);
 328   
                 }
 329   
                 else {
 330  0
                     throw new MissingMethodException(methodName, theClass, arguments);
 331   
                 }
 332   
             }
 333   
             catch (Exception e) {
 334  0
                 throw new MissingMethodException(methodName, theClass, arguments);
 335   
             }
 336   
         }
 337   
     }
 338   
 
 339  0
     protected MetaMethod retrieveMethod(Object owner, String methodName, Object[] arguments) {
 340   
         // lets try use the cache to find the method
 341  0
         MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
 342  0
         MetaMethod method = (MetaMethod) methodCache.get(methodKey);
 343  0
         if (method == null) {
 344  0
             method = pickMethod(owner, methodName, arguments);
 345  0
             if (method != null && method.isCacheable()) {
 346  0
                 methodCache.put(methodKey.createCopy(), method);
 347   
             }
 348   
         }
 349  0
         return method;
 350   
     }
 351   
 
 352  0
     public MetaMethod retrieveMethod(String methodName, Class[] arguments) {
 353   
         // lets try use the cache to find the method
 354  0
         MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
 355  0
         MetaMethod method = (MetaMethod) methodCache.get(methodKey);
 356  0
         if (method == null) {
 357  0
             method = pickMethod(methodName, arguments); // todo shall call pickStaticMethod also?
 358  0
             if (method != null && method.isCacheable()) {
 359  0
                 methodCache.put(methodKey.createCopy(), method);
 360   
             }
 361   
         }
 362  0
         return method;
 363   
     }
 364   
 
 365  0
     public Constructor retrieveConstructor(Class[] arguments) {
 366  0
         Constructor constructor = (Constructor) chooseMethod("<init>", constructors, arguments, false);
 367  0
         if (constructor != null) {
 368  0
             return constructor;
 369   
         }
 370   
         else {
 371  0
             constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
 372  0
             if (constructor != null) {
 373  0
                 return constructor;
 374   
             }
 375   
         }
 376  0
         return null;
 377   
     }
 378   
 
 379  0
     public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
 380  0
         MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
 381  0
         MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
 382  0
         if (method == null) {
 383  0
             method = pickStaticMethod(methodName, arguments);
 384  0
             if (method != null) {
 385  0
                 staticMethodCache.put(methodKey.createCopy(), method);
 386   
             }
 387   
         }
 388  0
         return method;
 389   
     }
 390   
     /**
 391   
      * Picks which method to invoke for the given object, method name and arguments
 392   
      */
 393  0
     protected MetaMethod pickMethod(Object object, String methodName, Object[] arguments) {
 394  0
         MetaMethod method = null;
 395  0
         List methods = getMethods(methodName);
 396  0
         if (!methods.isEmpty()) {
 397  0
             Class[] argClasses = convertToTypeArray(arguments);
 398  0
             method = (MetaMethod) chooseMethod(methodName, methods, argClasses, false);
 399  0
             if (method == null) {
 400  0
                 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
 401  0
                 if (method == null) {
 402  0
                     int size = (arguments != null) ? arguments.length : 0;
 403  0
                     if (size == 1) {
 404  0
                         Object firstArgument = arguments[0];
 405  0
                         if (firstArgument instanceof List) {
 406   
                             // lets coerce the list arguments into an array of
 407   
                             // arguments
 408   
                             // e.g. calling JFrame.setLocation( [100, 100] )
 409   
 
 410  0
                             List list = (List) firstArgument;
 411  0
                             arguments = list.toArray();
 412  0
                             argClasses = convertToTypeArray(arguments);
 413  0
                             method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
 414  0
                             return new TransformMetaMethod(method) {
 415  0
                                 public Object invoke(Object object, Object[] arguments) throws Exception {
 416  0
                                     Object firstArgument = arguments[0];
 417  0
                                     List list = (List) firstArgument;
 418  0
                                     arguments = list.toArray();
 419  0
                                     return super.invoke(object, arguments);
 420   
                                 }
 421   
                             };
 422   
                         }
 423   
                     }
 424   
                 }
 425   
             }
 426   
         }
 427  0
         return method;
 428   
     }
 429   
 
 430   
     /**
 431   
      * pick a method in a strict manner, i.e., without reinterpreting the first List argument.
 432   
      * this method is used only by ClassGenerator for static binding
 433   
      * @param methodName
 434   
      * @param arguments
 435   
      * @return
 436   
      */
 437  0
     protected MetaMethod pickMethod(String methodName, Class[] arguments) {
 438  0
         MetaMethod method = null;
 439  0
         List methods = getMethods(methodName);
 440  0
         if (!methods.isEmpty()) {
 441  0
             method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
 442   
 // no coersion at classgen time.
 443   
 //            if (method == null) {
 444   
 //                method = (MetaMethod) chooseMethod(methodName, methods, arguments, true);
 445   
 //            }
 446   
         }
 447  0
         return method;
 448   
     }
 449   
 
 450  0
     public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
 451   
         //        System.out.println("Calling static method: " + methodName + " on args: " + InvokerHelper.toString(arguments));
 452   
         //        Class type = arguments == null ? null : arguments.getClass();
 453   
         //        System.out.println("Argument  type: " + type);
 454   
         //        System.out.println("Type of first arg: " + arguments[0] + " type: " + arguments[0].getClass());
 455   
 
 456   
         // lets try use the cache to find the method
 457  0
         MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
 458  0
         MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
 459  0
         if (method == null) {
 460  0
             method = pickStaticMethod(object, methodName, arguments);
 461  0
             if (method != null) {
 462  0
                 staticMethodCache.put(methodKey.createCopy(), method);
 463   
             }
 464   
         }
 465   
 
 466  0
         if (method != null) {
 467  0
             return doMethodInvoke(object, method, arguments);
 468   
         }
 469   
         /*
 470   
         List methods = getStaticMethods(methodName);
 471   
         
 472   
         if (!methods.isEmpty()) {
 473   
             MetaMethod method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
 474   
             if (method != null) {
 475   
                 return doMethodInvoke(theClass, method, arguments);
 476   
             }
 477   
         }
 478   
         
 479   
         if (theClass != Class.class) {
 480   
             try {
 481   
                 return registry.getMetaClass(Class.class).invokeMethod(object, methodName, arguments);
 482   
             }
 483   
             catch (GroovyRuntimeException e) {
 484   
                 // throw our own exception
 485   
             }
 486   
         }
 487   
         */
 488  0
         throw new MissingMethodException(methodName, theClass, arguments);
 489   
     }
 490   
 
 491  0
     protected MetaMethod pickStaticMethod(Object object, String methodName, Object[] arguments) {
 492  0
         MetaMethod method = null;
 493  0
         List methods = getStaticMethods(methodName);
 494   
 
 495  0
         if (!methods.isEmpty()) {
 496  0
             method = (MetaMethod) chooseMethod(methodName, methods, convertToTypeArray(arguments), false);
 497   
         }
 498   
 
 499  0
         if (method == null && theClass != Class.class) {
 500  0
             MetaClass classMetaClass = registry.getMetaClass(Class.class);
 501  0
             method = classMetaClass.pickMethod(object, methodName, arguments);
 502   
         }
 503  0
         return method;
 504   
     }
 505   
 
 506  0
     protected MetaMethod pickStaticMethod(String methodName, Class[] arguments) {
 507  0
         MetaMethod method = null;
 508  0
         List methods = getStaticMethods(methodName);
 509   
 
 510  0
         if (!methods.isEmpty()) {
 511  0
             method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
 512   
 // disabled to keep consistant with the original version of pickStatciMethod
 513   
 //            if (method == null) {
 514   
 //                method = (MetaMethod) chooseMethod(methodName, methods, arguments, true);
 515   
 //            }
 516   
         }
 517   
 
 518  0
         if (method == null && theClass != Class.class) {
 519  0
             MetaClass classMetaClass = registry.getMetaClass(Class.class);
 520  0
             method = classMetaClass.pickMethod(methodName, arguments);
 521   
         }
 522  0
         return method;
 523   
     }
 524   
 
 525  0
     public Object invokeConstructor(Object[] arguments) {
 526  0
         Class[] argClasses = convertToTypeArray(arguments);
 527  0
         Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
 528  0
         if (constructor != null) {
 529  0
             return doConstructorInvoke(constructor, arguments);
 530   
         }
 531   
         else {
 532  0
             constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
 533  0
             if (constructor != null) {
 534  0
                 return doConstructorInvoke(constructor, arguments);
 535   
             }
 536   
         }
 537   
 
 538  0
         if (arguments.length == 1) {
 539  0
             Object firstArgument = arguments[0];
 540  0
             if (firstArgument instanceof Map) {
 541  0
                 constructor = (Constructor) chooseMethod("<init>", constructors, EMPTY_TYPE_ARRAY, false);
 542  0
                 if (constructor != null) {
 543  0
                     Object bean = doConstructorInvoke(constructor, EMPTY_ARRAY);
 544  0
                     setProperties(bean, ((Map) firstArgument));
 545  0
                     return bean;
 546   
                 }
 547   
             }
 548   
         }
 549  0
         throw new GroovyRuntimeException(
 550   
                     "Could not find matching constructor for: "
 551   
                         + theClass.getName()
 552   
                         + "("+InvokerHelper.toTypeString(arguments)+")");
 553   
     }
 554   
 
 555   
     /**
 556   
      * Sets a number of bean properties from the given Map where the keys are
 557   
      * the String names of properties and the values are the values of the
 558   
      * properties to set
 559   
      */
 560  0
     public void setProperties(Object bean, Map map) {
 561  0
         for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
 562  0
             Map.Entry entry = (Map.Entry) iter.next();
 563  0
             String key = entry.getKey().toString();
 564   
             
 565   
             // do we have this property?
 566  0
             if(propertyMap.get(key) == null)
 567  0
                 continue;
 568   
             
 569  0
             Object value = entry.getValue();
 570  0
             try {
 571  0
                 setProperty(bean, key, value);
 572   
             }
 573   
             catch (GroovyRuntimeException e) {
 574   
                 // lets ignore missing properties
 575   
                 /** todo should replace this code with a getMetaProperty(key) != null check
 576   
                  i.e. don't try and set a non-existent property
 577   
                  */
 578   
             }
 579   
         }
 580   
     }
 581   
 
 582   
     /**
 583   
      * @return the given property's value on the object
 584   
      */
 585  0
     public Object getProperty(final Object object, final String property) {
 586   
         /* old code; we now use the metaProperty map to handle properties
 587   
         MetaMethod metaMethod = null;
 588   
         PropertyDescriptor descriptor = (PropertyDescriptor) propertyDescriptors.get(property);
 589   
         if (descriptor != null) {
 590   
             Method method = descriptor.getReadMethod();
 591   
             if (method == null) {
 592   
                 throw new GroovyRuntimeException("Cannot read property: " + property);
 593   
             }
 594   
             metaMethod = findMethod(method);
 595   
             if (metaMethod == null) {
 596   
                 // lets try invoke a static getter method
 597   
                 metaMethod = findGetter(object, "get" + capitalize(property));
 598   
             }
 599   
             if (metaMethod != null) {
 600   
                 return doMethodInvoke(object, metaMethod, EMPTY_ARRAY);
 601   
             }
 602   
         }
 603   
         */
 604   
         
 605   
         // look for the property in our map
 606  0
         MetaProperty mp = (MetaProperty) propertyMap.get(property);
 607  0
         if(mp != null) {
 608  0
             try {
 609   
                 //System.out.println("we found a metaproperty for " + theClass.getName() +
 610   
                 //  "." + property);
 611   
                 // delegate the get operation to the metaproperty
 612  0
                 return mp.getProperty(object);
 613   
             }
 614   
             catch(Exception e) {
 615  0
                 throw new GroovyRuntimeException("Cannot read property: " + property);
 616   
             }
 617   
         }
 618   
 
 619  0
         if (genericGetMethod == null) {
 620   
             // Make sure there isn't a generic method in the "use" cases
 621  0
             List possibleGenericMethods = getMethods("get");
 622  0
             if (possibleGenericMethods != null) {
 623  0
                 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
 624  0
                     MetaMethod mmethod = (MetaMethod) i.next();
 625  0
                     Class[] paramTypes = mmethod.getParameterTypes();
 626  0
                     if (paramTypes.length == 1 && paramTypes[0] == String.class) {
 627  0
                         Object[] arguments = {property};
 628  0
                         Object answer = doMethodInvoke(object, mmethod, arguments);
 629  0
                         return answer;
 630   
                     }
 631   
                 }
 632   
             }
 633   
         } 
 634   
         else {
 635  0
             Object[] arguments = { property };
 636  0
             Object answer = doMethodInvoke(object, genericGetMethod, arguments);
 637   
             // jes bug? a property retrieved via a generic get() can't have a null value?
 638  0
             if (answer != null) {
 639  0
                 return answer;
 640   
             }
 641   
         }
 642   
 
 643   
         // is the property the name of a method - in which case return a
 644   
         // closure
 645  0
         List methods = getMethods(property);
 646  0
         if (!methods.isEmpty()) {
 647  0
             return new MethodClosure(object, property);
 648   
         }
 649   
 
 650   
         // lets try invoke a static getter method
 651   
         // this case is for protected fields. I wish there was a better way...
 652  0
         Exception lastException = null;
 653  0
         try {
 654  0
             MetaMethod method = findGetter(object, "get" + capitalize(property));
 655  0
             if (method != null) {
 656  0
                 return doMethodInvoke(object, method, EMPTY_ARRAY);
 657   
             }
 658   
         }
 659   
         catch (GroovyRuntimeException e) {
 660  0
             lastException = e;
 661   
         }
 662   
 
 663   
         /** todo or are we an extensible groovy class? */
 664  0
         if (genericGetMethod != null) {
 665  0
             return null;
 666   
         }
 667   
         else {
 668   
             /** todo these special cases should be special MetaClasses maybe */
 669  0
             if (object instanceof Class) {
 670   
                 // lets try a static field
 671  0
                 return getStaticProperty((Class) object, property);
 672   
             }
 673  0
             if (object instanceof Collection) {
 674  0
                 return DefaultGroovyMethods.getAt((Collection) object, property);
 675   
             }
 676  0
             if (object instanceof Object[]) {
 677  0
                 return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), property);
 678   
             }
 679  0
             if (object instanceof Object) {
 680  0
                 try {
 681   
                     // lets try a public field
 682  0
                     Field field = object.getClass().getDeclaredField(property);
 683  0
                     return field.get(object);
 684   
                 }
 685   
                 catch (Exception e1) {
 686   
                     // fall through
 687   
                 }
 688   
             }
 689   
             
 690  0
             MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
 691  0
             if (addListenerMethod != null) {
 692   
                 /* @todo one day we could try return the previously registered Closure listener for easy removal */
 693  0
                 return null;
 694   
             }
 695   
 
 696  0
             if (lastException == null)
 697  0
                 throw new MissingPropertyException(property, theClass);
 698   
             else
 699  0
                 throw new MissingPropertyException(property, theClass, lastException);
 700   
         }
 701   
     }
 702   
     
 703   
     /**
 704   
      * Get all the properties defined for this type
 705   
      * @return a list of MetaProperty objects
 706   
      */
 707  0
     public List getProperties() {
 708   
         // simply return the values of the metaproperty map as a List
 709  0
         return new ArrayList(propertyMap.values());
 710   
     }
 711   
     
 712   
     /**
 713   
      * This will build up the property map (Map of MetaProperty objects, keyed on 
 714   
      * property name).
 715   
      */
 716  0
     protected void setupProperties(PropertyDescriptor[] propertyDescriptors) {
 717  0
         MetaProperty mp;
 718  0
         Method method;
 719  0
         MetaMethod getter = null;
 720  0
         MetaMethod setter = null;
 721  0
         Class klass;
 722   
         
 723   
         // first get the public fields and create MetaFieldProperty objects
 724  0
         klass = theClass;
 725  0
         while(klass != null) {
 726  0
             Field[] fields = klass.getDeclaredFields();
 727  0
             for(int i = 0; i < fields.length; i++) {
 728   
                 // we're only interested in publics
 729  0
                 if((fields[i].getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0)
 730  0
                     continue;
 731   
                 
 732   
                 // see if we already got this
 733  0
                 if(propertyMap.get(fields[i].getName()) != null)
 734  0
                     continue;
 735   
                 
 736   
                 //System.out.println("adding field " + fields[i].getName() + 
 737   
                 //  " for class " + klass.getName());
 738   
                 // stick it in there!
 739  0
                 propertyMap.put(fields[i].getName(), new MetaFieldProperty(fields[i]));
 740   
             }
 741   
             
 742   
             // now get the super class
 743  0
             klass = klass.getSuperclass();
 744   
         }
 745   
         
 746   
         // if this an Array, then add the special read-only "length" property
 747  0
         if(theClass.isArray()) {
 748  0
             propertyMap.put("length", arrayLengthProperty);
 749   
         }
 750   
         
 751   
         // now iterate over the map of property descriptors and generate 
 752   
         // MetaBeanProperty objects
 753  0
         for(int i=0; i<propertyDescriptors.length; i++) {
 754  0
             PropertyDescriptor pd = propertyDescriptors[i];
 755   
             // skip if the field already exists in the map
 756  0
             if(propertyMap.get(pd.getName()) != null)
 757  0
                 continue;
 758   
             
 759   
             // skip if the property type is unknown (this seems to be the case if the 
 760   
             // property descriptor is based on a setX() method that has two parameters,
 761   
             // which is not a valid property)
 762  0
             if(pd.getPropertyType() == null)
 763  0
                 continue;
 764   
             
 765   
             // get the getter method
 766  0
             method = pd.getReadMethod();
 767  0
             if(method != null)
 768  0
                 getter = findMethod(method);
 769   
             else
 770  0
                 getter = null;
 771   
             
 772   
             // get the setter method
 773  0
             method = pd.getWriteMethod();
 774  0
             if(method != null)
 775  0
                 setter = findMethod(method);
 776   
             else
 777  0
                 setter = null;
 778   
             
 779   
             // now create the MetaProperty object
 780   
             //System.out.println("creating a bean property for class " +
 781   
             //  theClass.getName() + ": " + pd.getName());
 782   
                 
 783  0
             mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter);
 784   
             
 785   
             // put it in the list
 786  0
             propertyMap.put(pd.getName(), mp);
 787   
         }
 788   
         
 789   
         // now look for any stray getters that may be used to define a property
 790  0
         klass = theClass;
 791  0
         while(klass != null) {
 792  0
             Method[] methods = klass.getDeclaredMethods();
 793  0
             for (int i = 0; i < methods.length; i++) {
 794   
                 // filter out the privates
 795  0
                 if(Modifier.isPublic(methods[i].getModifiers()) == false)
 796  0
                     continue;
 797   
                 
 798  0
                 method = methods[i];
 799   
                 
 800  0
                 String methodName = method.getName();
 801   
                 
 802   
                 // is this a getter?
 803  0
                 if(methodName.startsWith("get") && 
 804   
                     methodName.length() > 3 &&
 805   
                     method.getParameterTypes().length == 0) {
 806   
                     
 807   
                     // get the name of the property
 808  0
                     String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
 809   
                     
 810   
                     // is this property already accounted for?
 811  0
                     mp = (MetaProperty) propertyMap.get(propName);
 812  0
                     if(mp != null) {
 813   
                         // we may have already found the setter for this
 814  0
                         if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getGetter() == null) {
 815   
                             // update the getter method to this one
 816  0
                             ((MetaBeanProperty) mp).setGetter(findMethod(method));
 817   
                         }
 818   
                     }
 819   
                     else {
 820   
                         // we need to create a new property object
 821   
                         // type of the property is what the get method returns
 822  0
                         MetaBeanProperty mbp = new MetaBeanProperty(propName, 
 823   
                             method.getReturnType(),
 824   
                             findMethod(method), null);
 825   
                             
 826   
                         // add it to the map
 827  0
                         propertyMap.put(propName, mbp);
 828   
                     }
 829   
                 }
 830  0
                 else if(methodName.startsWith("set") && 
 831   
                     methodName.length() > 3 &&
 832   
                     method.getParameterTypes().length == 1) {
 833   
                     
 834   
                     // get the name of the property
 835  0
                     String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
 836   
                     
 837   
                     // did we already find the getter of this?
 838  0
                     mp = (MetaProperty) propertyMap.get(propName);
 839  0
                     if(mp != null) {
 840  0
                         if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getSetter() == null) {
 841   
                             // update the setter method to this one
 842  0
                             ((MetaBeanProperty) mp).setSetter(findMethod(method));
 843   
                         }
 844   
                     }
 845   
                     else {
 846   
                         // this is a new property to add
 847  0
                         MetaBeanProperty mbp = new MetaBeanProperty(propName, 
 848   
                                                                     method.getParameterTypes()[0],
 849   
                                                                     null,
 850   
                                                                     findMethod(method));
 851   
                             
 852   
                         // add it to the map
 853  0
                         propertyMap.put(propName, mbp);
 854   
                     }
 855   
                 }
 856   
             }
 857   
             
 858   
             // now get the super class
 859  0
             klass = klass.getSuperclass();
 860   
         }
 861   
     }
 862   
     
 863   
     /**
 864   
      * Sets the property value on an object
 865   
      */
 866  0
     public void setProperty(Object object, String property, Object newValue) {
 867   
         /* old code, replaced with new MetaProperty stuff...
 868   
         PropertyDescriptor descriptor = (PropertyDescriptor) propertyDescriptors.get(property);
 869   
 
 870   
         if (descriptor != null) {
 871   
             Method method = descriptor.getWriteMethod();
 872   
             if (method == null) {
 873   
                 throw new ReadOnlyPropertyException(property, theClass);
 874   
             }
 875   
             MetaMethod metaMethod = findMethod(method);
 876   
             Object[] arguments = { newValue };
 877   
             try {
 878   
                 doMethodInvoke(object, metaMethod, arguments);
 879   
             }
 880   
             catch (GroovyRuntimeException e) {
 881   
                 // if the value is a List see if we can construct the value
 882   
                 // from a constructor
 883   
                 if (newValue instanceof List) {
 884   
                     List list = (List) newValue;
 885   
                     int params = list.size();
 886   
                     Constructor[] propConstructors = descriptor.getPropertyType().getConstructors();
 887   
                     for (int i = 0; i < propConstructors.length; i++) {
 888   
                         Constructor constructor = propConstructors[i];
 889   
                         if (constructor.getParameterTypes().length == params) {
 890   
                             Object value = doConstructorInvoke(constructor, list.toArray());
 891   
                             doMethodInvoke(object, metaMethod, new Object[] { value });
 892   
                             return;
 893   
                         }
 894   
                     }
 895   
                     
 896   
                     // if value is an array  
 897   
                     Class parameterType = method.getParameterTypes()[0];
 898   
                     if (parameterType.isArray()) {
 899   
                         Object objArray = asPrimitiveArray(list, parameterType);
 900   
                         doMethodInvoke(object, metaMethod, new Object[]{
 901   
                             objArray
 902   
                         });
 903   
                         return;
 904   
                     }
 905   
                 }
 906   
                 
 907   
                 // if value is an multidimensional array  
 908   
                 if (newValue.getClass().isArray()) {
 909   
                     List list = Arrays.asList((Object[])newValue);
 910   
                     
 911   
                     Class parameterType = method.getParameterTypes()[0];
 912   
                     Class arrayType = parameterType.getComponentType();
 913   
                     Object objArray = Array.newInstance(arrayType, list.size());
 914   
                     
 915   
                     for (int i = 0; i < list.size(); i++) {
 916   
                         List list2 =Arrays.asList((Object[]) list.get(i));
 917   
                         Object objArray2 = asPrimitiveArray(list2, arrayType);
 918   
                         Array.set(objArray, i, objArray2);
 919   
                     }
 920   
 
 921   
                     doMethodInvoke(object, metaMethod, new Object[]{
 922   
                         objArray
 923   
                     });
 924   
                     return;
 925   
                 }
 926   
                 
 927   
                 throw new MissingPropertyException(property, theClass, e);
 928   
             }
 929   
             return;
 930   
         }
 931   
         */
 932   
         
 933  0
         MetaProperty mp = (MetaProperty) propertyMap.get(property);
 934  0
         if(mp != null) {
 935  0
             try {
 936  0
                 mp.setProperty(object, newValue);
 937  0
                 return;
 938   
             }
 939   
             catch(ReadOnlyPropertyException e) {
 940   
                 // just rethrow it; there's nothing left to do here
 941  0
                 throw e;
 942   
             }
 943   
             catch (Exception e) {
 944   
                 // if the value is a List see if we can construct the value
 945   
                 // from a constructor
 946  0
                 if (newValue instanceof List) {
 947  0
                     List list = (List) newValue;
 948  0
                     int params = list.size();
 949  0
                     Constructor[] constructors = mp.getType().getConstructors();
 950  0
                     for (int i = 0; i < constructors.length; i++) {
 951  0
                         Constructor constructor = constructors[i];
 952  0
                         if (constructor.getParameterTypes().length == params) {
 953  0
                             Object value = doConstructorInvoke(constructor, list.toArray());
 954  0
                             mp.setProperty(object, value);
 955  0
                             return;
 956   
                         }
 957   
                     }
 958   
                     
 959   
                     // if value is an array  
 960  0
                     Class parameterType = mp.getType();
 961  0
                     if (parameterType.isArray()) {
 962  0
                         Object objArray = asPrimitiveArray(list, parameterType);
 963  0
                         mp.setProperty(object, objArray);
 964  0
                         return;
 965   
                     }
 966   
                 }
 967   
 
 968   
                 // if value is an multidimensional array  
 969   
                 // jes currently this logic only supports metabeansproperties and
 970   
                 // not metafieldproperties. It shouldn't be too hard to support
 971   
                 // the latter...
 972  0
                 if (newValue.getClass().isArray() && mp instanceof MetaBeanProperty) {
 973  0
                     MetaBeanProperty mbp = (MetaBeanProperty) mp;
 974  0
                     List list = Arrays.asList((Object[])newValue);
 975  0
                     MetaMethod setter = mbp.getSetter();
 976   
                     
 977  0
                     Class parameterType = setter.getParameterTypes()[0];
 978  0
                     Class arrayType = parameterType.getComponentType();
 979  0
                     Object objArray = Array.newInstance(arrayType, list.size());
 980   
                     
 981  0
                     for (int i = 0; i < list.size(); i++) {
 982  0
                         List list2 =Arrays.asList((Object[]) list.get(i));
 983  0
                         Object objArray2 = asPrimitiveArray(list2, arrayType);
 984  0
                         Array.set(objArray, i, objArray2);
 985   
                     }
 986   
 
 987  0
                     doMethodInvoke(object, setter, new Object[]{
 988   
                         objArray
 989   
                     });
 990  0
                     return;
 991   
                 }
 992   
                 
 993  0
                 throw new MissingPropertyException(property, theClass, e);
 994   
             }
 995   
         }
 996   
         
 997  0
         try {
 998  0
             MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
 999  0
             if (addListenerMethod != null && newValue instanceof Closure) {
 1000   
                 // lets create a dynamic proxy
 1001  0
                 Object proxy =
 1002   
                     createListenerProxy(addListenerMethod.getParameterTypes()[0], property, (Closure) newValue);
 1003  0
                 doMethodInvoke(object, addListenerMethod, new Object[] { proxy });
 1004  0
                 return;
 1005   
             }
 1006   
 
 1007  0
             if (genericSetMethod == null) {
 1008   
                 // Make sure there isn't a generic method in the "use" cases
 1009  0
                 List possibleGenericMethods = getMethods("set");
 1010  0
                 if (possibleGenericMethods != null) {
 1011  0
                     for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
 1012  0
                         MetaMethod mmethod = (MetaMethod) i.next();
 1013  0
                         Class[] paramTypes = mmethod.getParameterTypes();
 1014  0
                         if (paramTypes.length == 2 && paramTypes[0] == String.class) {
 1015  0
                             Object[] arguments = {property, newValue};
 1016  0
                             Object answer = doMethodInvoke(object, mmethod, arguments);
 1017  0
                             return;
 1018   
                         }
 1019   
                     }
 1020   
                 }
 1021   
             } 
 1022   
             else {
 1023  0
                 Object[] arguments = { property, newValue };
 1024  0
                 doMethodInvoke(object, genericSetMethod, arguments);
 1025  0
                 return;
 1026   
             }
 1027   
 
 1028   
             /** todo or are we an extensible class? */
 1029   
 
 1030   
             // lets try invoke the set method
 1031   
             // this is kind of ugly: if it is a protected field, we fall
 1032   
             // all the way down to this klunky code. Need a better
 1033   
             // way to handle this situation...
 1034   
 
 1035  0
             String method = "set" + capitalize(property);
 1036  0
             try {
 1037  0
                 invokeMethod(object, method, new Object[] { newValue });
 1038   
             }
 1039   
             catch (MissingMethodException e1) {
 1040  0
                 try {
 1041  0
                     Field field = object.getClass().getDeclaredField(property);
 1042  0
                     field.set(object, newValue);
 1043   
                 }
 1044   
                 catch (Exception e2) {
 1045  0
                     throw new MissingPropertyException(property, theClass, e2);
 1046   
                 }
 1047   
             }
 1048   
             
 1049   
         }
 1050   
         catch (GroovyRuntimeException e) {
 1051  0
             throw new MissingPropertyException(property, theClass, e);
 1052   
         }
 1053   
         
 1054   
         // if we got here, the damn thing just aint there...
 1055  0
         throw new MissingPropertyException(property, theClass);
 1056   
     }
 1057   
 
 1058   
     /**
 1059   
      * @param list
 1060   
      * @param parameterType
 1061   
      * @return
 1062   
      */
 1063  0
     private Object asPrimitiveArray(List list, Class parameterType) {
 1064  0
         Class arrayType = parameterType.getComponentType();
 1065  0
         Object objArray = Array.newInstance(arrayType, list.size());
 1066  0
         for (int i = 0; i < list.size(); i++) {
 1067  0
             Object obj = list.get(i);
 1068  0
             if (arrayType.isPrimitive()) {
 1069  0
                 if (obj instanceof Integer) {
 1070  0
                     Array.setInt(objArray, i, ((Integer) obj).intValue());
 1071   
                 }
 1072  0
                 else if (obj instanceof Double) {
 1073  0
                     Array.setDouble(objArray, i, ((Double) obj).doubleValue());
 1074   
                 }
 1075  0
                 else if (obj instanceof Boolean) {
 1076  0
                     Array.setBoolean(objArray, i, ((Boolean) obj).booleanValue());
 1077   
                 }
 1078  0
                 else if (obj instanceof Long) {
 1079  0
                     Array.setLong(objArray, i, ((Long) obj).longValue());
 1080   
                 }
 1081  0
                 else if (obj instanceof Float) {
 1082  0
                     Array.setFloat(objArray, i, ((Float) obj).floatValue());
 1083   
                 }
 1084  0
                 else if (obj instanceof Character) {
 1085  0
                     Array.setChar(objArray, i, ((Character) obj).charValue());
 1086   
                 }
 1087  0
                 else if (obj instanceof Byte) {
 1088  0
                     Array.setByte(objArray, i, ((Byte) obj).byteValue());
 1089   
                 }
 1090  0
                 else if (obj instanceof Short) {
 1091  0
                     Array.setShort(objArray, i, ((Short) obj).shortValue());
 1092   
                 }
 1093   
             }
 1094   
             else {
 1095  0
                 Array.set(objArray, i, obj);
 1096   
             }
 1097   
         }
 1098  0
         return objArray;
 1099   
     }
 1100   
     
 1101  0
     public ClassNode getClassNode() {
 1102  0
         if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) {
 1103   
             // lets try load it from the classpath
 1104  0
             String className = theClass.getName();
 1105  0
             String groovyFile = className;
 1106  0
             int idx = groovyFile.indexOf('$');
 1107  0
             if (idx > 0) {
 1108  0
                 groovyFile = groovyFile.substring(0, idx);
 1109   
             }
 1110  0
             groovyFile = groovyFile.replace('.', '/') + ".groovy";
 1111   
 
 1112   
             //System.out.println("Attempting to load: " + groovyFile);
 1113  0
             URL url = theClass.getClassLoader().getResource(groovyFile);
 1114  0
             if (url == null) {
 1115  0
                 url = Thread.currentThread().getContextClassLoader().getResource(groovyFile);
 1116   
             }
 1117  0
             if (url != null) {
 1118  0
                 try {
 1119   
 
 1120   
                     /**
 1121   
                      * todo there is no CompileUnit in scope so class name
 1122   
                      * checking won't work but that mostly affects the bytecode
 1123   
                      * generation rather than viewing the AST
 1124   
                      */
 1125   
 
 1126  0
                     CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
 1127  0
                         public void call( ClassVisitor writer, ClassNode node ) {
 1128  0
                             if( node.getName().equals(theClass.getName()) ) {
 1129  0
                                 MetaClass.this.classNode = node;
 1130   
                             }
 1131   
                         }
 1132   
                     };
 1133   
                     
 1134   
                     
 1135  0
                     CompilationUnit unit = new CompilationUnit( getClass().getClassLoader() );
 1136  0
                     unit.setClassgenCallback( search );
 1137  0
                     unit.addSource( url );
 1138  0
                     unit.compile( Phases.CLASS_GENERATION );
 1139   
                 }
 1140   
                 catch (Exception e) {
 1141  0
                     throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e);
 1142   
                 }
 1143   
             }
 1144   
 
 1145   
         }
 1146  0
         return classNode;
 1147   
     }
 1148   
 
 1149  0
     public String toString() {
 1150  0
         return super.toString() + "[" + theClass + "]";
 1151   
     }
 1152   
 
 1153   
     // Implementation methods
 1154   
     //-------------------------------------------------------------------------
 1155   
 
 1156   
     /**
 1157   
      * Converts the given object into an array; if its an array then just cast
 1158   
      * otherwise wrap it in an array
 1159   
      */
 1160  0
     protected Object[] asArray(Object arguments) {
 1161  0
         if (arguments == null) {
 1162  0
             return EMPTY_ARRAY;
 1163   
         }
 1164  0
         if (arguments instanceof Tuple) {
 1165  0
             Tuple tuple = (Tuple) arguments;
 1166  0
             return tuple.toArray();
 1167   
         }
 1168  0
         if (arguments instanceof Object[]) {
 1169  0
             return (Object[]) arguments;
 1170   
         }
 1171   
         else {
 1172  0
             return new Object[] { arguments };
 1173   
         }
 1174   
     }
 1175   
     
 1176   
     /**
 1177   
      * @param listenerType
 1178   
      *            the interface of the listener to proxy
 1179   
      * @param listenerMethodName
 1180   
      *            the name of the method in the listener API to call the
 1181   
      *            closure on
 1182   
      * @param closure
 1183   
      *            the closure to invoke on the listenerMethodName method
 1184   
      *            invocation
 1185   
      * @return a dynamic proxy which calls the given closure on the given
 1186   
      *         method name
 1187   
      */
 1188  0
     protected Object createListenerProxy(Class listenerType, final String listenerMethodName, final Closure closure) {
 1189  0
         InvocationHandler handler = new ClosureListener(listenerMethodName, closure);
 1190  0
         return Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[] { listenerType }, handler);
 1191   
     }
 1192   
 
 1193   
     /**
 1194   
      * Adds all the methods declared in the given class to the metaclass
 1195   
      * ignoring any matching methods already defined by a derived class
 1196   
      * 
 1197   
      * @param theClass
 1198   
      */
 1199  0
     protected void addMethods(Class theClass) {
 1200  0
         Method[] methodArray = theClass.getDeclaredMethods();
 1201  0
         for (int i = 0; i < methodArray.length; i++) {
 1202  0
             Method reflectionMethod = methodArray[i];
 1203  0
             if ( reflectionMethod.getName().indexOf('+') >= 0 ) {
 1204  0
                 continue;
 1205   
             }
 1206  0
             MetaMethod method = createMetaMethod(reflectionMethod);
 1207  0
             addMethod(method);
 1208   
         }
 1209   
     }
 1210   
 
 1211  0
     protected void addMethod(MetaMethod method) {
 1212  0
         String name = method.getName();
 1213   
 
 1214   
         //System.out.println(theClass.getName() + " == " + name + Arrays.asList(method.getParameterTypes()));
 1215   
 
 1216  0
         if (isGenericGetMethod(method) && genericGetMethod == null) {
 1217  0
             genericGetMethod = method;
 1218   
         }
 1219  0
         else if (isGenericSetMethod(method) && genericSetMethod == null) {
 1220  0
             genericSetMethod = method;
 1221   
         }
 1222  0
         if (method.isStatic()) {
 1223  0
             List list = (List) staticMethodIndex.get(name);
 1224  0
             if (list == null) {
 1225  0
                 list = new ArrayList();
 1226  0
                 staticMethodIndex.put(name, list);
 1227  0
                 list.add(method);
 1228   
             }
 1229   
             else {
 1230  0
                 if (!containsMatchingMethod(list, method)) {
 1231  0
                     list.add(method);
 1232   
                 }
 1233   
             }
 1234   
         }
 1235   
 
 1236  0
         List list = (List) methodIndex.get(name);
 1237  0
         if (list == null) {
 1238  0
             list = new ArrayList();
 1239  0
             methodIndex.put(name, list);
 1240  0
             list.add(method);
 1241   
         }
 1242   
         else {
 1243  0
             if (!containsMatchingMethod(list, method)) {
 1244  0
                 list.add(method);
 1245   
             }
 1246   
         }
 1247   
     }
 1248   
 
 1249   
     /**
 1250   
      * @return true if a method of the same matching prototype was found in the
 1251   
      *         list
 1252   
      */
 1253  0
     protected boolean containsMatchingMethod(List list, MetaMethod method) {
 1254  0
         for (Iterator iter = list.iterator(); iter.hasNext();) {
 1255  0
             MetaMethod aMethod = (MetaMethod) iter.next();
 1256  0
             Class[] params1 = aMethod.getParameterTypes();
 1257  0
             Class[] params2 = method.getParameterTypes();
 1258  0
             if (params1.length == params2.length) {
 1259  0
                 boolean matches = true;
 1260  0
                 for (int i = 0; i < params1.length; i++) {
 1261  0
                     if (params1[i] != params2[i]) {
 1262  0
                         matches = false;
 1263  0
                         break;
 1264   
                     }
 1265   
                 }
 1266  0
                 if (matches) {
 1267  0
                     return true;
 1268   
                 }
 1269   
             }
 1270   
         }
 1271  0
         return false;
 1272   
     }
 1273   
 
 1274   
     /**
 1275   
      * Adds all of the newly defined methods from the given class to this
 1276   
      * metaclass
 1277   
      * 
 1278   
      * @param theClass
 1279   
      */
 1280  0
     protected void addNewStaticMethodsFrom(Class theClass) {
 1281  0
         MetaClass interfaceMetaClass = registry.getMetaClass(theClass);
 1282  0
         Iterator iter = interfaceMetaClass.newGroovyMethodsList.iterator();
 1283  0
         while (iter.hasNext()) {
 1284  0
             MetaMethod method = (MetaMethod) iter.next();
 1285  0
             addMethod(method);
 1286  0
             newGroovyMethodsList.add(method);
 1287   
         }
 1288   
     }
 1289   
 
 1290   
     /**
 1291   
      * @return the value of the static property of the given class
 1292   
      */
 1293  0
     protected Object getStaticProperty(Class aClass, String property) {
 1294   
         //System.out.println("Invoking property: " + property + " on class: "
 1295   
         // + aClass);
 1296   
 
 1297  0
         Exception lastException = null;
 1298  0
         try {
 1299  0
             Field field = aClass.getField(property);
 1300  0
             if (field != null) {
 1301  0
                 if ((field.getModifiers() & Modifier.STATIC) != 0) {
 1302  0
                     return field.get(null);
 1303   
                 }
 1304   
             }
 1305   
         }
 1306   
         catch (Exception e) {
 1307  0
             lastException = e;
 1308   
         }
 1309   
 
 1310   
         // lets try invoke a static getter method
 1311  0
         try {
 1312  0
             MetaMethod method = findStaticGetter(aClass, "get" + capitalize(property));
 1313  0
             if (method != null) {
 1314  0
                 return doMethodInvoke(aClass, method, EMPTY_ARRAY);
 1315   
             }
 1316   
         }
 1317   
         catch (GroovyRuntimeException e) {
 1318  0
             throw new MissingPropertyException(property, aClass, e);
 1319   
         }
 1320   
 
 1321  0
         if (lastException == null) {
 1322  0
             throw new MissingPropertyException(property, aClass);
 1323   
         }
 1324   
         else {
 1325  0
             throw new MissingPropertyException(property, aClass, lastException);
 1326   
         }
 1327   
     }
 1328   
 
 1329   
     /**
 1330   
      * @return the matching method which should be found
 1331   
      */
 1332  0
     protected MetaMethod findMethod(Method aMethod) {
 1333  0
         List methods = getMethods(aMethod.getName());
 1334  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1335  0
             MetaMethod method = (MetaMethod) iter.next();
 1336  0
             if (method.isMethod(aMethod)) {
 1337  0
                 return method;
 1338   
             }
 1339   
         }
 1340   
         //log.warning("Creating reflection based dispatcher for: " + aMethod);
 1341  0
         return new ReflectionMetaMethod(aMethod);
 1342   
     }
 1343   
 
 1344   
     /**
 1345   
      * @return the getter method for the given object
 1346   
      */
 1347  0
     protected MetaMethod findGetter(Object object, String name) {
 1348  0
         List methods = getMethods(name);
 1349  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1350  0
             MetaMethod method = (MetaMethod) iter.next();
 1351  0
             if (method.getParameterTypes().length == 0) {
 1352  0
                 return method;
 1353   
             }
 1354   
         }
 1355  0
         return null;
 1356   
     }
 1357   
 
 1358   
     /**
 1359   
      * @return the Method of the given name with no parameters or null
 1360   
      */
 1361  0
     protected MetaMethod findStaticGetter(Class type, String name) {
 1362  0
         List methods = getStaticMethods(name);
 1363  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1364  0
             MetaMethod method = (MetaMethod) iter.next();
 1365  0
             if (method.getParameterTypes().length == 0) {
 1366  0
                 return method;
 1367   
             }
 1368   
         }
 1369   
 
 1370   
         /** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
 1371  0
         try {
 1372  0
             Method method = type.getMethod(name, EMPTY_TYPE_ARRAY);
 1373  0
             if ((method.getModifiers() & Modifier.STATIC) != 0) {
 1374  0
                 return findMethod(method);
 1375   
             }
 1376   
             else {
 1377  0
                 return null;
 1378   
             }
 1379   
         }
 1380   
         catch (Exception e) {
 1381  0
             return null;
 1382   
         }
 1383   
     }
 1384   
 
 1385  0
     protected Object doMethodInvoke(Object object, MetaMethod method, Object[] argumentArray) {
 1386   
         //System.out.println("Evaluating method: " + method);
 1387   
         //System.out.println("on object: " + object + " with arguments: " +
 1388   
         // InvokerHelper.toString(argumentArray));
 1389   
         //System.out.println(this.theClass);
 1390   
 
 1391  0
         try {
 1392  0
             if (argumentArray == null) {
 1393  0
                 argumentArray = EMPTY_ARRAY;
 1394   
             }
 1395  0
             else if (method.getParameterTypes().length == 1 && argumentArray.length == 0) {
 1396  0
                 argumentArray = ARRAY_WITH_NULL;
 1397   
             }
 1398  0
             return method.invoke(object, argumentArray);
 1399   
         }
 1400   
         catch (ClassCastException e) {
 1401  0
             if (coerceGStrings(argumentArray)) {
 1402  0
                 try {
 1403  0
                     return doMethodInvoke(object, method, argumentArray);
 1404   
                 }
 1405   
                 catch (Exception e2) {
 1406   
                     // allow fall through
 1407   
                 }
 1408   
             }
 1409  0
             throw new GroovyRuntimeException(
 1410   
                 "failed to invoke method: "
 1411   
                     + method
 1412   
                     + " on: "
 1413   
                     + object
 1414   
                     + " with arguments: "
 1415   
                     + InvokerHelper.toString(argumentArray)
 1416   
                     + " reason: "
 1417   
                     + e,
 1418   
                 e);
 1419   
         }
 1420   
         catch (InvocationTargetException e) {
 1421  0
             Throwable t = e.getTargetException();
 1422  0
             if (t instanceof Error) {
 1423  0
                 Error error = (Error) t;
 1424  0
                 throw error;
 1425   
             }
 1426  0
             if (t instanceof RuntimeException) {
 1427  0
                 RuntimeException runtimeEx = (RuntimeException) t;
 1428  0
                 throw runtimeEx;
 1429   
             }
 1430  0
             throw new InvokerInvocationException(e);
 1431   
         }
 1432   
         catch (IllegalAccessException e) {
 1433  0
             throw new GroovyRuntimeException(
 1434   
                 "could not access method: "
 1435   
                     + method
 1436   
                     + " on: "
 1437   
                     + object
 1438   
                     + " with arguments: "
 1439   
                     + InvokerHelper.toString(argumentArray)
 1440   
                     + " reason: "
 1441   
                     + e,
 1442   
                 e);
 1443   
         }
 1444   
         catch (IllegalArgumentException e) {
 1445  0
             if (coerceGStrings(argumentArray)) {
 1446  0
                 try {
 1447  0
                     return doMethodInvoke(object, method, argumentArray);
 1448   
                 }
 1449   
                 catch (Exception e2) {
 1450   
                     // allow fall through
 1451   
                 }
 1452   
             }
 1453  0
             Object[] args = coerceNumbers(method, argumentArray);
 1454  0
             if (args != null) {
 1455  0
                 try {
 1456  0
                     return doMethodInvoke(object, method, args);
 1457   
                 }
 1458   
                 catch (Exception e3) {
 1459   
                     // allow fall through
 1460   
                 }
 1461   
             }
 1462   
 
 1463  0
             throw new GroovyRuntimeException(
 1464   
                     "failed to invoke method: "
 1465   
                     + method
 1466   
                     + " on: "
 1467   
                     + object
 1468   
                     + " with arguments: "
 1469   
                     + InvokerHelper.toString(argumentArray)
 1470   
                     + " reason: "
 1471   
                     + e,
 1472   
                     e);
 1473   
         }
 1474   
         catch (RuntimeException e) {
 1475  0
             throw e;
 1476   
         }
 1477   
         catch (Exception e) {
 1478  0
             throw new GroovyRuntimeException(
 1479   
                 "failed to invoke method: "
 1480   
                     + method
 1481   
                     + " on: "
 1482   
                     + object
 1483   
                     + " with arguments: "
 1484   
                     + InvokerHelper.toString(argumentArray)
 1485   
                     + " reason: "
 1486   
                     + e,
 1487   
                 e);
 1488   
         }
 1489   
     }
 1490   
 
 1491  0
     private static Object[] coerceNumbers(MetaMethod method, Object[] arguments) {
 1492  0
         Object[] ans = null;
 1493  0
         boolean coerced = false; // to indicate that at least one param is coerced
 1494   
 
 1495  0
         Class[] params = method.getParameterTypes();
 1496   
 
 1497  0
         if (params.length != arguments.length) {
 1498  0
             return null;
 1499   
         }
 1500   
 
 1501  0
         ans = new Object[arguments.length];
 1502   
 
 1503  0
         for (int i = 0, size = arguments.length; i < size; i++) {
 1504  0
             Object argument = arguments[i];
 1505  0
             Class param = params[i];
 1506  0
             if ((Number.class.isAssignableFrom(param) || param.isPrimitive()) && argument instanceof Number) { // Number types
 1507  0
                 if (param == Byte.class || param == Byte.TYPE ) {
 1508  0
                     ans[i] = new Byte(((Number)argument).byteValue());
 1509  0
                     coerced = true; continue;
 1510   
                 }
 1511  0
                 if (param == Double.class || param == Double.TYPE) {
 1512  0
                     ans[i] = new Double(((Number)argument).doubleValue());
 1513  0
                     coerced = true; continue;
 1514   
                 }
 1515  0
                 if (param == Float.class || param == Float.TYPE) {
 1516  0
                     ans[i] = new Float(((Number)argument).floatValue());
 1517  0
                     coerced = true; continue;
 1518   
                 }
 1519  0
                 if (param == Integer.class || param == Integer.TYPE) {
 1520  0
                     ans[i] = new Integer(((Number)argument).intValue());
 1521  0
                     coerced = true; continue;
 1522   
                 }
 1523  0
                 if (param == Long.class || param == Long.TYPE) {
 1524  0
                     ans[i] = new Long(((Number)argument).longValue());
 1525  0
                     coerced = true; continue;
 1526   
                 }
 1527  0
                 if (param == Short.class || param == Short.TYPE) {
 1528  0
                     ans[i] = new Short(((Number)argument).shortValue());
 1529  0
                     coerced = true; continue;
 1530   
                 }
 1531  0
                 if (param == BigDecimal.class ) {
 1532  0
                     ans[i] = new BigDecimal(((Number)argument).doubleValue());
 1533  0
                     coerced = true; continue;
 1534   
                 }
 1535  0
                 if (param == BigInteger.class) {
 1536  0
                     ans[i] = new BigInteger(String.valueOf(((Number)argument).longValue()));
 1537  0
                     coerced = true; continue;
 1538   
                 }
 1539   
             }
 1540  0
             else if (param.isArray() && argument.getClass().isArray()) {
 1541  0
                 Class paramElem = param.getComponentType();
 1542  0
                 if (paramElem.isPrimitive()) {
 1543  0
                     if (paramElem == boolean.class && argument.getClass().getName().equals("[Ljava.lang.Boolean;")) {
 1544  0
                         ans[i] = InvokerHelper.convertToBooleanArray(argument);
 1545  0
                         coerced = true;
 1546  0
                         continue;
 1547   
                     }
 1548  0
                     if (paramElem == byte.class && argument.getClass().getName().equals("[Ljava.lang.Byte;")) {
 1549  0
                         ans[i] = InvokerHelper.convertToByteArray(argument);
 1550  0
                         coerced = true;
 1551  0
                         continue;
 1552   
                     }
 1553  0
                     if (paramElem == char.class && argument.getClass().getName().equals("[Ljava.lang.Character;")) {
 1554  0
                         ans[i] = InvokerHelper.convertToCharArray(argument);
 1555  0
                         coerced = true;
 1556  0
                         continue;
 1557   
                     }
 1558  0
                     if (paramElem == short.class && argument.getClass().getName().equals("[Ljava.lang.Short;")) {
 1559  0
                         ans[i] = InvokerHelper.convertToShortArray(argument);
 1560  0
                         coerced = true;
 1561  0
                         continue;
 1562   
                     }
 1563  0
                     if (paramElem == int.class && argument.getClass().getName().equals("[Ljava.lang.Integer;")) {
 1564  0
                         ans[i] = InvokerHelper.convertToIntArray(argument);
 1565  0
                         coerced = true;
 1566  0
                         continue;
 1567   
                     }
 1568  0
                     if (paramElem == long.class
 1569   
                             && argument.getClass().getName().equals("[Ljava.lang.Long;")
 1570   
                             && argument.getClass().getName().equals("[Ljava.lang.Integer;")
 1571   
                                                             ) {
 1572  0
                         ans[i] = InvokerHelper.convertToLongArray(argument);
 1573  0
                         coerced = true;
 1574  0
                         continue;
 1575   
                     }
 1576  0
                     if (paramElem == float.class
 1577   
                             && argument.getClass().getName().equals("[Ljava.lang.Float;")
 1578   
                             && argument.getClass().getName().equals("[Ljava.lang.Integer;")
 1579   
                                                             ) {
 1580  0
                         ans[i] = InvokerHelper.convertToFloatArray(argument);
 1581  0
                         coerced = true;
 1582  0
                         continue;
 1583   
                     }
 1584  0
                     if (paramElem == double.class &&
 1585   
                             argument.getClass().getName().equals("[Ljava.lang.Double;") &&
 1586   
                             argument.getClass().getName().equals("[Ljava.lang.BigDecimal;") &&
 1587   
                             argument.getClass().getName().equals("[Ljava.lang.Float;")) {
 1588  0
                         ans[i] = InvokerHelper.convertToDoubleArray(argument);
 1589  0
                         coerced = true;
 1590  0
                         continue;
 1591   
                     }
 1592   
                 }
 1593   
             }
 1594   
         }
 1595  0
         return coerced ? ans : null;
 1596   
     }
 1597   
 
 1598  0
     protected Object doConstructorInvoke(Constructor constructor, Object[] argumentArray) {
 1599   
         //System.out.println("Evaluating constructor: " + constructor + " with
 1600   
         // arguments: " + InvokerHelper.toString(argumentArray));
 1601   
         //System.out.println(this.theClass);
 1602   
 
 1603  0
         try {
 1604   
             // the following patch was provided by Mori Kouhei to fix JIRA 435
 1605   
             /* but it opens the ctor up to everyone, so it is no longer private!
 1606   
             final Constructor ctor = constructor;
 1607   
             AccessController.doPrivileged(new PrivilegedAction() {
 1608   
                 public Object run() {
 1609   
                     ctor.setAccessible(ctor.getDeclaringClass().equals(theClass));
 1610   
                     return null;
 1611   
                 }
 1612   
             });
 1613   
             */
 1614   
             // end of patch
 1615   
 
 1616  0
             return constructor.newInstance(argumentArray);
 1617   
         }
 1618   
         catch (InvocationTargetException e) {
 1619  0
             Throwable t = e.getTargetException();
 1620  0
             if (t instanceof Error) {
 1621  0
                 Error error = (Error) t;
 1622  0
                 throw error;
 1623   
             }
 1624  0
             if (t instanceof RuntimeException) {
 1625  0
                 RuntimeException runtimeEx = (RuntimeException) t;
 1626  0
                 throw runtimeEx;
 1627   
             }
 1628  0
             throw new InvokerInvocationException(e);
 1629   
         }
 1630   
         catch (IllegalArgumentException e) {
 1631  0
             if (coerceGStrings(argumentArray)) {
 1632  0
                 try {
 1633  0
                     return constructor.newInstance(argumentArray);
 1634   
                 }
 1635   
                 catch (Exception e2) {
 1636   
                     // allow fall through
 1637   
                 }
 1638   
             }
 1639  0
             throw new GroovyRuntimeException(
 1640   
                 "failed to invoke constructor: "
 1641   
                     + constructor
 1642   
                     + " with arguments: "
 1643   
                     + InvokerHelper.toString(argumentArray)
 1644   
                     + " reason: "
 1645   
                     + e,
 1646   
                 e);
 1647   
         }
 1648   
         catch (IllegalAccessException e) {
 1649  0
             throw new GroovyRuntimeException(
 1650   
                 "could not access constructor: "
 1651   
                     + constructor
 1652   
                     + " with arguments: "
 1653   
                     + InvokerHelper.toString(argumentArray)
 1654   
                     + " reason: "
 1655   
                     + e,
 1656   
                 e);
 1657   
         }
 1658   
         catch (Exception e) {
 1659  0
             throw new GroovyRuntimeException(
 1660   
                 "failed to invoke constructor: "
 1661   
                     + constructor
 1662   
                     + " with arguments: "
 1663   
                     + InvokerHelper.toString(argumentArray)
 1664   
                     + " reason: "
 1665   
                     + e,
 1666   
                 e);
 1667   
         }
 1668   
     }
 1669   
 
 1670   
     /**
 1671   
      * Chooses the correct method to use from a list of methods which match by
 1672   
      * name.
 1673   
      * 
 1674   
      * @param methods
 1675   
      *            the possible methods to choose from
 1676   
      * @param arguments
 1677   
      *            the original argument to the method
 1678   
      * @return
 1679   
      */
 1680  0
     protected Object chooseMethod(String methodName, List methods, Class[] arguments, boolean coerce) {
 1681  0
         int methodCount = methods.size();
 1682  0
         if (methodCount <= 0) {
 1683  0
             return null;
 1684   
         }
 1685  0
         else if (methodCount == 1) {
 1686  0
             Object method = methods.get(0);
 1687  0
             if (isValidMethod(method, arguments, coerce)) {
 1688  0
                 return method;
 1689   
             }
 1690  0
             return null;
 1691   
         }
 1692  0
         Object answer = null;
 1693  0
         if (arguments == null || arguments.length == 0) {
 1694  0
             answer = chooseEmptyMethodParams(methods);
 1695   
         }
 1696  0
         else if (arguments.length == 1 && arguments[0] == null) {
 1697  0
             answer = chooseMostGeneralMethodWith1Param(methods);
 1698   
         }
 1699   
         else {
 1700  0
             List matchingMethods = new ArrayList();
 1701   
 
 1702  0
             for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1703  0
                 Object method = iter.next();
 1704  0
                 Class[] paramTypes;
 1705   
 
 1706   
                 // making this false helps find matches
 1707  0
                 if (isValidMethod(method, arguments, coerce)) {
 1708  0
                     matchingMethods.add(method);
 1709   
                 }
 1710   
             }
 1711  0
             if (matchingMethods.isEmpty()) {
 1712  0
                 return null;
 1713   
             }
 1714  0
             else if (matchingMethods.size() == 1) {
 1715  0
                 return matchingMethods.get(0);
 1716   
             }
 1717  0
             return chooseMostSpecificParams(methodName, matchingMethods, arguments);
 1718   
 
 1719   
         }
 1720  0
         if (answer != null) {
 1721  0
             return answer;
 1722   
         }
 1723  0
         throw new GroovyRuntimeException(
 1724   
             "Could not find which method to invoke from this list: "
 1725   
                 + methods
 1726   
                 + " for arguments: "
 1727   
                 + InvokerHelper.toString(arguments));
 1728   
     }
 1729   
 
 1730  0
     protected boolean isValidMethod(Object method, Class[] arguments, boolean includeCoerce) {
 1731  0
         Class[] paramTypes = getParameterTypes(method);
 1732  0
         return isValidMethod(paramTypes, arguments, includeCoerce);
 1733   
     }
 1734   
 
 1735  0
     public static boolean isValidMethod(Class[] paramTypes, Class[] arguments, boolean includeCoerce) {
 1736  0
         if (arguments == null) {
 1737  0
             return true;
 1738   
         }
 1739  0
         int size = arguments.length;
 1740  0
         boolean validMethod = false;
 1741  0
         if (paramTypes.length == size) {
 1742   
             // lets check the parameter types match
 1743  0
             validMethod = true;
 1744  0
             for (int i = 0; i < size; i++) {
 1745  0
                 if (!isCompatibleClass(paramTypes[i], arguments[i], includeCoerce)) {
 1746  0
                     validMethod = false;
 1747   
                 }
 1748   
             }
 1749   
         }
 1750   
         else {
 1751  0
             if (paramTypes.length == 1 && size == 0) {
 1752  0
                 return true;
 1753   
             }
 1754   
         }
 1755  0
         return validMethod;
 1756   
     }
 1757   
 
 1758  0
     protected Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
 1759  0
         Object answer = null;
 1760  0
         int size = arguments.length;
 1761  0
         Class[] mostSpecificTypes = null;
 1762  0
         for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
 1763  0
             Object method = iter.next();
 1764  0
             Class[] paramTypes = getParameterTypes(method);
 1765  0
             if (answer == null) {
 1766  0
                 answer = method;
 1767  0
                 mostSpecificTypes = paramTypes;
 1768   
             }
 1769   
             else {
 1770  0
                 boolean useThisMethod = false;
 1771  0
                 for (int i = 0; i < size; i++) {
 1772  0
                     Class mostSpecificType = mostSpecificTypes[i];
 1773  0
                     Class type = paramTypes[i];
 1774   
 
 1775  0
                     if (!isAssignableFrom(mostSpecificType, type)) {
 1776   
 
 1777  0
                         useThisMethod = true;
 1778  0
                         break;
 1779   
                     }
 1780   
 
 1781   
                 }
 1782  0
                 if (useThisMethod) {
 1783   
 
 1784  0
                     if (size > 1) {
 1785  0
                         checkForInvalidOverloading(name, mostSpecificTypes, paramTypes);
 1786   
                     }
 1787   
 
 1788  0
                     answer = method;
 1789  0
                     mostSpecificTypes = paramTypes;
 1790   
                 }
 1791   
             }
 1792   
         }
 1793  0
         return answer;
 1794   
     }
 1795   
 
 1796   
     /**
 1797   
      * Checks that one of the parameter types is a superset of the other and
 1798   
      * that the two lists of types don't conflict. e.g. foo(String, Object) and
 1799   
      * foo(Object, String) would conflict if called with foo("a", "b").
 1800   
      * 
 1801   
      * Note that this method is only called with 2 possible signatures. i.e.
 1802   
      * possible invalid combinations will already have been filtered out. So if
 1803   
      * there were methods foo(String, Object) and foo(Object, String) then one
 1804   
      * of these would be already filtered out if foo was called as foo(12, "a")
 1805   
      */
 1806  0
     protected void checkForInvalidOverloading(String name, Class[] baseTypes, Class[] derivedTypes) {
 1807  0
         for (int i = 0, size = baseTypes.length; i < size; i++) {
 1808  0
             Class baseType = baseTypes[i];
 1809  0
             Class derivedType = derivedTypes[i];
 1810  0
             if (!isAssignableFrom(derivedType, baseType)) {
 1811  0
                 throw new GroovyRuntimeException(
 1812   
                     "Ambiguous method overloading for method: "
 1813   
                         + name
 1814   
                         + ". Cannot resolve which method to invoke due to overlapping prototypes between: "
 1815   
                         + InvokerHelper.toString(baseTypes)
 1816   
                         + " and: "
 1817   
                         + InvokerHelper.toString(derivedTypes));
 1818   
             }
 1819   
         }
 1820   
     }
 1821   
 
 1822  0
     protected Class[] getParameterTypes(Object methodOrConstructor) {
 1823  0
         if (methodOrConstructor instanceof MetaMethod) {
 1824  0
             MetaMethod method = (MetaMethod) methodOrConstructor;
 1825  0
             return method.getParameterTypes();
 1826   
         }
 1827  0
         if (methodOrConstructor instanceof Method) {
 1828  0
             Method method = (Method) methodOrConstructor;
 1829  0
             return method.getParameterTypes();
 1830   
         }
 1831  0
         if (methodOrConstructor instanceof Constructor) {
 1832  0
             Constructor constructor = (Constructor) methodOrConstructor;
 1833  0
             return constructor.getParameterTypes();
 1834   
         }
 1835  0
         throw new IllegalArgumentException("Must be a Method or Constructor");
 1836   
     }
 1837   
 
 1838   
     /**
 1839   
      * @return the method with 1 parameter which takes the most general type of
 1840   
      *         object (e.g. Object)
 1841   
      */
 1842  0
     protected Object chooseMostGeneralMethodWith1Param(List methods) {
 1843   
         // lets look for methods with 1 argument which matches the type of the
 1844   
         // arguments
 1845  0
         Class closestClass = null;
 1846  0
         Object answer = null;
 1847   
 
 1848  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1849  0
             Object method = iter.next();
 1850  0
             Class[] paramTypes = getParameterTypes(method);
 1851  0
             int paramLength = paramTypes.length;
 1852  0
             if (paramLength == 1) {
 1853  0
                 Class theType = paramTypes[0];
 1854  0
                 if (closestClass == null || isAssignableFrom(closestClass, theType)) {
 1855  0
                     closestClass = theType;
 1856  0
                     answer = method;
 1857   
                 }
 1858   
             }
 1859   
         }
 1860  0
         return answer;
 1861   
     }
 1862   
 
 1863   
     /**
 1864   
      * @return the method with 1 parameter which takes the most general type of
 1865   
      *         object (e.g. Object)
 1866   
      */
 1867  0
     protected Object chooseEmptyMethodParams(List methods) {
 1868  0
         for (Iterator iter = methods.iterator(); iter.hasNext();) {
 1869  0
             Object method = iter.next();
 1870  0
             Class[] paramTypes = getParameterTypes(method);
 1871  0
             int paramLength = paramTypes.length;
 1872  0
             if (paramLength == 0) {
 1873  0
                 return method;
 1874   
             }
 1875   
         }
 1876  0
         return null;
 1877   
     }
 1878   
 
 1879  0
     protected static boolean isCompatibleInstance(Class type, Object value, boolean includeCoerce) {
 1880  0
         boolean answer = value == null || type.isInstance(value);
 1881  0
         if (!answer) {
 1882  0
             if (type.isPrimitive()) {
 1883  0
                 if (type == int.class) {
 1884  0
                     return value instanceof Integer;
 1885   
                 }
 1886  0
                 else if (type == double.class) {
 1887  0
                     return value instanceof Double || value instanceof Float || value instanceof Integer || value instanceof BigDecimal;
 1888   
                 }
 1889  0
                 else if (type == boolean.class) {
 1890  0
                     return value instanceof Boolean;
 1891   
                 }
 1892  0
                 else if (type == long.class) {
 1893  0
                     return value instanceof Long || value instanceof Integer;
 1894   
                 }
 1895  0
                 else if (type == float.class) {
 1896  0
                     return value instanceof Float || value instanceof Integer;
 1897   
                 }
 1898  0
                 else if (type == char.class) {
 1899  0
                     return value instanceof Character;
 1900   
                 }
 1901  0
                 else if (type == byte.class) {
 1902  0
                     return value instanceof Byte;
 1903   
                 }
 1904  0
                 else if (type == short.class) {
 1905  0
                     return value instanceof Short;
 1906   
                 }
 1907   
             }
 1908  0
             else if(type.isArray() && value.getClass().isArray()) {
 1909  0
                 return isCompatibleClass(type.getComponentType(), value.getClass().getComponentType(), false);
 1910   
             }
 1911  0
             else if (includeCoerce) {
 1912  0
                 if (type == String.class && value instanceof GString) {
 1913  0
                     return true;
 1914   
                 }
 1915  0
                 else if (value instanceof Number) {
 1916   
                     // lets allow numbers to be coerced downwards?
 1917  0
                     return Number.class.isAssignableFrom(type);
 1918   
                 }
 1919   
             }
 1920   
         }
 1921  0
         return answer;
 1922   
     }
 1923  0
     protected static boolean isCompatibleClass(Class type, Class value, boolean includeCoerce) {
 1924  0
         boolean answer = value == null || type.isAssignableFrom(value); // this might have taken care of primitive types, rendering part of the following code unnecessary
 1925  0
         if (!answer) {
 1926  0
             if (type.isPrimitive()) {
 1927  0
                 if (type == int.class) {
 1928  0
                     return value == Integer.class;// || value == BigDecimal.class; //br added BigDecimal
 1929   
                 }
 1930  0
                 else if (type == double.class) {
 1931  0
                     return value == Double.class || value == Float.class || value == Integer.class || value == BigDecimal.class;
 1932   
                 }
 1933  0
                 else if (type == boolean.class) {
 1934  0
                     return value == Boolean.class;
 1935   
                 }
 1936  0
                 else if (type == long.class) {
 1937  0
                     return value == Long.class || value == Integer.class; // || value == BigDecimal.class;//br added BigDecimal
 1938   
                 }
 1939  0
                 else if (type == float.class) {
 1940  0
                     return value == Float.class || value == Integer.class; // || value == BigDecimal.class;//br added BigDecimal
 1941   
                 }
 1942  0
                 else if (type == char.class) {
 1943  0
                     return value == Character.class;
 1944   
                 }
 1945  0
                 else if (type == byte.class) {
 1946  0
                     return value == Byte.class;
 1947   
                 }
 1948  0
                 else if (type == short.class) {
 1949  0
                     return value == Short.class;
 1950   
                 }
 1951   
             }
 1952  0
             else if(type.isArray() && value.isArray()) {
 1953  0
                 return isCompatibleClass(type.getComponentType(), value.getComponentType(), false);
 1954   
             }
 1955  0
             else if (includeCoerce) {
 1956   
 //if (type == String.class && value == GString.class) {
 1957  0
                 if (type == String.class && GString.class.isAssignableFrom(value)) {
 1958  0
                     return true;
 1959   
                 }
 1960  0
                 else if (value == Number.class) {
 1961   
                     // lets allow numbers to be coerced downwards?
 1962  0
                     return Number.class.isAssignableFrom(type);
 1963   
                 }
 1964   
             }
 1965   
         }
 1966  0
         return answer;
 1967   
     }
 1968   
 
 1969  0
     protected boolean isAssignableFrom(Class mostSpecificType, Class type) {
 1970   
         // let's handle primitives
 1971  0
         if (mostSpecificType.isPrimitive() && type.isPrimitive()) {
 1972  0
             if (mostSpecificType == type) {
 1973  0
                 return true;
 1974   
             }
 1975   
             else {  // note: there is not coercion for boolean and char. Range matters, precision doesn't
 1976  0
                 if (type == int.class) {
 1977  0
                     return
 1978   
                             mostSpecificType == int.class
 1979   
                             || mostSpecificType == short.class
 1980   
                             || mostSpecificType == byte.class;
 1981   
                 }
 1982  0
                 else if (type == double.class) {
 1983  0
                     return
 1984   
                             mostSpecificType == double.class
 1985   
                             || mostSpecificType == int.class
 1986   
                             || mostSpecificType == long.class
 1987   
                             || mostSpecificType == short.class
 1988   
                             || mostSpecificType == byte.class
 1989   
                             || mostSpecificType == float.class;
 1990   
                 }
 1991  0
                 else if (type == long.class) {
 1992  0
                     return
 1993   
                             mostSpecificType == long.class
 1994   
                             || mostSpecificType == int.class
 1995   
                             || mostSpecificType == short.class
 1996   
                             || mostSpecificType == byte.class;
 1997   
                 }
 1998  0
                 else if (type == float.class) {
 1999  0
                     return
 2000   
                             mostSpecificType == float.class
 2001   
                             || mostSpecificType == int.class
 2002   
                             || mostSpecificType == long.class
 2003   
                             || mostSpecificType == short.class
 2004   
                             || mostSpecificType == byte.class;
 2005   
                 }
 2006  0
                 else if (type == short.class) {
 2007  0
                     return
 2008   
                             mostSpecificType == short.class
 2009   
                             || mostSpecificType == byte.class;
 2010   
                 }
 2011   
                 else {
 2012  0
                     return false;
 2013   
                 }
 2014   
             }
 2015   
         }
 2016   
 
 2017  0
         boolean answer = type.isAssignableFrom(mostSpecificType);
 2018  0
         if (!answer) {
 2019  0
             answer = autoboxType(type).isAssignableFrom(autoboxType(mostSpecificType));
 2020   
         }
 2021  0
         return answer;
 2022   
     }
 2023   
 
 2024  0
     private Class autoboxType(Class type) {
 2025  0
         if (type.isPrimitive()) {
 2026  0
             if (type == int.class) {
 2027  0
                 return Integer.class;
 2028   
             }
 2029  0
             else if (type == double.class) {
 2030  0
                 return Double.class;
 2031   
             }
 2032  0
             else if (type == long.class) {
 2033  0
                 return Long.class;
 2034   
             }
 2035  0
             else if (type == boolean.class) {
 2036  0
                 return Boolean.class;
 2037   
             }
 2038  0
             else if (type == float.class) {
 2039  0
                 return Float.class;
 2040   
             }
 2041  0
             else if (type == char.class) {
 2042  0
                 return Character.class;
 2043   
             }
 2044  0
             else if (type == byte.class) {
 2045  0
                 return Byte.class;
 2046   
             }
 2047  0
             else if (type == short.class) {
 2048  0
                 return Short.class;
 2049   
             }
 2050   
         }
 2051  0
         return type;
 2052   
     }
 2053   
 
 2054   
     /**
 2055   
      * Coerces any GString instances into Strings
 2056   
      * 
 2057   
      * @return true if some coercion was done. 
 2058   
      */
 2059  0
     protected static boolean coerceGStrings(Object[] arguments) {
 2060  0
         boolean coerced = false;
 2061  0
         for (int i = 0, size = arguments.length; i < size; i++) {
 2062  0
             Object argument = arguments[i];
 2063  0
             if (argument instanceof GString) {
 2064  0
                 arguments[i] = argument.toString();
 2065  0
                 coerced = true;
 2066   
             }
 2067   
         }
 2068  0
         return coerced;
 2069   
     }
 2070   
 
 2071  0
     protected boolean isGenericSetMethod(MetaMethod method) {
 2072  0
         return (method.getName().equals("set"))
 2073   
             && method.getParameterTypes().length == 2;
 2074   
     }
 2075   
 
 2076  0
     protected boolean isGenericGetMethod(MetaMethod method) {
 2077  0
         if (method.getName().equals("get")) {
 2078  0
             Class[] parameterTypes = method.getParameterTypes();
 2079  0
             return parameterTypes.length == 1 && parameterTypes[0] == String.class;
 2080   
         }
 2081  0
         return false;
 2082   
     }
 2083   
 
 2084  0
     private void registerMethods(boolean instanceMethods) {
 2085  0
         Method[] methods = theClass.getMethods();
 2086  0
         for (int i = 0; i < methods.length; i++) {
 2087  0
             Method method = methods[i];
 2088  0
             if (MethodHelper.isStatic(method)) {
 2089  0
                 Class[] paramTypes = method.getParameterTypes();
 2090  0
                 if (paramTypes.length > 0) {
 2091  0
                     Class owner = paramTypes[0];
 2092  0
                     if (instanceMethods) {
 2093  0
                         registry.lookup(owner).addNewInstanceMethod(method);
 2094   
                     } else {
 2095  0
                         registry.lookup(owner).addNewStaticMethod(method);
 2096   
                     }
 2097   
                 }
 2098   
             }
 2099   
         }
 2100   
     }
 2101   
 
 2102  0
     protected void registerStaticMethods() {
 2103  0
         registerMethods(false);
 2104   
     }
 2105   
 
 2106  0
     protected void registerInstanceMethods() {
 2107  0
         registerMethods(true);
 2108   
     }
 2109   
 
 2110  0
     protected String capitalize(String property) {
 2111  0
         return property.substring(0, 1).toUpperCase() + property.substring(1, property.length());
 2112   
     }
 2113   
 
 2114   
     /**
 2115   
      * Call this method when any mutation method is called, such as adding a new
 2116   
      * method to this MetaClass so that any caching or bytecode generation can be
 2117   
      * regenerated.
 2118   
      */
 2119  0
     protected synchronized void onMethodChange() {
 2120  0
         reflector = null;
 2121   
     }
 2122   
     
 2123  0
     protected synchronized void checkInitialised() {
 2124  0
         if (!initialised) {
 2125  0
             initialised = true;
 2126  0
             addInheritedMethods(theClass);
 2127   
         }
 2128  0
         if (reflector == null) {
 2129  0
             generateReflector();
 2130   
         }
 2131   
     }
 2132   
 
 2133  0
     protected MetaMethod createMetaMethod(final Method method) {
 2134  0
         if (registry.useAccessible()) {
 2135  0
             AccessController.doPrivileged(new PrivilegedAction() {
 2136  0
                 public Object run() {
 2137  0
                     method.setAccessible(true);
 2138  0
                     return null;
 2139   
                 }
 2140   
             });
 2141   
         }
 2142  0
         if (useReflection) {
 2143   
             //log.warning("Creating reflection based dispatcher for: " + method);
 2144  0
             return new ReflectionMetaMethod(method);
 2145   
         }
 2146  0
         MetaMethod answer = new MetaMethod(method);
 2147  0
         if (isValidReflectorMethod(answer)) {
 2148  0
             allMethods.add(answer);
 2149  0
             answer.setMethodIndex(allMethods.size());
 2150   
         }
 2151   
         else {
 2152   
             //log.warning("Creating reflection based dispatcher for: " + method);
 2153  0
             answer = new ReflectionMetaMethod(method);
 2154   
         }
 2155  0
         return answer;
 2156   
     }
 2157   
 
 2158  0
     protected boolean isValidReflectorMethod(MetaMethod method) {
 2159   
         // We cannot use a reflector if the method is private, protected, or package accessible only.
 2160  0
         if (!method.isPublic()) {
 2161  0
             return false;
 2162   
         }
 2163  0
         Class declaringClass = method.getDeclaringClass();
 2164  0
         if (!Modifier.isPublic(declaringClass.getModifiers())) {
 2165   
             // lets see if this method is implemented on an interface
 2166  0
             List list = getInterfaceMethods();
 2167  0
             for (Iterator iter = list.iterator(); iter.hasNext();) {
 2168  0
                 MetaMethod aMethod = (MetaMethod) iter.next();
 2169  0
                 if (method.isSame(aMethod)) {
 2170  0
                     method.setInterfaceClass(aMethod.getDeclaringClass());
 2171  0
                     return true;
 2172   
                 }
 2173   
             }
 2174   
             /** todo */
 2175   
             //log.warning("Cannot invoke method on protected/private class which isn't visible on an interface so must use reflection instead: " + method);
 2176  0
             return false;
 2177   
         }
 2178  0
         return true;
 2179   
     }
 2180   
 
 2181  0
     protected void generateReflector() {
 2182  0
         reflector = loadReflector(allMethods);
 2183  0
         if (reflector == null) {
 2184  0
             throw new RuntimeException("Should have a reflector!");
 2185   
         }
 2186   
         // lets set the reflector on all the methods
 2187  0
         for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
 2188  0
             MetaMethod metaMethod = (MetaMethod) iter.next();
 2189   
             //System.out.println("Setting reflector for method: " + metaMethod + " with index: " + metaMethod.getMethodIndex());
 2190  0
             metaMethod.setReflector(reflector);
 2191   
         }
 2192   
     }
 2193   
 
 2194  0
     protected Reflector loadReflector(List methods) {
 2195  0
         ReflectorGenerator generator = new ReflectorGenerator(methods);
 2196  0
         String className = theClass.getName();
 2197  0
         String packagePrefix = "gjdk.";
 2198   
         /*
 2199   
         if (className.startsWith("java.")) {
 2200   
             packagePrefix = "gjdk.";
 2201   
         }
 2202   
         */
 2203  0
         String name = packagePrefix + className + "_GroovyReflector";
 2204  0
         if (theClass.isArray()) {
 2205  0
             String componentName = theClass.getComponentType().getName();
 2206   
             /*
 2207   
             if (componentName.startsWith("java.")) {
 2208   
                 packagePrefix = "gjdk.";
 2209   
             }
 2210   
             */
 2211  0
             name = packagePrefix + componentName + "_GroovyReflectorArray";
 2212   
         }
 2213   
         // lets see if its already loaded
 2214  0
         try {
 2215  0
             Class type = loadReflectorClass(name);
 2216  0
             return (Reflector) type.newInstance();
 2217   
         }
 2218   
         catch (AccessControlException ace) {
 2219   
             //Don't ignore this exception type
 2220  0
             throw ace;
 2221   
         } 
 2222   
         catch (Exception e) {
 2223   
             // lets ignore, lets generate it && load it
 2224   
         }
 2225   
 
 2226  0
         ClassWriter cw = new ClassWriter(true);
 2227  0
         generator.generate(cw, name);
 2228   
 
 2229  0
         byte[] bytecode = cw.toByteArray();
 2230   
 
 2231  0
         try {
 2232  0
             Class type = loadReflectorClass(name, bytecode);
 2233  0
             return (Reflector) type.newInstance();
 2234   
         }
 2235   
         catch (Exception e) {
 2236  0
             throw new GroovyRuntimeException("Could not load the reflector for class: " + name + ". Reason: " + e, e);
 2237   
         }
 2238   
     }
 2239   
 
 2240  0
     protected Class loadReflectorClass(final String name, final byte[] bytecode) throws ClassNotFoundException {
 2241  0
         ClassLoader loader = theClass.getClassLoader();
 2242  0
         if (loader instanceof GroovyClassLoader) {
 2243  0
             final GroovyClassLoader gloader = (GroovyClassLoader) loader;
 2244  0
             return (Class) AccessController.doPrivileged(new PrivilegedAction() {
 2245  0
                 public Object run() {
 2246  0
                     return gloader.defineClass(name, bytecode, getClass().getProtectionDomain());
 2247   
                 }
 2248   
             });
 2249   
         }
 2250  0
         return registry.loadClass(name, bytecode);
 2251   
     }
 2252   
 
 2253  0
     protected Class loadReflectorClass(String name) throws ClassNotFoundException {
 2254  0
         ClassLoader loader = theClass.getClassLoader();
 2255  0
         if (loader instanceof GroovyClassLoader) {
 2256  0
             GroovyClassLoader gloader = (GroovyClassLoader) loader;
 2257  0
             return gloader.loadClass(name);
 2258   
         }
 2259  0
         return registry.loadClass(name);
 2260   
     }
 2261   
 
 2262  0
     public List getMethods() {
 2263  0
         return allMethods;
 2264   
     }
 2265   
 
 2266  0
     public List getMetaMethods() {
 2267  0
         return (List) ((ArrayList)newGroovyMethodsList).clone();
 2268   
     }
 2269   
 
 2270  0
     protected synchronized List getInterfaceMethods() {
 2271  0
         if (interfaceMethods == null) {
 2272  0
             interfaceMethods = new ArrayList();
 2273  0
             Class type = theClass;
 2274  0
             while (type != null) {
 2275  0
                 Class[] interfaces = type.getInterfaces();
 2276  0
                 for (int i = 0; i < interfaces.length; i++) {
 2277  0
                     Class iface = interfaces[i];
 2278  0
                     Method[] methods = iface.getMethods();
 2279  0
                     addInterfaceMethods(interfaceMethods, methods);
 2280   
                 }
 2281  0
                 type = type.getSuperclass();
 2282   
             }
 2283   
         }
 2284  0
         return interfaceMethods;
 2285   
     }
 2286   
 
 2287  0
     private void addInterfaceMethods(List list, Method[] methods) {
 2288  0
         for (int i = 0; i < methods.length; i++) {
 2289  0
             list.add(createMetaMethod(methods[i]));
 2290   
         }
 2291   
     }
 2292   
 
 2293   
     /**
 2294   
      * param instance array to the type array
 2295   
      * @param args
 2296   
      * @return
 2297   
      */
 2298  0
     Class[] convertToTypeArray(Object[] args) {
 2299  0
         if (args == null)
 2300  0
             return null;
 2301  0
         int s = args.length;
 2302  0
         Class[] ans = new Class[s];
 2303  0
         for (int i = 0; i < s; i++) {
 2304  0
             Object o = args[i];
 2305  0
             if (o != null) {
 2306  0
                 ans[i] = o.getClass();
 2307   
             } else {
 2308  0
                 ans[i] = null;
 2309   
             }
 2310   
         }
 2311  0
         return ans;
 2312   
     }
 2313   
 }
 2314