1 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.*; 70 import java.util.logging.Logger ; 71 72 import org.codehaus.groovy.ast.ClassNode; 73 import org.codehaus.groovy.classgen.ReflectorGenerator; 74 import org.codehaus.groovy.control.CompilationUnit; 75 import org.codehaus.groovy.control.Phases; 76 import org.codehaus.groovy.control.CompilerConfiguration; 77 import org.codehaus.groovy.runtime.ClosureListener; 78 import org.codehaus.groovy.runtime.DefaultGroovyMethods; 79 import org.codehaus.groovy.runtime.GroovyCategorySupport; 80 import org.codehaus.groovy.runtime.InvokerHelper; 81 import org.codehaus.groovy.runtime.InvokerInvocationException; 82 import org.codehaus.groovy.runtime.MethodClosure; 83 import org.codehaus.groovy.runtime.MethodHelper; 84 import org.codehaus.groovy.runtime.MethodKey; 85 import org.codehaus.groovy.runtime.NewInstanceMetaMethod; 86 import org.codehaus.groovy.runtime.NewStaticMetaMethod; 87 import org.codehaus.groovy.runtime.ReflectionMetaMethod; 88 import org.codehaus.groovy.runtime.Reflector; 89 import org.codehaus.groovy.runtime.TemporaryMethodKey; 90 import org.codehaus.groovy.runtime.TransformMetaMethod; 91 import org.objectweb.asm.ClassVisitor; 92 import org.objectweb.asm.ClassWriter; 93 94 101 public class MetaClass { 102 103 private static final Logger log = Logger.getLogger(MetaClass.class.getName()); 104 105 public static final Object [] EMPTY_ARRAY = { 106 }; 107 public static Class [] EMPTY_TYPE_ARRAY = { 108 }; 109 protected static final Object [] ARRAY_WITH_NULL = { null }; 110 111 private static boolean useReflection = false; 112 113 protected MetaClassRegistry registry; 114 protected Class theClass; 115 private ClassNode classNode; 116 private Map methodIndex = new HashMap(); 117 private Map staticMethodIndex = new HashMap(); 118 private List newGroovyMethodsList = new ArrayList(); 119 private Map propertyMap = Collections.synchronizedMap(new HashMap()); 121 private Map listeners = new HashMap(); 122 private Map methodCache = Collections.synchronizedMap(new HashMap()); 123 private Map staticMethodCache = Collections.synchronizedMap(new HashMap()); 124 private MetaMethod genericGetMethod; 125 private MetaMethod genericSetMethod; 126 private List constructors; 127 private List allMethods = new ArrayList(); 128 private List interfaceMethods; 129 private Reflector reflector; 130 private boolean initialised; 131 private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty(); 133 134 public MetaClass(MetaClassRegistry registry, final Class theClass) throws IntrospectionException { 135 this.registry = registry; 136 this.theClass = theClass; 137 138 constructors = Arrays.asList(theClass.getDeclaredConstructors()); 139 addMethods(theClass,true); 140 141 BeanInfo info = null; 143 try { 144 info =(BeanInfo ) AccessController.doPrivileged(new PrivilegedExceptionAction () { 145 public Object run() throws IntrospectionException { 146 return Introspector.getBeanInfo(theClass); 147 } 148 }); 149 } catch (PrivilegedActionException pae) { 150 if (pae.getException() instanceof IntrospectionException ) { 151 throw (IntrospectionException ) pae.getException(); 152 } else { 153 throw new RuntimeException (pae.getException()); 154 } 155 } 156 157 PropertyDescriptor [] descriptors = info.getPropertyDescriptors(); 158 159 setupProperties(descriptors); 162 163 169 170 EventSetDescriptor [] eventDescriptors = info.getEventSetDescriptors(); 171 for (int i = 0; i < eventDescriptors.length; i++) { 172 EventSetDescriptor descriptor = eventDescriptors[i]; 173 Method [] listenerMethods = descriptor.getListenerMethods(); 174 for (int j = 0; j < listenerMethods.length; j++) { 175 Method listenerMethod = listenerMethods[j]; 176 MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod()); 177 listeners.put(listenerMethod.getName(), metaMethod); 178 } 179 } 180 } 181 182 public static boolean isUseReflection() { 183 return useReflection; 184 } 185 186 192 public static void setUseReflection(boolean useReflection) { 193 MetaClass.useReflection = useReflection; 194 } 195 196 private void addInheritedMethods() { 197 LinkedList superClasses = new LinkedList(); 198 for (Class c = theClass.getSuperclass(); c!=Object .class && c!= null; c = c.getSuperclass()) { 199 superClasses.addFirst(c); 200 } 201 for (Iterator iter = superClasses.iterator(); iter.hasNext();) { 203 Class c = (Class ) iter.next(); 204 addMethods(c,true); 205 addNewStaticMethodsFrom(c); 206 } 207 208 Class [] interfaces = theClass.getInterfaces(); 210 for (int i = 0; i < interfaces.length; i++) { 211 addNewStaticMethodsFrom(interfaces[i]); 212 } 213 214 if (theClass != Object .class) { 217 addMethods(Object .class, false); 218 addNewStaticMethodsFrom(Object .class); 219 } 220 221 if (theClass.isArray() && !theClass.equals(Object [].class)) { 222 addNewStaticMethodsFrom(Object [].class); 223 } 224 } 225 226 230 public List getMethods(String name) { 231 List answer = (List) methodIndex.get(name); 232 List used = GroovyCategorySupport.getCategoryMethods(theClass, name); 233 if (used != null) { 234 if (answer != null) { 235 used.addAll(answer); 236 } 237 answer = used; 238 } 239 if (answer == null) { 240 answer = Collections.EMPTY_LIST; 241 } 242 return answer; 243 } 244 245 249 public List getStaticMethods(String name) { 250 List answer = (List) staticMethodIndex.get(name); 251 if (answer == null) { 252 return Collections.EMPTY_LIST; 253 } 254 return answer; 255 } 256 257 263 protected void addNewInstanceMethod(Method method) { 264 if (initialised) { 265 throw new RuntimeException ("Already initialized, cannot add new method: " + method); 266 } 267 else { 268 NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method)); 269 addMethod(newMethod,false); 270 addNewInstanceMethod(newMethod); 271 } 272 } 273 274 protected void addNewInstanceMethod(MetaMethod method) { 275 newGroovyMethodsList.add(method); 276 } 277 278 protected void addNewStaticMethod(Method method) { 279 if (initialised) { 280 throw new RuntimeException ("Already initialized, cannot add new method: " + method); 281 } 282 else { 283 NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method)); 284 addMethod(newMethod,false); 285 addNewStaticMethod(newMethod); 286 } 287 } 288 289 protected void addNewStaticMethod(MetaMethod method) { 290 newGroovyMethodsList.add(method); 291 } 292 293 public Object invokeMethod(Object object, String methodName, Object arguments) { 294 return invokeMethod(object, methodName, asArray(arguments)); 295 } 296 297 301 public Object invokeMethod(Object object, String methodName, Object [] arguments) { 302 if (object == null) { 303 throw new NullPointerException ("Cannot invoke method: " + methodName + " on null object"); 304 } 305 306 MetaMethod method = retrieveMethod(object, methodName, arguments); 307 308 if (method != null) { 309 return doMethodInvoke(object, method, arguments); 310 } else { 311 try { 313 Object value = this.getProperty(object, methodName); 314 if (value instanceof Closure && object!=this) { 315 Closure closure = (Closure) value; 316 closure.setDelegate(this); 317 return closure.call(arguments); 318 } 319 else { 320 throw new MissingMethodException(methodName, theClass, arguments); 321 } 322 } 323 catch (Exception e) { 324 throw new MissingMethodException(methodName, theClass, arguments); 325 } 326 } 327 } 328 329 protected MetaMethod retrieveMethod(Object owner, String methodName, Object [] arguments) { 330 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments); 332 MetaMethod method = (MetaMethod) methodCache.get(methodKey); 333 if (method == null) { 334 method = pickMethod(owner, methodName, arguments); 335 if (method != null && method.isCacheable()) { 336 methodCache.put(methodKey.createCopy(), method); 337 } 338 } 339 return method; 340 } 341 342 public MetaMethod retrieveMethod(String methodName, Class [] arguments) { 343 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments); 345 MetaMethod method = (MetaMethod) methodCache.get(methodKey); 346 if (method == null) { 347 method = pickMethod(methodName, arguments); if (method != null && method.isCacheable()) { 349 methodCache.put(methodKey.createCopy(), method); 350 } 351 } 352 return method; 353 } 354 355 public Constructor retrieveConstructor(Class [] arguments) { 356 Constructor constructor = (Constructor ) chooseMethod("<init>", constructors, arguments, false); 357 if (constructor != null) { 358 return constructor; 359 } 360 else { 361 constructor = (Constructor ) chooseMethod("<init>", constructors, arguments, true); 362 if (constructor != null) { 363 return constructor; 364 } 365 } 366 return null; 367 } 368 369 public MetaMethod retrieveStaticMethod(String methodName, Class [] arguments) { 370 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments); 371 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey); 372 if (method == null) { 373 method = pickStaticMethod(methodName, arguments); 374 if (method != null) { 375 staticMethodCache.put(methodKey.createCopy(), method); 376 } 377 } 378 return method; 379 } 380 383 protected MetaMethod pickMethod(Object object, String methodName, Object [] arguments) { 384 MetaMethod method = null; 385 List methods = getMethods(methodName); 386 if (!methods.isEmpty()) { 387 Class [] argClasses = convertToTypeArray(arguments); 388 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true); 389 if (method == null) { 390 int size = (arguments != null) ? arguments.length : 0; 391 if (size == 1) { 392 Object firstArgument = arguments[0]; 393 if (firstArgument instanceof List) { 394 398 List list = (List) firstArgument; 399 arguments = list.toArray(); 400 argClasses = convertToTypeArray(arguments); 401 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true); 402 if (method==null) return null; 403 return new TransformMetaMethod(method) { 404 public Object invoke(Object object, Object [] arguments) throws Exception { 405 Object firstArgument = arguments[0]; 406 List list = (List) firstArgument; 407 arguments = list.toArray(); 408 return super.invoke(object, arguments); 409 } 410 }; 411 } 412 } 413 } 414 } 415 return method; 416 } 417 418 425 protected MetaMethod pickMethod(String methodName, Class [] arguments) { 426 MetaMethod method = null; 427 List methods = getMethods(methodName); 428 if (!methods.isEmpty()) { 429 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false); 430 } 435 return method; 436 } 437 438 public Object invokeStaticMethod(Object object, String methodName, Object [] arguments) { 439 444 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments); 446 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey); 447 if (method == null) { 448 method = pickStaticMethod(object, methodName, arguments); 449 if (method != null) { 450 staticMethodCache.put(methodKey.createCopy(), method); 451 } 452 } 453 454 if (method != null) { 455 return doMethodInvoke(object, method, arguments); 456 } 457 476 throw new MissingMethodException(methodName, theClass, arguments); 477 } 478 479 protected MetaMethod pickStaticMethod(Object object, String methodName, Object [] arguments) { 480 MetaMethod method = null; 481 List methods = getStaticMethods(methodName); 482 483 if (!methods.isEmpty()) { 484 method = (MetaMethod) chooseMethod(methodName, methods, convertToTypeArray(arguments), false); 485 } 486 487 if (method == null && theClass != Class .class) { 488 MetaClass classMetaClass = registry.getMetaClass(Class .class); 489 method = classMetaClass.pickMethod(object, methodName, arguments); 490 } 491 return method; 492 } 493 494 protected MetaMethod pickStaticMethod(String methodName, Class [] arguments) { 495 MetaMethod method = null; 496 List methods = getStaticMethods(methodName); 497 498 if (!methods.isEmpty()) { 499 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false); 500 } 505 506 if (method == null && theClass != Class .class) { 507 MetaClass classMetaClass = registry.getMetaClass(Class .class); 508 method = classMetaClass.pickMethod(methodName, arguments); 509 } 510 return method; 511 } 512 513 public Object invokeConstructor(Object [] arguments) { 514 Class [] argClasses = convertToTypeArray(arguments); 515 Constructor constructor = (Constructor ) chooseMethod("<init>", constructors, argClasses, false); 516 if (constructor != null) { 517 return doConstructorInvoke(constructor, arguments); 518 } 519 else { 520 constructor = (Constructor ) chooseMethod("<init>", constructors, argClasses, true); 521 if (constructor != null) { 522 return doConstructorInvoke(constructor, arguments); 523 } 524 } 525 526 if (arguments.length == 1) { 527 Object firstArgument = arguments[0]; 528 if (firstArgument instanceof Map) { 529 constructor = (Constructor ) chooseMethod("<init>", constructors, EMPTY_TYPE_ARRAY, false); 530 if (constructor != null) { 531 Object bean = doConstructorInvoke(constructor, EMPTY_ARRAY); 532 setProperties(bean, ((Map) firstArgument)); 533 return bean; 534 } 535 } 536 } 537 throw new GroovyRuntimeException( 538 "Could not find matching constructor for: " 539 + theClass.getName() 540 + "("+InvokerHelper.toTypeString(arguments)+")"); 541 } 542 543 548 public void setProperties(Object bean, Map map) { 549 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { 550 Map.Entry entry = (Map.Entry) iter.next(); 551 String key = entry.getKey().toString(); 552 553 if(propertyMap.get(key) == null) 555 continue; 556 557 Object value = entry.getValue(); 558 try { 559 setProperty(bean, key, value); 560 } 561 catch (GroovyRuntimeException e) { 562 566 } 567 } 568 } 569 570 573 public Object getProperty(final Object object, final String property) { 574 MetaProperty mp = (MetaProperty) propertyMap.get(property); 576 if(mp != null) { 577 try { 578 return mp.getProperty(object); 582 } 583 catch(Exception e) { 584 throw new GroovyRuntimeException("Cannot read property: " + property); 585 } 586 } 587 588 if (genericGetMethod == null) { 589 List possibleGenericMethods = getMethods("get"); 591 if (possibleGenericMethods != null) { 592 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) { 593 MetaMethod mmethod = (MetaMethod) i.next(); 594 Class [] paramTypes = mmethod.getParameterTypes(); 595 if (paramTypes.length == 1 && paramTypes[0] == String .class) { 596 Object [] arguments = {property}; 597 Object answer = doMethodInvoke(object, mmethod, arguments); 598 return answer; 599 } 600 } 601 } 602 } 603 else { 604 Object [] arguments = { property }; 605 Object answer = doMethodInvoke(object, genericGetMethod, arguments); 606 if (answer != null) { 608 return answer; 609 } 610 } 611 612 if (!CompilerConfiguration.isJsrGroovy()) { 613 List methods = getMethods(property); 616 if (!methods.isEmpty()) { 617 return new MethodClosure(object, property); 618 } 619 } 620 621 Exception lastException = null; 624 try { 625 MetaMethod method = findGetter(object, "get" + capitalize(property)); 626 if (method != null) { 627 return doMethodInvoke(object, method, EMPTY_ARRAY); 628 } 629 } 630 catch (GroovyRuntimeException e) { 631 lastException = e; 632 } 633 634 635 if (genericGetMethod != null) { 636 return null; 637 } 638 else { 639 640 if (object instanceof Class ) { 641 return getStaticProperty((Class ) object, property); 643 } 644 if (object instanceof Collection) { 645 return DefaultGroovyMethods.getAt((Collection) object, property); 646 } 647 if (object instanceof Object []) { 648 return DefaultGroovyMethods.getAt(Arrays.asList((Object []) object), property); 649 } 650 if (object instanceof Object ) { 651 Field field = null; 652 try { 653 field = object.getClass().getDeclaredField(property); 655 return field.get(object); 656 } catch (IllegalAccessException iae) { 657 lastException = new IllegalPropertyAccessException(field,object.getClass()); 658 } catch (Exception e1) { 659 } 661 } 662 663 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property); 664 if (addListenerMethod != null) { 665 666 return null; 667 } 668 669 if (lastException == null) 670 throw new MissingPropertyException(property, theClass); 671 else 672 throw new MissingPropertyException(property, theClass, lastException); 673 } 674 } 675 676 680 public List getProperties() { 681 return new ArrayList(propertyMap.values()); 683 } 684 685 689 protected void setupProperties(PropertyDescriptor [] propertyDescriptors) { 690 MetaProperty mp; 691 Method method; 692 MetaMethod getter = null; 693 MetaMethod setter = null; 694 Class klass; 695 696 klass = theClass; 698 while(klass != null) { 699 Field [] fields = klass.getDeclaredFields(); 700 for(int i = 0; i < fields.length; i++) { 701 if((fields[i].getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0) 703 continue; 704 705 if(propertyMap.get(fields[i].getName()) != null) 707 continue; 708 709 propertyMap.put(fields[i].getName(), new MetaFieldProperty(fields[i])); 713 } 714 715 klass = klass.getSuperclass(); 717 } 718 719 if(theClass.isArray()) { 721 propertyMap.put("length", arrayLengthProperty); 722 } 723 724 for(int i=0; i<propertyDescriptors.length; i++) { 727 PropertyDescriptor pd = propertyDescriptors[i]; 728 if(propertyMap.get(pd.getName()) != null) 730 continue; 731 732 if(pd.getPropertyType() == null) 736 continue; 737 738 method = pd.getReadMethod(); 740 if(method != null) 741 getter = findMethod(method); 742 else 743 getter = null; 744 745 method = pd.getWriteMethod(); 747 if(method != null) 748 setter = findMethod(method); 749 else 750 setter = null; 751 752 756 mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter); 757 758 propertyMap.put(pd.getName(), mp); 760 } 761 762 klass = theClass; 764 while(klass != null) { 765 Method [] methods = klass.getDeclaredMethods(); 766 for (int i = 0; i < methods.length; i++) { 767 if(Modifier.isPublic(methods[i].getModifiers()) == false) 769 continue; 770 771 method = methods[i]; 772 773 String methodName = method.getName(); 774 775 if(methodName.startsWith("get") && 777 methodName.length() > 3 && 778 method.getParameterTypes().length == 0) { 779 780 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4); 782 783 mp = (MetaProperty) propertyMap.get(propName); 785 if(mp != null) { 786 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getGetter() == null) { 788 ((MetaBeanProperty) mp).setGetter(findMethod(method)); 790 } 791 } 792 else { 793 MetaBeanProperty mbp = new MetaBeanProperty(propName, 796 method.getReturnType(), 797 findMethod(method), null); 798 799 propertyMap.put(propName, mbp); 801 } 802 } 803 else if(methodName.startsWith("set") && 804 methodName.length() > 3 && 805 method.getParameterTypes().length == 1) { 806 807 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4); 809 810 mp = (MetaProperty) propertyMap.get(propName); 812 if(mp != null) { 813 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getSetter() == null) { 814 ((MetaBeanProperty) mp).setSetter(findMethod(method)); 816 } 817 } 818 else { 819 MetaBeanProperty mbp = new MetaBeanProperty(propName, 821 method.getParameterTypes()[0], 822 null, 823 findMethod(method)); 824 825 propertyMap.put(propName, mbp); 827 } 828 } 829 } 830 831 klass = klass.getSuperclass(); 833 } 834 } 835 836 839 public void setProperty(Object object, String property, Object newValue) { 840 MetaProperty mp = (MetaProperty) propertyMap.get(property); 841 if(mp != null) { 842 try { 843 mp.setProperty(object, newValue); 844 return; 845 } 846 catch(ReadOnlyPropertyException e) { 847 throw e; 849 } 850 catch (TypeMismatchException e) { 851 throw e; 853 } 854 catch (Exception e) { 855 if (newValue == null) 858 return; 859 if (newValue instanceof List) { 860 List list = (List) newValue; 861 int params = list.size(); 862 Constructor [] constructors = mp.getType().getConstructors(); 863 for (int i = 0; i < constructors.length; i++) { 864 Constructor constructor = constructors[i]; 865 if (constructor.getParameterTypes().length == params) { 866 Object value = doConstructorInvoke(constructor, list.toArray()); 867 mp.setProperty(object, value); 868 return; 869 } 870 } 871 872 Class parameterType = mp.getType(); 874 if (parameterType.isArray()) { 875 Object objArray = asPrimitiveArray(list, parameterType); 876 mp.setProperty(object, objArray); 877 return; 878 } 879 } 880 881 if (newValue.getClass().isArray() && mp instanceof MetaBeanProperty) { 886 MetaBeanProperty mbp = (MetaBeanProperty) mp; 887 List list = Arrays.asList((Object [])newValue); 888 MetaMethod setter = mbp.getSetter(); 889 890 Class parameterType = setter.getParameterTypes()[0]; 891 Class arrayType = parameterType.getComponentType(); 892 Object objArray = Array.newInstance(arrayType, list.size()); 893 894 for (int i = 0; i < list.size(); i++) { 895 List list2 =Arrays.asList((Object []) list.get(i)); 896 Object objArray2 = asPrimitiveArray(list2, arrayType); 897 Array.set(objArray, i, objArray2); 898 } 899 900 doMethodInvoke(object, setter, new Object []{ 901 objArray 902 }); 903 return; 904 } 905 906 throw new MissingPropertyException(property, theClass, e); 907 } 908 } 909 910 try { 911 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property); 912 if (addListenerMethod != null && newValue instanceof Closure) { 913 Object proxy = 915 createListenerProxy(addListenerMethod.getParameterTypes()[0], property, (Closure) newValue); 916 doMethodInvoke(object, addListenerMethod, new Object [] { proxy }); 917 return; 918 } 919 920 if (genericSetMethod == null) { 921 List possibleGenericMethods = getMethods("set"); 923 if (possibleGenericMethods != null) { 924 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) { 925 MetaMethod mmethod = (MetaMethod) i.next(); 926 Class [] paramTypes = mmethod.getParameterTypes(); 927 if (paramTypes.length == 2 && paramTypes[0] == String .class) { 928 Object [] arguments = {property, newValue}; 929 Object answer = doMethodInvoke(object, mmethod, arguments); 930 return; 931 } 932 } 933 } 934 } 935 else { 936 Object [] arguments = { property, newValue }; 937 doMethodInvoke(object, genericSetMethod, arguments); 938 return; 939 } 940 941 942 943 948 String method = "set" + capitalize(property); 949 try { 950 invokeMethod(object, method, new Object [] { newValue }); 951 } 952 catch (MissingMethodException e1) { 953 Field field = null; 954 try { 955 field = object.getClass().getDeclaredField(property); 956 field.set(object, newValue); 958 } catch (IllegalAccessException iae) { 959 throw new IllegalPropertyAccessException(field,object.getClass()); 960 } catch (Exception e2) { 961 throw new MissingPropertyException(property, theClass, e2); 962 } 963 } 964 965 } 966 catch (GroovyRuntimeException e) { 967 throw new MissingPropertyException(property, theClass, e); 968 } 969 970 } 971 972 973 976 public Object getAttribute(Object object, String attribute) { 977 try { 978 Field field = theClass.getDeclaredField(attribute); 979 field.setAccessible(true); 980 return field.get(object); 981 } 982 catch (NoSuchFieldException e) { 983 throw new MissingFieldException(attribute, theClass); 984 } 985 catch (IllegalAccessException e) { 986 throw new MissingFieldException(attribute, theClass, e); 987 } 988 } 989 990 993 public void setAttribute(Object object, String attribute, Object newValue) { 994 try { 995 Field field = theClass.getDeclaredField(attribute); 996 field.setAccessible(true); 997 field.set(object, newValue); 998 } 999 catch (NoSuchFieldException e) { 1000 throw new MissingFieldException(attribute, theClass); 1001 } 1002 catch (IllegalAccessException e) { 1003 throw new MissingFieldException(attribute, theClass, e); 1004 } 1005 } 1006 1007 1012 public Closure getMethodPointer(Object object, String methodName) { 1013 return new MethodClosure(object, methodName); 1014 } 1015 1016 1021 private Object asPrimitiveArray(List list, Class parameterType) { 1022 Class arrayType = parameterType.getComponentType(); 1023 Object objArray = Array.newInstance(arrayType, list.size()); 1024 for (int i = 0; i < list.size(); i++) { 1025 Object obj = list.get(i); 1026 if (arrayType.isPrimitive()) { 1027 if (obj instanceof Integer ) { 1028 Array.setInt(objArray, i, ((Integer ) obj).intValue()); 1029 } 1030 else if (obj instanceof Double ) { 1031 Array.setDouble(objArray, i, ((Double ) obj).doubleValue()); 1032 } 1033 else if (obj instanceof Boolean ) { 1034 Array.setBoolean(objArray, i, ((Boolean ) obj).booleanValue()); 1035 } 1036 else if (obj instanceof Long ) { 1037 Array.setLong(objArray, i, ((Long ) obj).longValue()); 1038 } 1039 else if (obj instanceof Float ) { 1040 Array.setFloat(objArray, i, ((Float ) obj).floatValue()); 1041 } 1042 else if (obj instanceof Character ) { 1043 Array.setChar(objArray, i, ((Character ) obj).charValue()); 1044 } 1045 else if (obj instanceof Byte ) { 1046 Array.setByte(objArray, i, ((Byte ) obj).byteValue()); 1047 } 1048 else if (obj instanceof Short ) { 1049 Array.setShort(objArray, i, ((Short ) obj).shortValue()); 1050 } 1051 } 1052 else { 1053 Array.set(objArray, i, obj); 1054 } 1055 } 1056 return objArray; 1057 } 1058 1059 public ClassNode getClassNode() { 1060 if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) { 1061 String className = theClass.getName(); 1063 String groovyFile = className; 1064 int idx = groovyFile.indexOf('$'); 1065 if (idx > 0) { 1066 groovyFile = groovyFile.substring(0, idx); 1067 } 1068 groovyFile = groovyFile.replace('.', '/') + ".groovy"; 1069 1070 URL url = theClass.getClassLoader().getResource(groovyFile); 1072 if (url == null) { 1073 url = Thread.currentThread().getContextClassLoader().getResource(groovyFile); 1074 } 1075 if (url != null) { 1076 try { 1077 1078 1083 1084 CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() { 1085 public void call( ClassVisitor writer, ClassNode node ) { 1086 if( node.getName().equals(theClass.getName()) ) { 1087 MetaClass.this.classNode = node; 1088 } 1089 } 1090 }; 1091 1092 1093 CompilationUnit unit = new CompilationUnit( getClass().getClassLoader() ); 1094 unit.setClassgenCallback( search ); 1095 unit.addSource( url ); 1096 unit.compile( Phases.CLASS_GENERATION ); 1097 } 1098 catch (Exception e) { 1099 throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e); 1100 } 1101 } 1102 1103 } 1104 return classNode; 1105 } 1106 1107 public String toString() { 1108 return super.toString() + "[" + theClass + "]"; 1109 } 1110 1111 1114 1118 protected Object [] asArray(Object arguments) { 1119 if (arguments == null) { 1120 return EMPTY_ARRAY; 1121 } 1122 if (arguments instanceof Tuple) { 1123 Tuple tuple = (Tuple) arguments; 1124 return tuple.toArray(); 1125 } 1126 if (arguments instanceof Object []) { 1127 return (Object []) arguments; 1128 } 1129 else { 1130 return new Object [] { arguments }; 1131 } 1132 } 1133 1134 1146 protected Object createListenerProxy(Class listenerType, final String listenerMethodName, final Closure closure) { 1147 InvocationHandler handler = new ClosureListener(listenerMethodName, closure); 1148 return Proxy.newProxyInstance(listenerType.getClassLoader(), new Class [] { listenerType }, handler); 1149 } 1150 1151 1157 protected void addMethods(Class theClass, boolean forceOverwrite) { 1158 Method [] methodArray = theClass.getDeclaredMethods(); 1160 for (int i = 0; i < methodArray.length; i++) { 1161 Method reflectionMethod = methodArray[i]; 1162 if ( reflectionMethod.getName().indexOf('+') >= 0 ) { 1163 continue; 1164 } 1165 MetaMethod method = createMetaMethod(reflectionMethod); 1166 addMethod(method,forceOverwrite); 1167 } 1168 } 1169 1170 protected void addMethod(MetaMethod method, boolean forceOverwrite) { 1171 String name = method.getName(); 1172 1173 1175 if (isGenericGetMethod(method) && genericGetMethod == null) { 1176 genericGetMethod = method; 1177 } 1178 else if (isGenericSetMethod(method) && genericSetMethod == null) { 1179 genericSetMethod = method; 1180 } 1181 if (method.isStatic()) { 1182 List list = (List) staticMethodIndex.get(name); 1183 if (list == null) { 1184 list = new ArrayList(); 1185 staticMethodIndex.put(name, list); 1186 list.add(method); 1187 } 1188 else { 1189 if (!containsMatchingMethod(list, method)) { 1190 list.add(method); 1191 } 1192 } 1193 } 1194 1195 List list = (List) methodIndex.get(name); 1196 if (list == null) { 1197 list = new ArrayList(); 1198 methodIndex.put(name, list); 1199 list.add(method); 1200 } 1201 else { 1202 if (forceOverwrite) { 1203 removeMatchingMethod(list,method); 1204 list.add(method); 1205 } else if (!containsMatchingMethod(list, method)) { 1206 list.add(method); 1207 } 1208 } 1209 } 1210 1211 1215 protected boolean containsMatchingMethod(List list, MetaMethod method) { 1216 for (Iterator iter = list.iterator(); iter.hasNext();) { 1217 MetaMethod aMethod = (MetaMethod) iter.next(); 1218 Class [] params1 = aMethod.getParameterTypes(); 1219 Class [] params2 = method.getParameterTypes(); 1220 if (params1.length == params2.length) { 1221 boolean matches = true; 1222 for (int i = 0; i < params1.length; i++) { 1223 if (params1[i] != params2[i]) { 1224 matches = false; 1225 break; 1226 } 1227 } 1228 if (matches) { 1229 return true; 1230 } 1231 } 1232 } 1233 return false; 1234 } 1235 1236 1239 protected void removeMatchingMethod(List list, MetaMethod method) { 1240 for (Iterator iter = list.iterator(); iter.hasNext();) { 1241 MetaMethod aMethod = (MetaMethod) iter.next(); 1242 Class [] params1 = aMethod.getParameterTypes(); 1243 Class [] params2 = method.getParameterTypes(); 1244 if (params1.length == params2.length) { 1245 boolean matches = true; 1246 for (int i = 0; i < params1.length; i++) { 1247 if (params1[i] != params2[i]) { 1248 matches = false; 1249 break; 1250 } 1251 } 1252 if (matches) { 1253 iter.remove(); 1254 return; 1255 } 1256 } 1257 } 1258 return; 1259 } 1260 1261 1262 1268 protected void addNewStaticMethodsFrom(Class theClass) { 1269 MetaClass interfaceMetaClass = registry.getMetaClass(theClass); 1270 Iterator iter = interfaceMetaClass.newGroovyMethodsList.iterator(); 1271 while (iter.hasNext()) { 1272 MetaMethod method = (MetaMethod) iter.next(); 1273 addMethod(method,false); 1274 newGroovyMethodsList.add(method); 1275 } 1276 } 1277 1278 1281 protected Object getStaticProperty(Class aClass, String property) { 1282 1285 Exception lastException = null; 1286 try { 1287 Field field = aClass.getField(property); 1288 if (field != null) { 1289 if ((field.getModifiers() & Modifier.STATIC) != 0) { 1290 return field.get(null); 1291 } 1292 } 1293 } 1294 catch (Exception e) { 1295 lastException = e; 1296 } 1297 1298 try { 1300 MetaMethod method = findStaticGetter(aClass, "get" + capitalize(property)); 1301 if (method != null) { 1302 return doMethodInvoke(aClass, method, EMPTY_ARRAY); 1303 } 1304 } 1305 catch (GroovyRuntimeException e) { 1306 throw new MissingPropertyException(property, aClass, e); 1307 } 1308 1309 if (lastException == null) { 1310 throw new MissingPropertyException(property, aClass); 1311 } 1312 else { 1313 throw new MissingPropertyException(property, aClass, lastException); 1314 } 1315 } 1316 1317 1320 protected MetaMethod findMethod(Method aMethod) { 1321 List methods = getMethods(aMethod.getName()); 1322 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1323 MetaMethod method = (MetaMethod) iter.next(); 1324 if (method.isMethod(aMethod)) { 1325 return method; 1326 } 1327 } 1328 return new ReflectionMetaMethod(aMethod); 1330 } 1331 1332 1335 protected MetaMethod findGetter(Object object, String name) { 1336 List methods = getMethods(name); 1337 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1338 MetaMethod method = (MetaMethod) iter.next(); 1339 if (method.getParameterTypes().length == 0) { 1340 return method; 1341 } 1342 } 1343 return null; 1344 } 1345 1346 1349 protected MetaMethod findStaticGetter(Class type, String name) { 1350 List methods = getStaticMethods(name); 1351 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1352 MetaMethod method = (MetaMethod) iter.next(); 1353 if (method.getParameterTypes().length == 0) { 1354 return method; 1355 } 1356 } 1357 1358 1359 try { 1360 Method method = type.getMethod(name, EMPTY_TYPE_ARRAY); 1361 if ((method.getModifiers() & Modifier.STATIC) != 0) { 1362 return findMethod(method); 1363 } 1364 else { 1365 return null; 1366 } 1367 } 1368 catch (Exception e) { 1369 return null; 1370 } 1371 } 1372 1373 protected Object doMethodInvoke(Object object, MetaMethod method, Object [] argumentArray) { 1374 1379 try { 1380 if (argumentArray == null) { 1381 argumentArray = EMPTY_ARRAY; 1382 } 1383 else if (method.getParameterTypes().length == 1 && argumentArray.length == 0) { 1384 argumentArray = ARRAY_WITH_NULL; 1385 } 1386 return method.invoke(object, argumentArray); 1387 } 1388 catch (ClassCastException e) { 1389 if (coerceGStrings(argumentArray)) { 1390 try { 1391 return doMethodInvoke(object, method, argumentArray); 1392 } 1393 catch (Exception e2) { 1394 } 1396 } 1397 throw new GroovyRuntimeException( 1398 "failed to invoke method: " 1399 + method 1400 + " on: " 1401 + object 1402 + " with arguments: " 1403 + InvokerHelper.toString(argumentArray) 1404 + " reason: " 1405 + e, 1406 e); 1407 } 1408 catch (InvocationTargetException e) { 1409 1418 throw new InvokerInvocationException(e); 1419 } 1420 catch (IllegalAccessException e) { 1421 throw new GroovyRuntimeException( 1422 "could not access method: " 1423 + method 1424 + " on: " 1425 + object 1426 + " with arguments: " 1427 + InvokerHelper.toString(argumentArray) 1428 + " reason: " 1429 + e, 1430 e); 1431 } 1432 catch (IllegalArgumentException e) { 1433 if (coerceGStrings(argumentArray)) { 1434 try { 1435 return doMethodInvoke(object, method, argumentArray); 1436 } 1437 catch (Exception e2) { 1438 } 1440 } 1441 Object [] args = coerceNumbers(method, argumentArray); 1442 if (args != null && !Arrays.equals(argumentArray,args)) { 1443 try { 1444 return doMethodInvoke(object, method, args); 1445 } 1446 catch (Exception e3) { 1447 } 1449 } 1450 throw new GroovyRuntimeException( 1451 "failed to invoke method: " 1452 + method 1453 + " on: " 1454 + object 1455 + " with arguments: " 1456 + InvokerHelper.toString(argumentArray) 1457 + "reason: " 1458 + e 1459 ); 1460 } 1461 catch (RuntimeException e) { 1462 throw e; 1463 } 1464 catch (Exception e) { 1465 throw new GroovyRuntimeException( 1466 "failed to invoke method: " 1467 + method 1468 + " on: " 1469 + object 1470 + " with arguments: " 1471 + InvokerHelper.toString(argumentArray) 1472 + " reason: " 1473 + e, 1474 e); 1475 } 1476 } 1477 1478 private static Object [] coerceNumbers(MetaMethod method, Object [] arguments) { 1479 Object [] ans = null; 1480 boolean coerced = false; 1482 Class [] params = method.getParameterTypes(); 1483 1484 if (params.length != arguments.length) { 1485 return null; 1486 } 1487 1488 ans = new Object [arguments.length]; 1489 1490 for (int i = 0, size = arguments.length; i < size; i++) { 1491 Object argument = arguments[i]; 1492 Class param = params[i]; 1493 if ((Number .class.isAssignableFrom(param) || param.isPrimitive()) && argument instanceof Number ) { if (param == Byte .class || param == Byte.TYPE ) { 1495 ans[i] = new Byte (((Number )argument).byteValue()); 1496 coerced = true; continue; 1497 } 1498 if (param == Double .class || param == Double.TYPE) { 1499 ans[i] = new Double (((Number )argument).doubleValue()); 1500 coerced = true; continue; 1501 } 1502 if (param == Float .class || param == Float.TYPE) { 1503 ans[i] = new Float (((Number )argument).floatValue()); 1504 coerced = true; continue; 1505 } 1506 if (param == Integer .class || param == Integer.TYPE) { 1507 ans[i] = new Integer (((Number )argument).intValue()); 1508 coerced = true; continue; 1509 } 1510 if (param == Long .class || param == Long.TYPE) { 1511 ans[i] = new Long (((Number )argument).longValue()); 1512 coerced = true; continue; 1513 } 1514 if (param == Short .class || param == Short.TYPE) { 1515 ans[i] = new Short (((Number )argument).shortValue()); 1516 coerced = true; continue; 1517 } 1518 if (param == BigDecimal .class ) { 1519 ans[i] = new BigDecimal (((Number )argument).doubleValue()); 1520 coerced = true; continue; 1521 } 1522 if (param == BigInteger .class) { 1523 ans[i] = new BigInteger (String.valueOf(((Number )argument).longValue())); 1524 coerced = true; continue; 1525 } 1526 } 1527 else if (param.isArray() && argument.getClass().isArray()) { 1528 Class paramElem = param.getComponentType(); 1529 if (paramElem.isPrimitive()) { 1530 if (paramElem == boolean.class && argument.getClass().getName().equals("[Ljava.lang.Boolean;")) { 1531 ans[i] = InvokerHelper.convertToBooleanArray(argument); 1532 coerced = true; 1533 continue; 1534 } 1535 if (paramElem == byte.class && argument.getClass().getName().equals("[Ljava.lang.Byte;")) { 1536 ans[i] = InvokerHelper.convertToByteArray(argument); 1537 coerced = true; 1538 continue; 1539 } 1540 if (paramElem == char.class && argument.getClass().getName().equals("[Ljava.lang.Character;")) { 1541 ans[i] = InvokerHelper.convertToCharArray(argument); 1542 coerced = true; 1543 continue; 1544 } 1545 if (paramElem == short.class && argument.getClass().getName().equals("[Ljava.lang.Short;")) { 1546 ans[i] = InvokerHelper.convertToShortArray(argument); 1547 coerced = true; 1548 continue; 1549 } 1550 if (paramElem == int.class && argument.getClass().getName().equals("[Ljava.lang.Integer;")) { 1551 ans[i] = InvokerHelper.convertToIntArray(argument); 1552 coerced = true; 1553 continue; 1554 } 1555 if (paramElem == long.class 1556 && argument.getClass().getName().equals("[Ljava.lang.Long;") 1557 && argument.getClass().getName().equals("[Ljava.lang.Integer;") 1558 ) { 1559 ans[i] = InvokerHelper.convertToLongArray(argument); 1560 coerced = true; 1561 continue; 1562 } 1563 if (paramElem == float.class 1564 && argument.getClass().getName().equals("[Ljava.lang.Float;") 1565 && argument.getClass().getName().equals("[Ljava.lang.Integer;") 1566 ) { 1567 ans[i] = InvokerHelper.convertToFloatArray(argument); 1568 coerced = true; 1569 continue; 1570 } 1571 if (paramElem == double.class && 1572 argument.getClass().getName().equals("[Ljava.lang.Double;") && 1573 argument.getClass().getName().equals("[Ljava.lang.BigDecimal;") && 1574 argument.getClass().getName().equals("[Ljava.lang.Float;")) { 1575 ans[i] = InvokerHelper.convertToDoubleArray(argument); 1576 coerced = true; 1577 continue; 1578 } 1579 } 1580 } 1581 } 1582 return coerced ? ans : null; 1583 } 1584 1585 protected Object doConstructorInvoke(Constructor constructor, Object [] argumentArray) { 1586 1590 try { 1591 1601 1603 return constructor.newInstance(argumentArray); 1604 } 1605 catch (InvocationTargetException e) { 1606 1615 throw new InvokerInvocationException(e); 1616 } 1617 catch (IllegalArgumentException e) { 1618 if (coerceGStrings(argumentArray)) { 1619 try { 1620 return constructor.newInstance(argumentArray); 1621 } 1622 catch (Exception e2) { 1623 } 1625 } 1626 throw new GroovyRuntimeException( 1627 "failed to invoke constructor: " 1628 + constructor 1629 + " with arguments: " 1630 + InvokerHelper.toString(argumentArray) 1631 + " reason: " 1632 + e); 1633 } 1634 catch (IllegalAccessException e) { 1635 throw new GroovyRuntimeException( 1636 "could not access constructor: " 1637 + constructor 1638 + " with arguments: " 1639 + InvokerHelper.toString(argumentArray) 1640 + " reason: " 1641 + e); 1642 } 1643 catch (Exception e) { 1644 throw new GroovyRuntimeException( 1645 "failed to invoke constructor: " 1646 + constructor 1647 + " with arguments: " 1648 + InvokerHelper.toString(argumentArray) 1649 + " reason: " 1650 + e, 1651 e); 1652 } 1653 } 1654 1655 1665 protected Object chooseMethod(String methodName, List methods, Class [] arguments, boolean coerce) { 1666 int methodCount = methods.size(); 1667 if (methodCount <= 0) { 1668 return null; 1669 } 1670 else if (methodCount == 1) { 1671 Object method = methods.get(0); 1672 if (isValidMethod(method, arguments, coerce)) { 1673 return method; 1674 } 1675 return null; 1676 } 1677 Object answer = null; 1678 if (arguments == null || arguments.length == 0) { 1679 answer = chooseEmptyMethodParams(methods); 1680 } 1681 else if (arguments.length == 1 && arguments[0] == null) { 1682 answer = chooseMostGeneralMethodWith1NullParam(methods); 1683 } 1684 else { 1685 List matchingMethods = new ArrayList(); 1686 1687 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1688 Object method = iter.next(); 1689 Class [] paramTypes; 1690 1691 if (isValidMethod(method, arguments, coerce)) { 1693 matchingMethods.add(method); 1694 } 1695 } 1696 if (matchingMethods.isEmpty()) { 1697 return null; 1698 } 1699 else if (matchingMethods.size() == 1) { 1700 return matchingMethods.get(0); 1701 } 1702 return chooseMostSpecificParams(methodName, matchingMethods, arguments); 1703 1704 } 1705 if (answer != null) { 1706 return answer; 1707 } 1708 throw new GroovyRuntimeException( 1709 "Could not find which method to invoke from this list: " 1710 + methods 1711 + " for arguments: " 1712 + InvokerHelper.toString(arguments)); 1713 } 1714 1715 protected boolean isValidMethod(Object method, Class [] arguments, boolean includeCoerce) { 1716 Class [] paramTypes = getParameterTypes(method); 1717 return isValidMethod(paramTypes, arguments, includeCoerce); 1718 } 1719 1720 public static boolean isValidMethod(Class [] paramTypes, Class [] arguments, boolean includeCoerce) { 1721 if (arguments == null) { 1722 return true; 1723 } 1724 int size = arguments.length; 1725 boolean validMethod = false; 1726 if (paramTypes.length == size) { 1727 validMethod = true; 1729 for (int i = 0; i < size; i++) { 1730 if (!isCompatibleClass(paramTypes[i], arguments[i], includeCoerce)) { 1731 validMethod = false; 1732 } 1733 } 1734 } 1735 else { 1736 if (paramTypes.length == 1 && size == 0) { 1737 return true; 1738 } 1739 } 1740 return validMethod; 1741 } 1742 1743 private boolean isSuperclass(Class claszz, Class superclass) { 1744 while (claszz!=null) { 1745 if (claszz==superclass) return true; 1746 claszz = claszz.getSuperclass(); 1747 } 1748 return false; 1749 } 1750 1751 private Class [] wrap(Class [] classes) { 1752 Class [] wrappedArguments = new Class [classes.length]; 1753 for (int i = 0; i < wrappedArguments.length; i++) { 1754 Class c = classes[i]; 1755 if (c==null) continue; 1756 if (c.isPrimitive()) { 1757 if (c==Integer.TYPE) { 1758 c=Integer .class; 1759 } else if (c==Byte.TYPE) { 1760 c=Byte .class; 1761 } else if (c==Long.TYPE) { 1762 c=Long .class; 1763 } else if (c==Double.TYPE) { 1764 c=Double .class; 1765 } else if (c==Float.TYPE) { 1766 c=Float .class; 1767 } 1768 } else if (isSuperclass(c,GString.class)) { 1769 c = String .class; 1770 } 1771 wrappedArguments[i]=c; 1772 } 1773 return wrappedArguments; 1774 } 1775 1776 protected Object chooseMostSpecificParams(String name, List matchingMethods, Class [] arguments) { 1777 1778 Class [] wrappedArguments = wrap(arguments); 1779 LinkedList directMatches = new LinkedList(); 1780 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) { 1782 Object method = iter.next(); 1783 Class [] paramTypes = wrap(getParameterTypes(method)); 1784 if (Arrays.equals(wrappedArguments, paramTypes)) directMatches.add(method); 1785 } 1786 if (directMatches.size()>0) { 1787 matchingMethods = directMatches; 1788 } 1789 if (directMatches.size()>1) { 1790 matchingMethods = directMatches; 1791 directMatches = new LinkedList(); 1794 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) { 1795 Object method = iter.next(); 1796 Class [] paramTypes = getParameterTypes(method); 1797 if (Arrays.equals(arguments, paramTypes)) directMatches.add(method); 1798 } 1799 if (directMatches.size()==1) matchingMethods = directMatches; 1800 } 1801 1802 List superclassMatches = new ArrayList(matchingMethods); 1804 for (Iterator iter = superclassMatches.iterator(); iter.hasNext(); ) { 1805 Object method = iter.next(); 1806 Class [] paramTypes = getParameterTypes(method); 1807 for (int i=0; i<paramTypes.length; i++) { 1808 if (!isSuperclass(arguments[i],paramTypes[i])) { 1809 iter.remove(); 1810 break; } 1812 } 1813 } 1814 if (superclassMatches.size()!=0) { 1815 matchingMethods = superclassMatches; 1817 } 1818 1819 Object answer = null; 1820 int size = arguments.length; 1821 Class [] mostSpecificTypes = null; 1822 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) { 1823 Object method = iter.next(); 1824 Class [] paramTypes = getParameterTypes(method); 1825 if (answer == null) { 1826 answer = method; 1827 mostSpecificTypes = paramTypes; 1828 } 1829 else { 1830 boolean useThisMethod = false; 1831 for (int i = 0; i < size; i++) { 1832 Class mostSpecificType = mostSpecificTypes[i]; 1833 Class type = paramTypes[i]; 1834 1835 if (!isAssignableFrom(mostSpecificType, type)) { 1836 useThisMethod = true; 1837 break; 1838 } 1839 } 1840 if (useThisMethod) { 1841 1842 if (size > 1) { 1843 checkForInvalidOverloading(name, mostSpecificTypes, paramTypes); 1844 } 1845 1846 answer = method; 1847 mostSpecificTypes = paramTypes; 1848 } 1849 } 1850 } 1851 return answer; 1852 } 1853 1854 1864 protected void checkForInvalidOverloading(String name, Class [] baseTypes, Class [] derivedTypes) { 1865 for (int i = 0, size = baseTypes.length; i < size; i++) { 1866 Class baseType = baseTypes[i]; 1867 Class derivedType = derivedTypes[i]; 1868 if (!isAssignableFrom(derivedType, baseType)) { 1869 throw new GroovyRuntimeException( 1870 "Ambiguous method overloading for method: " 1871 + name 1872 + ". Cannot resolve which method to invoke due to overlapping prototypes between: " 1873 + InvokerHelper.toString(baseTypes) 1874 + " and: " 1875 + InvokerHelper.toString(derivedTypes)); 1876 } 1877 } 1878 } 1879 1880 protected Class [] getParameterTypes(Object methodOrConstructor) { 1881 if (methodOrConstructor instanceof MetaMethod) { 1882 MetaMethod method = (MetaMethod) methodOrConstructor; 1883 return method.getParameterTypes(); 1884 } 1885 if (methodOrConstructor instanceof Method ) { 1886 Method method = (Method ) methodOrConstructor; 1887 return method.getParameterTypes(); 1888 } 1889 if (methodOrConstructor instanceof Constructor ) { 1890 Constructor constructor = (Constructor ) methodOrConstructor; 1891 return constructor.getParameterTypes(); 1892 } 1893 throw new IllegalArgumentException ("Must be a Method or Constructor"); 1894 } 1895 1896 1900 protected Object chooseMostGeneralMethodWith1NullParam(List methods) { 1901 Class closestClass = null; 1904 Object answer = null; 1905 1906 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1907 Object method = iter.next(); 1908 Class [] paramTypes = getParameterTypes(method); 1909 int paramLength = paramTypes.length; 1910 if (paramLength == 1) { 1911 Class theType = paramTypes[0]; 1912 if (theType.isPrimitive()) continue; 1913 if (closestClass == null || isAssignableFrom(closestClass, theType)) { 1914 closestClass = theType; 1915 answer = method; 1916 } 1917 } 1918 } 1919 return answer; 1920 } 1921 1922 1926 protected Object chooseEmptyMethodParams(List methods) { 1927 for (Iterator iter = methods.iterator(); iter.hasNext();) { 1928 Object method = iter.next(); 1929 Class [] paramTypes = getParameterTypes(method); 1930 int paramLength = paramTypes.length; 1931 if (paramLength == 0) { 1932 return method; 1933 } 1934 } 1935 return null; 1936 } 1937 1938 protected static boolean isCompatibleInstance(Class type, Object value, boolean includeCoerce) { 1939 boolean answer = value == null || type.isInstance(value); 1940 if (!answer) { 1941 if (type.isPrimitive()) { 1942 if (type == int.class) { 1943 return value instanceof Integer ; 1944 } 1945 else if (type == double.class) { 1946 return value instanceof Double || value instanceof Float || value instanceof Integer || value instanceof BigDecimal ; 1947 } 1948 else if (type == boolean.class) { 1949 return value instanceof Boolean ; 1950 } 1951 else if (type == long.class) { 1952 return value instanceof Long || value instanceof Integer ; 1953 } 1954 else if (type == float.class) { 1955 return value instanceof Float || value instanceof Integer ; 1956 } 1957 else if (type == char.class) { 1958 return value instanceof Character ; 1959 } 1960 else if (type == byte.class) { 1961 return value instanceof Byte ; 1962 } 1963 else if (type == short.class) { 1964 return value instanceof Short ; 1965 } 1966 } 1967 else if(type.isArray() && value.getClass().isArray()) { 1968 return isCompatibleClass(type.getComponentType(), value.getClass().getComponentType(), false); 1969 } 1970 else if (includeCoerce) { 1971 if (type == String .class && value instanceof GString) { 1972 return true; 1973 } 1974 else if (value instanceof Number ) { 1975 return Number .class.isAssignableFrom(type); 1977 } 1978 } 1979 } 1980 return answer; 1981 } 1982 protected static boolean isCompatibleClass(Class type, Class value, boolean includeCoerce) { 1983 boolean answer = value == null || type.isAssignableFrom(value); if (!answer) { 1985 if (type.isPrimitive()) { 1986 if (type == int.class) { 1987 return value == Integer .class; } 1989 else if (type == double.class) { 1990 return value == Double .class || value == Float .class || value == Integer .class || value == BigDecimal .class; 1991 } 1992 else if (type == boolean.class) { 1993 return value == Boolean .class; 1994 } 1995 else if (type == long.class) { 1996 return value == Long .class || value == Integer .class; } 1998 else if (type == float.class) { 1999 return value == Float .class || value == Integer .class; } 2001 else if (type == char.class) { 2002 return value == Character .class; 2003 } 2004 else if (type == byte.class) { 2005 return value == Byte .class; 2006 } 2007 else if (type == short.class) { 2008 return value == Short .class; 2009 } 2010 } 2011 else if(type.isArray() && value.isArray()) { 2012 return isCompatibleClass(type.getComponentType(), value.getComponentType(), false); 2013 } 2014 else if (includeCoerce) { 2015 if (type == String .class && GString.class.isAssignableFrom(value)) { 2017 return true; 2018 } 2019 else if (value == Number .class) { 2020 return Number .class.isAssignableFrom(type); 2022 } 2023 } 2024 } 2025 return answer; 2026 } 2027 2028 protected boolean isAssignableFrom(Class mostSpecificType, Class type) { 2029 if (mostSpecificType.isPrimitive() && type.isPrimitive()) { 2031 if (mostSpecificType == type) { 2032 return true; 2033 } 2034 else { if (type == int.class) { 2036 return 2037 mostSpecificType == int.class 2038 || mostSpecificType == short.class 2039 || mostSpecificType == byte.class; 2040 } 2041 else if (type == double.class) { 2042 return 2043 mostSpecificType == double.class 2044 || mostSpecificType == int.class 2045 || mostSpecificType == long.class 2046 || mostSpecificType == short.class 2047 || mostSpecificType == byte.class 2048 || mostSpecificType == float.class; 2049 } 2050 else if (type == long.class) { 2051 return 2052 mostSpecificType == long.class 2053 || mostSpecificType == int.class 2054 || mostSpecificType == short.class 2055 || mostSpecificType == byte.class; 2056 } 2057 else if (type == float.class) { 2058 return 2059 mostSpecificType == float.class 2060 || mostSpecificType == int.class 2061 || mostSpecificType == long.class 2062 || mostSpecificType == short.class 2063 || mostSpecificType == byte.class; 2064 } 2065 else if (type == short.class) { 2066 return 2067 mostSpecificType == short.class 2068 || mostSpecificType == byte.class; 2069 } 2070 else { 2071 return false; 2072 } 2073 } 2074 } 2075 2076 boolean answer = type.isAssignableFrom(mostSpecificType); 2077 if (!answer) { 2078 answer = autoboxType(type).isAssignableFrom(autoboxType(mostSpecificType)); 2079 } 2080 return answer; 2081 } 2082 2083 private Class autoboxType(Class type) { 2084 if (type.isPrimitive()) { 2085 if (type == int.class) { 2086 return Integer .class; 2087 } 2088 else if (type == double.class) { 2089 return Double .class; 2090 } 2091 else if (type == long.class) { 2092 return Long .class; 2093 } 2094 else if (type == boolean.class) { 2095 return Boolean .class; 2096 } 2097 else if (type == float.class) { 2098 return Float .class; 2099 } 2100 else if (type == char.class) { 2101 return Character .class; 2102 } 2103 else if (type == byte.class) { 2104 return Byte .class; 2105 } 2106 else if (type == short.class) { 2107 return Short .class; 2108 } 2109 } 2110 return type; 2111 } 2112 2113 2118 protected static boolean coerceGStrings(Object [] arguments) { 2119 boolean coerced = false; 2120 for (int i = 0, size = arguments.length; i < size; i++) { 2121 Object argument = arguments[i]; 2122 if (argument instanceof GString) { 2123 arguments[i] = argument.toString(); 2124 coerced = true; 2125 } 2126 } 2127 return coerced; 2128 } 2129 2130 protected boolean isGenericSetMethod(MetaMethod method) { 2131 return (method.getName().equals("set")) 2132 && method.getParameterTypes().length == 2; 2133 } 2134 2135 protected boolean isGenericGetMethod(MetaMethod method) { 2136 if (method.getName().equals("get")) { 2137 Class [] parameterTypes = method.getParameterTypes(); 2138 return parameterTypes.length == 1 && parameterTypes[0] == String .class; 2139 } 2140 return false; 2141 } 2142 2143 private void registerMethods(boolean instanceMethods) { 2144 Method [] methods = theClass.getMethods(); 2145 for (int i = 0; i < methods.length; i++) { 2146 Method method = methods[i]; 2147 if (MethodHelper.isStatic(method)) { 2148 Class [] paramTypes = method.getParameterTypes(); 2149 if (paramTypes.length > 0) { 2150 Class owner = paramTypes[0]; 2151 if (instanceMethods) { 2152 registry.lookup(owner).addNewInstanceMethod(method); 2153 } else { 2154 registry.lookup(owner).addNewStaticMethod(method); 2155 } 2156 } 2157 } 2158 } 2159 } 2160 2161 protected void registerStaticMethods() { 2162 registerMethods(false); 2163 } 2164 2165 protected void registerInstanceMethods() { 2166 registerMethods(true); 2167 } 2168 2169 protected String capitalize(String property) { 2170 return property.substring(0, 1).toUpperCase() + property.substring(1, property.length()); 2171 } 2172 2173 2178 protected synchronized void onMethodChange() { 2179 reflector = null; 2180 } 2181 2182 protected synchronized void checkInitialised() { 2183 if (!initialised) { 2184 initialised = true; 2185 addInheritedMethods(); 2186 } 2187 if (reflector == null) { 2188 generateReflector(); 2189 } 2190 } 2191 2192 protected MetaMethod createMetaMethod(final Method method) { 2193 if (registry.useAccessible()) { 2194 AccessController.doPrivileged(new PrivilegedAction () { 2195 public Object run() { 2196 method.setAccessible(true); 2197 return null; 2198 } 2199 }); 2200 } 2201 if (useReflection) { 2202 return new ReflectionMetaMethod(method); 2204 } 2205 MetaMethod answer = new MetaMethod(method); 2206 if (isValidReflectorMethod(answer)) { 2207 allMethods.add(answer); 2208 answer.setMethodIndex(allMethods.size()); 2209 } 2210 else { 2211 answer = new ReflectionMetaMethod(method); 2213 } 2214 return answer; 2215 } 2216 2217 protected boolean isValidReflectorMethod(MetaMethod method) { 2218 if (!method.isPublic()) { 2220 return false; 2221 } 2222 Class declaringClass = method.getDeclaringClass(); 2223 if (!Modifier.isPublic(declaringClass.getModifiers())) { 2224 List list = getInterfaceMethods(); 2226 for (Iterator iter = list.iterator(); iter.hasNext();) { 2227 MetaMethod aMethod = (MetaMethod) iter.next(); 2228 if (method.isSame(aMethod)) { 2229 method.setInterfaceClass(aMethod.getDeclaringClass()); 2230 return true; 2231 } 2232 } 2233 2234 return false; 2236 } 2237 return true; 2238 } 2239 2240 protected void generateReflector() { 2241 reflector = loadReflector(allMethods); 2242 if (reflector == null) { 2243 throw new RuntimeException ("Should have a reflector!"); 2244 } 2245 for (Iterator iter = allMethods.iterator(); iter.hasNext();) { 2247 MetaMethod metaMethod = (MetaMethod) iter.next(); 2248 metaMethod.setReflector(reflector); 2250 } 2251 } 2252 2253 protected Reflector loadReflector(List methods) { 2254 ReflectorGenerator generator = new ReflectorGenerator(methods); 2255 String className = theClass.getName(); 2256 String packagePrefix = "gjdk."; 2257 2262 String name = packagePrefix + className + "_GroovyReflector"; 2263 if (theClass.isArray()) { 2264 String componentName = theClass.getComponentType().getName(); 2265 2270 name = packagePrefix + componentName + "_GroovyReflectorArray"; 2271 } 2272 try { 2274 Class type = loadReflectorClass(name); 2275 return (Reflector) type.newInstance(); 2276 } 2277 catch (AccessControlException ace) { 2278 throw ace; 2280 } 2281 catch (Exception e) { 2282 } 2284 2285 ClassWriter cw = new ClassWriter(true); 2286 generator.generate(cw, name); 2287 2288 byte[] bytecode = cw.toByteArray(); 2289 2290 try { 2291 Class type = loadReflectorClass(name, bytecode); 2292 return (Reflector) type.newInstance(); 2293 } 2294 catch (Exception e) { 2295 throw new GroovyRuntimeException("Could not load the reflector for class: " + name + ". Reason: " + e, e); 2296 } 2297 } 2298 2299 protected Class loadReflectorClass(final String name, final byte[] bytecode) throws ClassNotFoundException { 2300 ClassLoader loader = theClass.getClassLoader(); 2301 if (loader instanceof GroovyClassLoader) { 2302 final GroovyClassLoader gloader = (GroovyClassLoader) loader; 2303 return (Class ) AccessController.doPrivileged(new PrivilegedAction () { 2304 public Object run() { 2305 return gloader.defineClass(name, bytecode, getClass().getProtectionDomain()); 2306 } 2307 }); 2308 } 2309 return registry.loadClass(loader, name, bytecode); 2310 } 2311 2312 protected Class loadReflectorClass(String name) throws ClassNotFoundException { 2313 ClassLoader loader = theClass.getClassLoader(); 2314 if (loader instanceof GroovyClassLoader) { 2315 GroovyClassLoader gloader = (GroovyClassLoader) loader; 2316 return gloader.loadClass(name); 2317 } 2318 return registry.loadClass(loader, name); 2319 } 2320 2321 public List getMethods() { 2322 return allMethods; 2323 } 2324 2325 public List getMetaMethods() { 2326 return (List) ((ArrayList)newGroovyMethodsList).clone(); 2327 } 2328 2329 protected synchronized List getInterfaceMethods() { 2330 if (interfaceMethods == null) { 2331 interfaceMethods = new ArrayList(); 2332 Class type = theClass; 2333 while (type != null) { 2334 Class [] interfaces = type.getInterfaces(); 2335 for (int i = 0; i < interfaces.length; i++) { 2336 Class iface = interfaces[i]; 2337 Method [] methods = iface.getMethods(); 2338 addInterfaceMethods(interfaceMethods, methods); 2339 } 2340 type = type.getSuperclass(); 2341 } 2342 } 2343 return interfaceMethods; 2344 } 2345 2346 private void addInterfaceMethods(List list, Method [] methods) { 2347 for (int i = 0; i < methods.length; i++) { 2348 list.add(createMetaMethod(methods[i])); 2349 } 2350 } 2351 2352 2357 Class [] convertToTypeArray(Object [] args) { 2358 if (args == null) 2359 return null; 2360 int s = args.length; 2361 Class [] ans = new Class [s]; 2362 for (int i = 0; i < s; i++) { 2363 Object o = args[i]; 2364 if (o != null) { 2365 ans[i] = o.getClass(); 2366 } else { 2367 ans[i] = null; 2368 } 2369 } 2370 return ans; 2371 } 2372 2373} 2374 | Popular Tags |