1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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.AccessController;
65 import java.security.PrivilegedAction;
66 import java.security.PrivilegedActionException;
67 import java.security.PrivilegedExceptionAction;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collection;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.Iterator;
74 import java.util.LinkedList;
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.CompilerConfiguration;
83 import org.codehaus.groovy.control.Phases;
84 import org.codehaus.groovy.runtime.ClosureListener;
85 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
86 import org.codehaus.groovy.runtime.GroovyCategorySupport;
87 import org.codehaus.groovy.runtime.InvokerHelper;
88 import org.codehaus.groovy.runtime.InvokerInvocationException;
89 import org.codehaus.groovy.runtime.MethodClosure;
90 import org.codehaus.groovy.runtime.MethodHelper;
91 import org.codehaus.groovy.runtime.MethodKey;
92 import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
93 import org.codehaus.groovy.runtime.NewStaticMetaMethod;
94 import org.codehaus.groovy.runtime.ReflectionMetaMethod;
95 import org.codehaus.groovy.runtime.Reflector;
96 import org.codehaus.groovy.runtime.TemporaryMethodKey;
97 import org.codehaus.groovy.runtime.TransformMetaMethod;
98 import org.objectweb.asm.ClassVisitor;
99 import org.objectweb.asm.ClassWriter;
100
101 /***
102 * Allows methods to be dynamically added to existing classes at runtime
103 *
104 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
105 * @author Guillaume Laforge
106 * @author Jochen Theodorou
107 * @version $Revision: 1.114 $
108 */
109 public class MetaClass {
110
111 private static final Logger log = Logger.getLogger(MetaClass.class.getName());
112
113 public static final Object[] EMPTY_ARRAY = {
114 };
115 public static Class[] EMPTY_TYPE_ARRAY = {
116 };
117 protected static final Object[] ARRAY_WITH_NULL = { null };
118
119 private static boolean useReflection = false;
120
121 protected MetaClassRegistry registry;
122 protected Class theClass;
123 private ClassNode classNode;
124 private Map methodIndex = new HashMap();
125 private Map staticMethodIndex = new HashMap();
126 private List newGroovyMethodsList = new LinkedList();
127
128 private Map propertyMap = Collections.synchronizedMap(new HashMap());
129 private Map listeners = new HashMap();
130 private Map methodCache = Collections.synchronizedMap(new HashMap());
131 private Map staticMethodCache = Collections.synchronizedMap(new HashMap());
132 private MetaMethod genericGetMethod;
133 private MetaMethod genericSetMethod;
134 private List constructors;
135 private List allMethods = new ArrayList();
136 private List interfaceMethods;
137 private Reflector reflector;
138 private boolean initialised;
139
140 private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
141
142 public MetaClass(MetaClassRegistry registry, final Class theClass) throws IntrospectionException {
143 this.registry = registry;
144 this.theClass = theClass;
145
146 constructors = (List) AccessController.doPrivileged(new PrivilegedAction() {
147 public Object run() {
148 return Arrays.asList (theClass.getDeclaredConstructors());
149 }
150 });
151
152 addMethods(theClass,true);
153
154
155 BeanInfo info = null;
156 try {
157 info =(BeanInfo) AccessController.doPrivileged(new PrivilegedExceptionAction() {
158 public Object run() throws IntrospectionException {
159 return Introspector.getBeanInfo(theClass);
160 }
161 });
162 } catch (PrivilegedActionException pae) {
163 if (pae.getException() instanceof IntrospectionException) {
164 throw (IntrospectionException) pae.getException();
165 } else {
166 throw new RuntimeException(pae.getException());
167 }
168 }
169
170 PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
171
172
173
174 setupProperties(descriptors);
175
176
177
178
179
180
181
182
183 EventSetDescriptor[] eventDescriptors = info.getEventSetDescriptors();
184 for (int i = 0; i < eventDescriptors.length; i++) {
185 EventSetDescriptor descriptor = eventDescriptors[i];
186 Method[] listenerMethods = descriptor.getListenerMethods();
187 for (int j = 0; j < listenerMethods.length; j++) {
188 Method listenerMethod = listenerMethods[j];
189 MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod());
190 listeners.put(listenerMethod.getName(), metaMethod);
191 }
192 }
193 }
194
195 public static boolean isUseReflection() {
196 return useReflection;
197 }
198
199 /***
200 * Allows reflection to be enabled in situations where bytecode generation
201 * of method invocations causes issues.
202 *
203 * @param useReflection
204 */
205 public static void setUseReflection(boolean useReflection) {
206 MetaClass.useReflection = useReflection;
207 }
208
209 private void addInheritedMethods() {
210 LinkedList superClasses = new LinkedList();
211 for (Class c = theClass.getSuperclass(); c!=Object.class && c!= null; c = c.getSuperclass()) {
212 superClasses.addFirst(c);
213 }
214
215 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
216 Class c = (Class) iter.next();
217 addMethods(c,true);
218 addNewStaticMethodsFrom(c);
219 }
220
221
222 Class[] interfaces = theClass.getInterfaces();
223 for (int i = 0; i < interfaces.length; i++) {
224 addNewStaticMethodsFrom(interfaces[i]);
225 }
226
227
228
229 if (theClass != Object.class) {
230 addMethods(Object.class, false);
231 addNewStaticMethodsFrom(Object.class);
232 }
233
234 if (theClass.isArray() && !theClass.equals(Object[].class)) {
235 addNewStaticMethodsFrom(Object[].class);
236 }
237 }
238
239 /***
240 * @return all the normal instance methods avaiable on this class for the
241 * given name
242 */
243 public List getMethods(String name) {
244 List answer = (List) methodIndex.get(name);
245 List used = GroovyCategorySupport.getCategoryMethods(theClass, name);
246 if (used != null) {
247 if (answer != null) {
248 used.addAll(answer);
249 }
250 answer = used;
251 }
252 if (answer == null) {
253 answer = Collections.EMPTY_LIST;
254 }
255 return answer;
256 }
257
258 /***
259 * @return all the normal static methods avaiable on this class for the
260 * given name
261 */
262 public List getStaticMethods(String name) {
263 List answer = (List) staticMethodIndex.get(name);
264 if (answer == null) {
265 return Collections.EMPTY_LIST;
266 }
267 return answer;
268 }
269
270 /***
271 * Allows static method definitions to be added to a meta class as if it
272 * was an instance method
273 *
274 * @param method
275 */
276 protected void addNewInstanceMethod(Method method) {
277 if (initialised) {
278 throw new RuntimeException("Already initialized, cannot add new method: " + method);
279 }
280 else {
281 NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method));
282 if (! newGroovyMethodsList.contains(newMethod)){
283 newGroovyMethodsList.add(newMethod);
284 addMethod(newMethod,false);
285 }
286 }
287 }
288
289 protected void addNewStaticMethod(Method method) {
290 if (initialised) {
291 throw new RuntimeException("Already initialized, cannot add new method: " + method);
292 }
293 else {
294 NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method));
295 if (! newGroovyMethodsList.contains(newMethod)){
296 newGroovyMethodsList.add(newMethod);
297 addMethod(newMethod,false);
298 }
299 }
300 }
301
302 public Object invokeMethod(Object object, String methodName, Object arguments) {
303 return invokeMethod(object, methodName, asArray(arguments));
304 }
305
306 /***
307 * Invokes the given method on the object.
308 *
309 */
310 public Object invokeMethod(Object object, String methodName, Object[] arguments) {
311 if (object == null) {
312 throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
313 }
314
315 MetaMethod method = retrieveMethod(object, methodName, arguments);
316
317 if (method != null) {
318 return doMethodInvoke(object, method, arguments);
319 } else {
320
321 try {
322 Object value = this.getProperty(object, methodName);
323 if (value instanceof Closure && object!=this) {
324 Closure closure = (Closure) value;
325 closure.setDelegate(this);
326 return closure.call(new ParameterArray(arguments));
327 }
328 else {
329 throw new MissingMethodException(methodName, theClass, arguments);
330 }
331 }
332 catch (Exception e) {
333 throw new MissingMethodException(methodName, theClass, arguments);
334 }
335 }
336 }
337
338 protected MetaMethod retrieveMethod(Object owner, String methodName, Object[] arguments) {
339
340 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
341 MetaMethod method = (MetaMethod) methodCache.get(methodKey);
342 if (method == null) {
343 method = pickMethod(owner, methodName, arguments);
344 if (method != null && method.isCacheable()) {
345 methodCache.put(methodKey.createCopy(), method);
346 }
347 }
348 return method;
349 }
350
351 public MetaMethod retrieveMethod(String methodName, Class[] arguments) {
352
353 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
354 MetaMethod method = (MetaMethod) methodCache.get(methodKey);
355 if (method == null) {
356 method = pickMethod(methodName, arguments);
357 if (method != null && method.isCacheable()) {
358 methodCache.put(methodKey.createCopy(), method);
359 }
360 }
361 return method;
362 }
363
364 public Constructor retrieveConstructor(Class[] arguments) {
365 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, arguments, false);
366 if (constructor != null) {
367 return constructor;
368 }
369 else {
370 constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
371 if (constructor != null) {
372 return constructor;
373 }
374 }
375 return null;
376 }
377
378 public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
379 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
380 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
381 if (method == null) {
382 method = pickStaticMethod(methodName, arguments);
383 if (method != null) {
384 staticMethodCache.put(methodKey.createCopy(), method);
385 }
386 }
387 return method;
388 }
389 /***
390 * Picks which method to invoke for the given object, method name and arguments
391 */
392 protected MetaMethod pickMethod(Object object, String methodName, Object[] arguments) {
393 MetaMethod method = null;
394 List methods = getMethods(methodName);
395 if (!methods.isEmpty()) {
396 Class[] argClasses = convertToTypeArray(arguments);
397 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
398 if (method == null) {
399 int size = (arguments != null) ? arguments.length : 0;
400 if (size == 1) {
401 Object firstArgument = arguments[0];
402 if (firstArgument instanceof List) {
403
404
405
406
407 List list = (List) firstArgument;
408 arguments = list.toArray();
409 argClasses = convertToTypeArray(arguments);
410 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
411 if (method==null) return null;
412 return new TransformMetaMethod(method) {
413 public Object invoke(Object object, Object[] arguments) throws Exception {
414 Object firstArgument = arguments[0];
415 List list = (List) firstArgument;
416 arguments = list.toArray();
417 return super.invoke(object, arguments);
418 }
419 };
420 }
421 }
422 }
423 }
424 return method;
425 }
426
427 /***
428 * pick a method in a strict manner, i.e., without reinterpreting the first List argument.
429 * this method is used only by ClassGenerator for static binding
430 * @param methodName
431 * @param arguments
432 * @return
433 */
434 protected MetaMethod pickMethod(String methodName, Class[] arguments) {
435 MetaMethod method = null;
436 List methods = getMethods(methodName);
437 if (!methods.isEmpty()) {
438 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
439
440
441
442
443 }
444 return method;
445 }
446
447 public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
448
449
450
451
452
453
454 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
455 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
456 if (method == null) {
457 method = pickStaticMethod(object, methodName, arguments);
458 if (method != null) {
459 staticMethodCache.put(methodKey.createCopy(), method);
460 }
461 }
462
463 if (method != null) {
464 return doMethodInvoke(object, method, arguments);
465 }
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485 throw new MissingMethodException(methodName, theClass, arguments);
486 }
487
488 protected MetaMethod pickStaticMethod(Object object, String methodName, Object[] arguments) {
489 MetaMethod method = null;
490 List methods = getStaticMethods(methodName);
491
492 if (!methods.isEmpty()) {
493 method = (MetaMethod) chooseMethod(methodName, methods, convertToTypeArray(arguments), false);
494 }
495
496 if (method == null && theClass != Class.class) {
497 MetaClass classMetaClass = registry.getMetaClass(Class.class);
498 method = classMetaClass.pickMethod(object, methodName, arguments);
499 }
500 if (method == null) {
501 method = (MetaMethod) chooseMethod(methodName, methods, convertToTypeArray(arguments), true);
502 }
503 return method;
504 }
505
506 protected MetaMethod pickStaticMethod(String methodName, Class[] arguments) {
507 MetaMethod method = null;
508 List methods = getStaticMethods(methodName);
509
510 if (!methods.isEmpty()) {
511 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
512
513
514
515
516 }
517
518 if (method == null && theClass != Class.class) {
519 MetaClass classMetaClass = registry.getMetaClass(Class.class);
520 method = classMetaClass.pickMethod(methodName, arguments);
521 }
522 return method;
523 }
524
525 public Object invokeConstructor(Object[] arguments) {
526 Class[] argClasses = convertToTypeArray(arguments);
527 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
528 if (constructor != null) {
529 return doConstructorInvoke(constructor, arguments);
530 }
531 else {
532 constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
533 if (constructor != null) {
534 return doConstructorInvoke(constructor, arguments);
535 }
536 }
537
538 if (arguments.length == 1) {
539 Object firstArgument = arguments[0];
540 if (firstArgument instanceof Map) {
541 constructor = (Constructor) chooseMethod("<init>", constructors, EMPTY_TYPE_ARRAY, false);
542 if (constructor != null) {
543 Object bean = doConstructorInvoke(constructor, EMPTY_ARRAY);
544 setProperties(bean, ((Map) firstArgument));
545 return bean;
546 }
547 }
548 }
549 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 public void setProperties(Object bean, Map map) {
561 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
562 Map.Entry entry = (Map.Entry) iter.next();
563 String key = entry.getKey().toString();
564
565
566 if(propertyMap.get(key) == null)
567 continue;
568
569 Object value = entry.getValue();
570 try {
571 setProperty(bean, key, value);
572 }
573 catch (GroovyRuntimeException e) {
574
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 public Object getProperty(final Object object, final String property) {
586
587 MetaProperty mp = (MetaProperty) propertyMap.get(property);
588 if(mp != null) {
589 try {
590
591
592
593 return mp.getProperty(object);
594 }
595 catch(Exception e) {
596 throw new GroovyRuntimeException("Cannot read property: " + property);
597 }
598 }
599
600 if (genericGetMethod == null) {
601
602 List possibleGenericMethods = getMethods("get");
603 if (possibleGenericMethods != null) {
604 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
605 MetaMethod mmethod = (MetaMethod) i.next();
606 Class[] paramTypes = mmethod.getParameterTypes();
607 if (paramTypes.length == 1 && paramTypes[0] == String.class) {
608 Object[] arguments = {property};
609 Object answer = doMethodInvoke(object, mmethod, arguments);
610 return answer;
611 }
612 }
613 }
614 }
615 else {
616 Object[] arguments = { property };
617 Object answer = doMethodInvoke(object, genericGetMethod, arguments);
618
619 if (answer != null) {
620 return answer;
621 }
622 }
623
624 if (!CompilerConfiguration.isJsrGroovy()) {
625
626
627 List methods = getMethods(property);
628 if (!methods.isEmpty()) {
629 return new MethodClosure(object, property);
630 }
631 }
632
633
634
635 Exception lastException = null;
636 try {
637 MetaMethod method = findGetter(object, "get" + capitalize(property));
638 if (method != null) {
639 return doMethodInvoke(object, method, EMPTY_ARRAY);
640 }
641 }
642 catch (GroovyRuntimeException e) {
643 lastException = e;
644 }
645
646 /*** todo or are we an extensible groovy class? */
647 if (genericGetMethod != null) {
648 return null;
649 }
650 else {
651 /*** todo these special cases should be special MetaClasses maybe */
652 if (object instanceof Class) {
653
654 return getStaticProperty((Class) object, property);
655 }
656 if (object instanceof Collection) {
657 return DefaultGroovyMethods.getAt((Collection) object, property);
658 }
659 if (object instanceof Object[]) {
660 return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), property);
661 }
662 if (object instanceof Object) {
663 Field field = null;
664 try {
665
666 field = object.getClass().getDeclaredField(property);
667 return field.get(object);
668 } catch (IllegalAccessException iae) {
669 lastException = new IllegalPropertyAccessException(field,object.getClass());
670 } catch (Exception e1) {
671
672 }
673 }
674
675 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
676 if (addListenerMethod != null) {
677
678 return null;
679 }
680
681 if (lastException == null)
682 throw new MissingPropertyException(property, theClass);
683 else
684 throw new MissingPropertyException(property, theClass, lastException);
685 }
686 }
687
688 /***
689 * Get all the properties defined for this type
690 * @return a list of MetaProperty objects
691 */
692 public List getProperties() {
693
694 return new ArrayList(propertyMap.values());
695 }
696
697 /***
698 * This will build up the property map (Map of MetaProperty objects, keyed on
699 * property name).
700 */
701 protected void setupProperties(PropertyDescriptor[] propertyDescriptors) {
702 MetaProperty mp;
703 Method method;
704 MetaMethod getter = null;
705 MetaMethod setter = null;
706 Class klass;
707
708
709 klass = theClass;
710 while(klass != null) {
711 final Class clazz = klass;
712 Field[] fields = (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
713 public Object run() {
714 return clazz.getDeclaredFields();
715 }
716 });
717 for(int i = 0; i < fields.length; i++) {
718
719 if((fields[i].getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0)
720 continue;
721
722
723 if(propertyMap.get(fields[i].getName()) != null)
724 continue;
725
726
727
728
729 propertyMap.put(fields[i].getName(), new MetaFieldProperty(fields[i]));
730 }
731
732
733 klass = klass.getSuperclass();
734 }
735
736
737 if(theClass.isArray()) {
738 propertyMap.put("length", arrayLengthProperty);
739 }
740
741
742
743 for(int i=0; i<propertyDescriptors.length; i++) {
744 PropertyDescriptor pd = propertyDescriptors[i];
745
746 if(propertyMap.get(pd.getName()) != null)
747 continue;
748
749
750
751
752 if(pd.getPropertyType() == null)
753 continue;
754
755
756 method = pd.getReadMethod();
757 if(method != null)
758 getter = findMethod(method);
759 else
760 getter = null;
761
762
763 method = pd.getWriteMethod();
764 if(method != null)
765 setter = findMethod(method);
766 else
767 setter = null;
768
769
770
771
772
773 mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter);
774
775
776 propertyMap.put(pd.getName(), mp);
777 }
778
779
780 klass = theClass;
781 while(klass != null) {
782 final Class clazz = klass;
783 Method[] methods = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
784 public Object run() {
785 return clazz.getDeclaredMethods();
786 }
787 });
788 for (int i = 0; i < methods.length; i++) {
789
790 if(Modifier.isPublic(methods[i].getModifiers()) == false)
791 continue;
792
793 method = methods[i];
794
795 String methodName = method.getName();
796
797
798 if(methodName.startsWith("get") &&
799 methodName.length() > 3 &&
800 method.getParameterTypes().length == 0) {
801
802
803 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
804
805
806 mp = (MetaProperty) propertyMap.get(propName);
807 if(mp != null) {
808
809 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getGetter() == null) {
810
811 ((MetaBeanProperty) mp).setGetter(findMethod(method));
812 }
813 }
814 else {
815
816
817 MetaBeanProperty mbp = new MetaBeanProperty(propName,
818 method.getReturnType(),
819 findMethod(method), null);
820
821
822 propertyMap.put(propName, mbp);
823 }
824 }
825 else if(methodName.startsWith("set") &&
826 methodName.length() > 3 &&
827 method.getParameterTypes().length == 1) {
828
829
830 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
831
832
833 mp = (MetaProperty) propertyMap.get(propName);
834 if(mp != null) {
835 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getSetter() == null) {
836
837 ((MetaBeanProperty) mp).setSetter(findMethod(method));
838 }
839 }
840 else {
841
842 MetaBeanProperty mbp = new MetaBeanProperty(propName,
843 method.getParameterTypes()[0],
844 null,
845 findMethod(method));
846
847
848 propertyMap.put(propName, mbp);
849 }
850 }
851 }
852
853
854 klass = klass.getSuperclass();
855 }
856 }
857
858 /***
859 * Sets the property value on an object
860 */
861 public void setProperty(Object object, String property, Object newValue) {
862 MetaProperty mp = (MetaProperty) propertyMap.get(property);
863 if(mp != null) {
864 try {
865 mp.setProperty(object, newValue);
866 return;
867 }
868 catch(ReadOnlyPropertyException e) {
869
870 throw e;
871 }
872 catch (TypeMismatchException e) {
873
874 throw e;
875 }
876 catch (Exception e) {
877
878
879 if (newValue == null)
880 return;
881 if (newValue instanceof List) {
882 List list = (List) newValue;
883 int params = list.size();
884 Constructor[] constructors = mp.getType().getConstructors();
885 for (int i = 0; i < constructors.length; i++) {
886 Constructor constructor = constructors[i];
887 if (constructor.getParameterTypes().length == params) {
888 Object value = doConstructorInvoke(constructor, list.toArray());
889 mp.setProperty(object, value);
890 return;
891 }
892 }
893
894
895 Class parameterType = mp.getType();
896 if (parameterType.isArray()) {
897 Object objArray = asPrimitiveArray(list, parameterType);
898 mp.setProperty(object, objArray);
899 return;
900 }
901 }
902
903
904
905
906
907 if (newValue.getClass().isArray() && mp instanceof MetaBeanProperty) {
908 MetaBeanProperty mbp = (MetaBeanProperty) mp;
909 List list = Arrays.asList((Object[])newValue);
910 MetaMethod setter = mbp.getSetter();
911
912 Class parameterType = setter.getParameterTypes()[0];
913 Class arrayType = parameterType.getComponentType();
914 Object objArray = Array.newInstance(arrayType, list.size());
915
916 for (int i = 0; i < list.size(); i++) {
917 List list2 =Arrays.asList((Object[]) list.get(i));
918 Object objArray2 = asPrimitiveArray(list2, arrayType);
919 Array.set(objArray, i, objArray2);
920 }
921
922 doMethodInvoke(object, setter, new Object[]{
923 objArray
924 });
925 return;
926 }
927
928 throw new MissingPropertyException(property, theClass, e);
929 }
930 }
931
932 try {
933 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
934 if (addListenerMethod != null && newValue instanceof Closure) {
935
936 Object proxy =
937 createListenerProxy(addListenerMethod.getParameterTypes()[0], property, (Closure) newValue);
938 doMethodInvoke(object, addListenerMethod, new Object[] { proxy });
939 return;
940 }
941
942 if (genericSetMethod == null) {
943
944 List possibleGenericMethods = getMethods("set");
945 if (possibleGenericMethods != null) {
946 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
947 MetaMethod mmethod = (MetaMethod) i.next();
948 Class[] paramTypes = mmethod.getParameterTypes();
949 if (paramTypes.length == 2 && paramTypes[0] == String.class) {
950 Object[] arguments = {property, newValue};
951 Object answer = doMethodInvoke(object, mmethod, arguments);
952 return;
953 }
954 }
955 }
956 }
957 else {
958 Object[] arguments = { property, newValue };
959 doMethodInvoke(object, genericSetMethod, arguments);
960 return;
961 }
962
963 /*** todo or are we an extensible class? */
964
965
966
967
968
969
970 String method = "set" + capitalize(property);
971 try {
972 invokeMethod(object, method, new Object[] { newValue });
973 }
974 catch (MissingMethodException e1) {
975 Field field = null;
976 try {
977 final Class clazz = object.getClass();
978 final String prop = property;
979 try {
980 field = (Field) AccessController.doPrivileged(new PrivilegedExceptionAction() {
981 public Object run() throws NoSuchFieldException {
982 return clazz.getDeclaredField(prop);
983 }
984 });
985
986 field.set(object, newValue);
987 }
988 catch (PrivilegedActionException pae) {
989 if (pae.getException() instanceof NoSuchFieldException) {
990 throw (NoSuchFieldException) pae.getException();
991 } else {
992 throw new RuntimeException(pae.getException());
993 }
994 }
995 } catch (IllegalAccessException iae) {
996 throw new IllegalPropertyAccessException(field,object.getClass());
997 } catch (Exception e2) {
998 throw new MissingPropertyException(property, theClass, e2);
999 }
1000 }
1001
1002 }
1003 catch (GroovyRuntimeException e) {
1004 throw new MissingPropertyException(property, theClass, e);
1005 }
1006
1007 }
1008
1009
1010 /***
1011 * Looks up the given attribute (field) on the given object
1012 */
1013 public Object getAttribute(Object object, final String attribute) {
1014 try {
1015 final Class clazz = theClass;
1016 try {
1017 Field field = (Field) AccessController.doPrivileged(new PrivilegedExceptionAction() {
1018 public Object run() throws NoSuchFieldException {
1019 return clazz.getDeclaredField(attribute);
1020 }
1021 });
1022 field.setAccessible(true);
1023 return field.get(object);
1024 } catch (PrivilegedActionException pae) {
1025 if (pae.getException() instanceof NoSuchFieldException) {
1026 throw (NoSuchFieldException) pae.getException();
1027 } else {
1028 throw new RuntimeException(pae.getException());
1029 }
1030 }
1031 }
1032 catch (NoSuchFieldException e) {
1033 throw new MissingFieldException(attribute, theClass);
1034 }
1035 catch (IllegalAccessException e) {
1036 throw new MissingFieldException(attribute, theClass, e);
1037 }
1038 }
1039
1040 /***
1041 * Sets the given attribute (field) on the given object
1042 */
1043 public void setAttribute(Object object, final String attribute, Object newValue) {
1044 try {
1045 final Class clazz = theClass;
1046 try {
1047 Field field = (Field) AccessController.doPrivileged(new PrivilegedExceptionAction() {
1048 public Object run() throws NoSuchFieldException {
1049 return clazz.getDeclaredField(attribute);
1050 }
1051 });
1052 field.setAccessible(true);
1053 field.set(object, newValue);
1054 } catch (PrivilegedActionException pae) {
1055 if (pae.getException() instanceof NoSuchFieldException) {
1056 throw (NoSuchFieldException) pae.getException();
1057 } else {
1058 throw new RuntimeException(pae.getException());
1059 }
1060 }
1061 }
1062 catch (NoSuchFieldException e) {
1063 throw new MissingFieldException(attribute, theClass);
1064 }
1065 catch (IllegalAccessException e) {
1066 throw new MissingFieldException(attribute, theClass, e);
1067 }
1068 }
1069
1070 /***
1071 * Returns a callable object for the given method name on the object.
1072 * The object acts like a Closure in that it can be called, like a closure
1073 * and passed around - though really its a method pointer, not a closure per se.
1074 */
1075 public Closure getMethodPointer(Object object, String methodName) {
1076 return new MethodClosure(object, methodName);
1077 }
1078
1079 /***
1080 * @param list
1081 * @param parameterType
1082 * @return
1083 */
1084 private Object asPrimitiveArray(List list, Class parameterType) {
1085 Class arrayType = parameterType.getComponentType();
1086 Object objArray = Array.newInstance(arrayType, list.size());
1087 for (int i = 0; i < list.size(); i++) {
1088 Object obj = list.get(i);
1089 if (arrayType.isPrimitive()) {
1090 if (obj instanceof Integer) {
1091 Array.setInt(objArray, i, ((Integer) obj).intValue());
1092 }
1093 else if (obj instanceof Double) {
1094 Array.setDouble(objArray, i, ((Double) obj).doubleValue());
1095 }
1096 else if (obj instanceof Boolean) {
1097 Array.setBoolean(objArray, i, ((Boolean) obj).booleanValue());
1098 }
1099 else if (obj instanceof Long) {
1100 Array.setLong(objArray, i, ((Long) obj).longValue());
1101 }
1102 else if (obj instanceof Float) {
1103 Array.setFloat(objArray, i, ((Float) obj).floatValue());
1104 }
1105 else if (obj instanceof Character) {
1106 Array.setChar(objArray, i, ((Character) obj).charValue());
1107 }
1108 else if (obj instanceof Byte) {
1109 Array.setByte(objArray, i, ((Byte) obj).byteValue());
1110 }
1111 else if (obj instanceof Short) {
1112 Array.setShort(objArray, i, ((Short) obj).shortValue());
1113 }
1114 }
1115 else {
1116 Array.set(objArray, i, obj);
1117 }
1118 }
1119 return objArray;
1120 }
1121
1122 public ClassNode getClassNode() {
1123 if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) {
1124
1125 String className = theClass.getName();
1126 String groovyFile = className;
1127 int idx = groovyFile.indexOf('$');
1128 if (idx > 0) {
1129 groovyFile = groovyFile.substring(0, idx);
1130 }
1131 groovyFile = groovyFile.replace('.', '/') + ".groovy";
1132
1133
1134 URL url = theClass.getClassLoader().getResource(groovyFile);
1135 if (url == null) {
1136 url = Thread.currentThread().getContextClassLoader().getResource(groovyFile);
1137 }
1138 if (url != null) {
1139 try {
1140
1141 /***
1142 * todo there is no CompileUnit in scope so class name
1143 * checking won't work but that mostly affects the bytecode
1144 * generation rather than viewing the AST
1145 */
1146
1147 CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
1148 public void call( ClassVisitor writer, ClassNode node ) {
1149 if( node.getName().equals(theClass.getName()) ) {
1150 MetaClass.this.classNode = node;
1151 }
1152 }
1153 };
1154
1155
1156 CompilationUnit unit = new CompilationUnit( getClass().getClassLoader() );
1157 unit.setClassgenCallback( search );
1158 unit.addSource( url );
1159 unit.compile( Phases.CLASS_GENERATION );
1160 }
1161 catch (Exception e) {
1162 throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e);
1163 }
1164 }
1165
1166 }
1167 return classNode;
1168 }
1169
1170 public String toString() {
1171 return super.toString() + "[" + theClass + "]";
1172 }
1173
1174
1175
1176
1177 /***
1178 * Converts the given object into an array; if its an array then just cast
1179 * otherwise wrap it in an array
1180 */
1181 protected Object[] asArray(Object arguments) {
1182 if (arguments == null) {
1183 return EMPTY_ARRAY;
1184 }
1185 if (arguments instanceof Tuple) {
1186 Tuple tuple = (Tuple) arguments;
1187 return tuple.toArray();
1188 }
1189 if (arguments instanceof Object[]) {
1190 return (Object[]) arguments;
1191 }
1192 else {
1193 return new Object[] { arguments };
1194 }
1195 }
1196
1197 /***
1198 * @param listenerType
1199 * the interface of the listener to proxy
1200 * @param listenerMethodName
1201 * the name of the method in the listener API to call the
1202 * closure on
1203 * @param closure
1204 * the closure to invoke on the listenerMethodName method
1205 * invocation
1206 * @return a dynamic proxy which calls the given closure on the given
1207 * method name
1208 */
1209 protected Object createListenerProxy(Class listenerType, final String listenerMethodName, final Closure closure) {
1210 InvocationHandler handler = new ClosureListener(listenerMethodName, closure);
1211 return Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[] { listenerType }, handler);
1212 }
1213
1214 /***
1215 * Adds all the methods declared in the given class to the metaclass
1216 * ignoring any matching methods already defined by a derived class
1217 *
1218 * @param theClass
1219 */
1220 protected void addMethods(final Class theClass, boolean forceOverwrite) {
1221
1222 Method[] methodArray = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
1223 public Object run() {
1224 return theClass.getDeclaredMethods();
1225 }
1226 });
1227 for (int i = 0; i < methodArray.length; i++) {
1228 Method reflectionMethod = methodArray[i];
1229 if ( reflectionMethod.getName().indexOf('+') >= 0 ) {
1230 continue;
1231 }
1232 MetaMethod method = createMetaMethod(reflectionMethod);
1233 addMethod(method,forceOverwrite);
1234 }
1235 }
1236
1237 protected void addMethod(MetaMethod method, boolean forceOverwrite) {
1238 String name = method.getName();
1239
1240
1241
1242 if (isGenericGetMethod(method) && genericGetMethod == null) {
1243 genericGetMethod = method;
1244 }
1245 else if (isGenericSetMethod(method) && genericSetMethod == null) {
1246 genericSetMethod = method;
1247 }
1248 if (method.isStatic()) {
1249 List list = (List) staticMethodIndex.get(name);
1250 if (list == null) {
1251 list = new ArrayList();
1252 staticMethodIndex.put(name, list);
1253 list.add(method);
1254 }
1255 else {
1256 if (!containsMatchingMethod(list, method)) {
1257 list.add(method);
1258 }
1259 }
1260 }
1261
1262 List list = (List) methodIndex.get(name);
1263 if (list == null) {
1264 list = new ArrayList();
1265 methodIndex.put(name, list);
1266 list.add(method);
1267 }
1268 else {
1269 if (forceOverwrite) {
1270 removeMatchingMethod(list,method);
1271 list.add(method);
1272 } else if (!containsMatchingMethod(list, method)) {
1273 list.add(method);
1274 }
1275 }
1276 }
1277
1278 /***
1279 * @return true if a method of the same matching prototype was found in the
1280 * list
1281 */
1282 protected boolean containsMatchingMethod(List list, MetaMethod method) {
1283 for (Iterator iter = list.iterator(); iter.hasNext();) {
1284 MetaMethod aMethod = (MetaMethod) iter.next();
1285 Class[] params1 = aMethod.getParameterTypes();
1286 Class[] params2 = method.getParameterTypes();
1287 if (params1.length == params2.length) {
1288 boolean matches = true;
1289 for (int i = 0; i < params1.length; i++) {
1290 if (params1[i] != params2[i]) {
1291 matches = false;
1292 break;
1293 }
1294 }
1295 if (matches) {
1296 return true;
1297 }
1298 }
1299 }
1300 return false;
1301 }
1302
1303 /***
1304 * remove a method of the same matching prototype was found in the list
1305 */
1306 protected void removeMatchingMethod(List list, MetaMethod method) {
1307 for (Iterator iter = list.iterator(); iter.hasNext();) {
1308 MetaMethod aMethod = (MetaMethod) iter.next();
1309 Class[] params1 = aMethod.getParameterTypes();
1310 Class[] params2 = method.getParameterTypes();
1311 if (params1.length == params2.length) {
1312 boolean matches = true;
1313 for (int i = 0; i < params1.length; i++) {
1314 if (params1[i] != params2[i]) {
1315 matches = false;
1316 break;
1317 }
1318 }
1319 if (matches) {
1320 iter.remove();
1321 return;
1322 }
1323 }
1324 }
1325 return;
1326 }
1327
1328
1329 /***
1330 * Adds all of the newly defined methods from the given class to this
1331 * metaclass
1332 *
1333 * @param theClass
1334 */
1335 protected void addNewStaticMethodsFrom(Class theClass) {
1336 MetaClass interfaceMetaClass = registry.getMetaClass(theClass);
1337 Iterator iter = interfaceMetaClass.newGroovyMethodsList.iterator();
1338 while (iter.hasNext()) {
1339 MetaMethod method = (MetaMethod) iter.next();
1340 if (! newGroovyMethodsList.contains(method)){
1341 newGroovyMethodsList.add(method);
1342 addMethod(method,false);
1343 }
1344 }
1345 }
1346
1347 /***
1348 * @return the value of the static property of the given class
1349 */
1350 protected Object getStaticProperty(Class aClass, String property) {
1351
1352
1353
1354 Exception lastException = null;
1355 try {
1356 Field field = aClass.getField(property);
1357 if (field != null) {
1358 if ((field.getModifiers() & Modifier.STATIC) != 0) {
1359 return field.get(null);
1360 }
1361 }
1362 }
1363 catch (Exception e) {
1364 lastException = e;
1365 }
1366
1367
1368 try {
1369 MetaMethod method = findStaticGetter(aClass, "get" + capitalize(property));
1370 if (method != null) {
1371 return doMethodInvoke(aClass, method, EMPTY_ARRAY);
1372 }
1373 }
1374 catch (GroovyRuntimeException e) {
1375 throw new MissingPropertyException(property, aClass, e);
1376 }
1377
1378 if (lastException == null) {
1379 throw new MissingPropertyException(property, aClass);
1380 }
1381 else {
1382 throw new MissingPropertyException(property, aClass, lastException);
1383 }
1384 }
1385
1386 /***
1387 * @return the matching method which should be found
1388 */
1389 protected MetaMethod findMethod(Method aMethod) {
1390 List methods = getMethods(aMethod.getName());
1391 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1392 MetaMethod method = (MetaMethod) iter.next();
1393 if (method.isMethod(aMethod)) {
1394 return method;
1395 }
1396 }
1397
1398 return new ReflectionMetaMethod(aMethod);
1399 }
1400
1401 /***
1402 * @return the getter method for the given object
1403 */
1404 protected MetaMethod findGetter(Object object, String name) {
1405 List methods = getMethods(name);
1406 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1407 MetaMethod method = (MetaMethod) iter.next();
1408 if (method.getParameterTypes().length == 0) {
1409 return method;
1410 }
1411 }
1412 return null;
1413 }
1414
1415 /***
1416 * @return the Method of the given name with no parameters or null
1417 */
1418 protected MetaMethod findStaticGetter(Class type, String name) {
1419 List methods = getStaticMethods(name);
1420 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1421 MetaMethod method = (MetaMethod) iter.next();
1422 if (method.getParameterTypes().length == 0) {
1423 return method;
1424 }
1425 }
1426
1427 /*** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
1428 try {
1429 Method method = type.getMethod(name, EMPTY_TYPE_ARRAY);
1430 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1431 return findMethod(method);
1432 }
1433 else {
1434 return null;
1435 }
1436 }
1437 catch (Exception e) {
1438 return null;
1439 }
1440 }
1441
1442 protected Object doMethodInvoke(Object object, MetaMethod method, Object[] argumentArray) {
1443
1444
1445
1446
1447
1448 try {
1449 if (argumentArray == null) {
1450 argumentArray = EMPTY_ARRAY;
1451 }
1452 else if (method.getParameterTypes().length == 1 && argumentArray.length == 0) {
1453 argumentArray = ARRAY_WITH_NULL;
1454 }
1455 return method.invoke(object, argumentArray);
1456 }
1457 catch (ClassCastException e) {
1458 if (coerceGStrings(argumentArray)) {
1459 try {
1460 return doMethodInvoke(object, method, argumentArray);
1461 }
1462 catch (Exception e2) {
1463
1464 }
1465 }
1466 throw new GroovyRuntimeException(
1467 "failed to invoke method: "
1468 + method
1469 + " on: "
1470 + object
1471 + " with arguments: "
1472 + InvokerHelper.toString(argumentArray)
1473 + " reason: "
1474 + e,
1475 e);
1476 }
1477 catch (InvocationTargetException e) {
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487 throw new InvokerInvocationException(e);
1488 }
1489 catch (IllegalAccessException e) {
1490 throw new GroovyRuntimeException(
1491 "could not access method: "
1492 + method
1493 + " on: "
1494 + object
1495 + " with arguments: "
1496 + InvokerHelper.toString(argumentArray)
1497 + " reason: "
1498 + e,
1499 e);
1500 }
1501 catch (IllegalArgumentException e) {
1502 if (coerceGStrings(argumentArray)) {
1503 try {
1504 return doMethodInvoke(object, method, argumentArray);
1505 }
1506 catch (Exception e2) {
1507
1508 }
1509 }
1510 Object[] args = coerceNumbers(method, argumentArray);
1511 if (args != null && !Arrays.equals(argumentArray,args)) {
1512 try {
1513 return doMethodInvoke(object, method, args);
1514 }
1515 catch (Exception e3) {
1516
1517 }
1518 }
1519 throw new GroovyRuntimeException(
1520 "failed to invoke method: "
1521 + method
1522 + " on: "
1523 + object
1524 + " with arguments: "
1525 + InvokerHelper.toString(argumentArray)
1526 + "reason: "
1527 + e
1528 );
1529 }
1530 catch (RuntimeException e) {
1531 throw e;
1532 }
1533 catch (Exception e) {
1534 throw new GroovyRuntimeException(
1535 "failed to invoke method: "
1536 + method
1537 + " on: "
1538 + object
1539 + " with arguments: "
1540 + InvokerHelper.toString(argumentArray)
1541 + " reason: "
1542 + e,
1543 e);
1544 }
1545 }
1546
1547 private static Object[] coerceNumbers(MetaMethod method, Object[] arguments) {
1548 Object[] ans = null;
1549 boolean coerced = false;
1550
1551 Class[] params = method.getParameterTypes();
1552
1553 if (params.length != arguments.length) {
1554 return null;
1555 }
1556
1557 ans = new Object[arguments.length];
1558
1559 for (int i = 0, size = arguments.length; i < size; i++) {
1560 Object argument = arguments[i];
1561 Class param = params[i];
1562 if ((Number.class.isAssignableFrom(param) || param.isPrimitive()) && argument instanceof Number) {
1563 if (param == Byte.class || param == Byte.TYPE ) {
1564 ans[i] = new Byte(((Number)argument).byteValue());
1565 coerced = true; continue;
1566 }
1567 if (param == Double.class || param == Double.TYPE) {
1568 ans[i] = new Double(((Number)argument).doubleValue());
1569 coerced = true; continue;
1570 }
1571 if (param == Float.class || param == Float.TYPE) {
1572 ans[i] = new Float(((Number)argument).floatValue());
1573 coerced = true; continue;
1574 }
1575 if (param == Integer.class || param == Integer.TYPE) {
1576 ans[i] = new Integer(((Number)argument).intValue());
1577 coerced = true; continue;
1578 }
1579 if (param == Long.class || param == Long.TYPE) {
1580 ans[i] = new Long(((Number)argument).longValue());
1581 coerced = true; continue;
1582 }
1583 if (param == Short.class || param == Short.TYPE) {
1584 ans[i] = new Short(((Number)argument).shortValue());
1585 coerced = true; continue;
1586 }
1587 if (param == BigDecimal.class ) {
1588 ans[i] = new BigDecimal(((Number)argument).doubleValue());
1589 coerced = true; continue;
1590 }
1591 if (param == BigInteger.class) {
1592 ans[i] = new BigInteger(String.valueOf(((Number)argument).longValue()));
1593 coerced = true; continue;
1594 }
1595 }
1596 else if (param.isArray() && argument.getClass().isArray()) {
1597 Class paramElem = param.getComponentType();
1598 if (paramElem.isPrimitive()) {
1599 if (paramElem == boolean.class && argument.getClass().getName().equals("[Ljava.lang.Boolean;")) {
1600 ans[i] = InvokerHelper.convertToBooleanArray(argument);
1601 coerced = true;
1602 continue;
1603 }
1604 if (paramElem == byte.class && argument.getClass().getName().equals("[Ljava.lang.Byte;")) {
1605 ans[i] = InvokerHelper.convertToByteArray(argument);
1606 coerced = true;
1607 continue;
1608 }
1609 if (paramElem == char.class && argument.getClass().getName().equals("[Ljava.lang.Character;")) {
1610 ans[i] = InvokerHelper.convertToCharArray(argument);
1611 coerced = true;
1612 continue;
1613 }
1614 if (paramElem == short.class && argument.getClass().getName().equals("[Ljava.lang.Short;")) {
1615 ans[i] = InvokerHelper.convertToShortArray(argument);
1616 coerced = true;
1617 continue;
1618 }
1619 if (paramElem == int.class && argument.getClass().getName().equals("[Ljava.lang.Integer;")) {
1620 ans[i] = InvokerHelper.convertToIntArray(argument);
1621 coerced = true;
1622 continue;
1623 }
1624 if (paramElem == long.class
1625 && argument.getClass().getName().equals("[Ljava.lang.Long;")
1626 && argument.getClass().getName().equals("[Ljava.lang.Integer;")
1627 ) {
1628 ans[i] = InvokerHelper.convertToLongArray(argument);
1629 coerced = true;
1630 continue;
1631 }
1632 if (paramElem == float.class
1633 && argument.getClass().getName().equals("[Ljava.lang.Float;")
1634 && argument.getClass().getName().equals("[Ljava.lang.Integer;")
1635 ) {
1636 ans[i] = InvokerHelper.convertToFloatArray(argument);
1637 coerced = true;
1638 continue;
1639 }
1640 if (paramElem == double.class &&
1641 argument.getClass().getName().equals("[Ljava.lang.Double;") &&
1642 argument.getClass().getName().equals("[Ljava.lang.BigDecimal;") &&
1643 argument.getClass().getName().equals("[Ljava.lang.Float;")) {
1644 ans[i] = InvokerHelper.convertToDoubleArray(argument);
1645 coerced = true;
1646 continue;
1647 }
1648 }
1649 }
1650 }
1651 return coerced ? ans : null;
1652 }
1653
1654 protected Object doConstructorInvoke(Constructor constructor, Object[] argumentArray) {
1655
1656
1657
1658
1659 try {
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672 return constructor.newInstance(argumentArray);
1673 }
1674 catch (InvocationTargetException e) {
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684 throw new InvokerInvocationException(e);
1685 }
1686 catch (IllegalArgumentException e) {
1687 if (coerceGStrings(argumentArray)) {
1688 try {
1689 return constructor.newInstance(argumentArray);
1690 }
1691 catch (Exception e2) {
1692
1693 }
1694 }
1695 throw new GroovyRuntimeException(
1696 "failed to invoke constructor: "
1697 + constructor
1698 + " with arguments: "
1699 + InvokerHelper.toString(argumentArray)
1700 + " reason: "
1701 + e);
1702 }
1703 catch (IllegalAccessException e) {
1704 throw new GroovyRuntimeException(
1705 "could not access constructor: "
1706 + constructor
1707 + " with arguments: "
1708 + InvokerHelper.toString(argumentArray)
1709 + " reason: "
1710 + e);
1711 }
1712 catch (Exception e) {
1713 throw new GroovyRuntimeException(
1714 "failed to invoke constructor: "
1715 + constructor
1716 + " with arguments: "
1717 + InvokerHelper.toString(argumentArray)
1718 + " reason: "
1719 + e,
1720 e);
1721 }
1722 }
1723
1724 /***
1725 * Chooses the correct method to use from a list of methods which match by
1726 * name.
1727 *
1728 * @param methods
1729 * the possible methods to choose from
1730 * @param arguments
1731 * the original argument to the method
1732 * @return
1733 */
1734 protected Object chooseMethod(String methodName, List methods, Class[] arguments, boolean coerce) {
1735 int methodCount = methods.size();
1736 if (methodCount <= 0) {
1737 return null;
1738 }
1739 else if (methodCount == 1) {
1740 Object method = methods.get(0);
1741 if (isValidMethod(method, arguments, coerce)) {
1742 return method;
1743 }
1744 return null;
1745 }
1746 Object answer = null;
1747 if (arguments == null || arguments.length == 0) {
1748 answer = chooseEmptyMethodParams(methods);
1749 }
1750 else if (arguments.length == 1 && arguments[0] == null) {
1751 answer = chooseMostGeneralMethodWith1NullParam(methods);
1752 }
1753 else {
1754 List matchingMethods = new ArrayList();
1755
1756 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1757 Object method = iter.next();
1758 Class[] paramTypes;
1759
1760
1761 if (isValidMethod(method, arguments, coerce)) {
1762 matchingMethods.add(method);
1763 }
1764 }
1765 if (matchingMethods.isEmpty()) {
1766 return null;
1767 }
1768 else if (matchingMethods.size() == 1) {
1769 return matchingMethods.get(0);
1770 }
1771 return chooseMostSpecificParams(methodName, matchingMethods, arguments);
1772
1773 }
1774 if (answer != null) {
1775 return answer;
1776 }
1777 throw new GroovyRuntimeException(
1778 "Could not find which method to invoke from this list: "
1779 + methods
1780 + " for arguments: "
1781 + InvokerHelper.toString(arguments));
1782 }
1783
1784 protected boolean isValidMethod(Object method, Class[] arguments, boolean includeCoerce) {
1785 Class[] paramTypes = getParameterTypes(method);
1786 return isValidMethod(paramTypes, arguments, includeCoerce);
1787 }
1788
1789 public static boolean isValidMethod(Class[] paramTypes, Class[] arguments, boolean includeCoerce) {
1790 if (arguments == null) {
1791 return true;
1792 }
1793 int size = arguments.length;
1794 boolean validMethod = false;
1795 if (paramTypes.length == size) {
1796
1797 validMethod = true;
1798 for (int i = 0; i < size; i++) {
1799 if (!isCompatibleClass(paramTypes[i], arguments[i], includeCoerce)) {
1800 validMethod = false;
1801 }
1802 }
1803 }
1804 else {
1805 if (paramTypes.length == 1 && size == 0) {
1806 return true;
1807 }
1808 }
1809 return validMethod;
1810 }
1811
1812 private boolean implementsInterface (Class clazz, Class iface) {
1813 if (!iface.isInterface()) return false;
1814 return iface.isAssignableFrom(clazz);
1815 }
1816
1817 private boolean isSuperclass(Class claszz, Class superclass) {
1818 while (claszz!=null) {
1819 if (claszz==superclass) return true;
1820 claszz = claszz.getSuperclass();
1821 }
1822 return false;
1823 }
1824
1825 private Class[] wrap(Class[] classes) {
1826 Class[] wrappedArguments = new Class[classes.length];
1827 for (int i = 0; i < wrappedArguments.length; i++) {
1828 Class c = classes[i];
1829 if (c==null) continue;
1830 if (c.isPrimitive()) {
1831 if (c==Integer.TYPE) {
1832 c=Integer.class;
1833 } else if (c==Byte.TYPE) {
1834 c=Byte.class;
1835 } else if (c==Long.TYPE) {
1836 c=Long.class;
1837 } else if (c==Double.TYPE) {
1838 c=Double.class;
1839 } else if (c==Float.TYPE) {
1840 c=Float.class;
1841 }
1842 } else if (isSuperclass(c,GString.class)) {
1843 c = String.class;
1844 }
1845 wrappedArguments[i]=c;
1846 }
1847 return wrappedArguments;
1848 }
1849
1850 private boolean parametersAreCompatible(Class[] arguments, Class[] parameters) {
1851 if (arguments.length!=parameters.length) return false;
1852 for (int i=0; i<arguments.length; i++) {
1853 if (!isAssignableFrom(arguments[i],parameters[i])) return false;
1854 }
1855 return true;
1856 }
1857
1858 private int calculateParameterDistance(Class[] arguments, Class[] parameters) {
1859 int dist=0;
1860 for (int i=0; i<arguments.length; i++) {
1861 if (parameters[i]==arguments[i]) continue;
1862
1863 if (parameters[i].isInterface()) {
1864 dist+=2;
1865 continue;
1866 }
1867
1868 if (arguments[i]!=null) {
1869 if (arguments[i].isPrimitive() || parameters[i].isPrimitive()) {
1870
1871
1872 dist++;
1873 continue;
1874 }
1875
1876
1877 dist++;
1878 Class clazz = arguments[i];
1879 while (clazz!=null && clazz!=parameters[i]) {
1880 clazz = clazz.getSuperclass();
1881 dist+=2;
1882 }
1883 } else {
1884
1885
1886
1887
1888 dist--;
1889 Class clazz = parameters[i];
1890 while (clazz!=Object.class) {
1891 clazz = clazz.getSuperclass();
1892 dist+=2;
1893 }
1894 }
1895 }
1896 return dist;
1897 }
1898
1899
1900 protected Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
1901
1902 Class[] wrappedArguments = wrap(arguments);
1903
1904 int matchesDistance = -1;
1905 LinkedList matches = new LinkedList();
1906 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
1907 Object method = iter.next();
1908 Class[] paramTypes = getParameterTypes(method);
1909 if (!parametersAreCompatible(arguments, paramTypes)) continue;
1910 int dist = calculateParameterDistance(arguments, paramTypes);
1911 if (matches.size()==0) {
1912 matches.add(method);
1913 matchesDistance = dist;
1914 } else if (dist<matchesDistance) {
1915 matchesDistance=dist;
1916 matches.clear();
1917 matches.add(method);
1918 } else if (dist==matchesDistance) {
1919 matches.add(method);
1920 }
1921
1922 }
1923 if (matches.size()==1) {
1924 return matches.getFirst();
1925 }
1926 if (matches.size()==0) {
1927 return null;
1928 }
1929
1930
1931 String msg = "Ambiguous method overloading for method ";
1932 msg+= theClass.getName()+"#"+name;
1933 msg+= ".\nCannot resolve which method to invoke for ";
1934 msg+= InvokerHelper.toString(arguments);
1935 msg+= " due to overlapping prototypes between:";
1936 for (Iterator iter = matches.iterator(); iter.hasNext();) {
1937 Class[] types=getParameterTypes(iter.next());
1938 msg+= "\n\t"+InvokerHelper.toString(types);
1939 }
1940 throw new GroovyRuntimeException(msg);
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019 }
2020
2021 /***
2022 * Checks that one of the parameter types is a superset of the other and
2023 * that the two lists of types don't conflict. e.g. foo(String, Object) and
2024 * foo(Object, String) would conflict if called with foo("a", "b").
2025 *
2026 * Note that this method is only called with 2 possible signatures. i.e.
2027 * possible invalid combinations will already have been filtered out. So if
2028 * there were methods foo(String, Object) and foo(Object, String) then one
2029 * of these would be already filtered out if foo was called as foo(12, "a")
2030 */
2031 protected void checkForInvalidOverloading(String name, Class[] baseTypes, Class[] derivedTypes) {
2032 for (int i = 0, size = baseTypes.length; i < size; i++) {
2033 Class baseType = baseTypes[i];
2034 Class derivedType = derivedTypes[i];
2035 if (!isAssignableFrom(derivedType, baseType)) {
2036 throw new GroovyRuntimeException(
2037 "Ambiguous method overloading for method: "
2038 + name
2039 + ". Cannot resolve which method to invoke due to overlapping prototypes between: "
2040 + InvokerHelper.toString(baseTypes)
2041 + " and: "
2042 + InvokerHelper.toString(derivedTypes));
2043 }
2044 }
2045 }
2046
2047 protected Class[] getParameterTypes(Object methodOrConstructor) {
2048 if (methodOrConstructor instanceof MetaMethod) {
2049 MetaMethod method = (MetaMethod) methodOrConstructor;
2050 return method.getParameterTypes();
2051 }
2052 if (methodOrConstructor instanceof Method) {
2053 Method method = (Method) methodOrConstructor;
2054 return method.getParameterTypes();
2055 }
2056 if (methodOrConstructor instanceof Constructor) {
2057 Constructor constructor = (Constructor) methodOrConstructor;
2058 return constructor.getParameterTypes();
2059 }
2060 throw new IllegalArgumentException("Must be a Method or Constructor");
2061 }
2062
2063 /***
2064 * @return the method with 1 parameter which takes the most general type of
2065 * object (e.g. Object) ignoring primitve types
2066 */
2067 protected Object chooseMostGeneralMethodWith1NullParam(List methods) {
2068
2069
2070 Class closestClass = null;
2071 Object answer = null;
2072
2073 for (Iterator iter = methods.iterator(); iter.hasNext();) {
2074 Object method = iter.next();
2075 Class[] paramTypes = getParameterTypes(method);
2076 int paramLength = paramTypes.length;
2077 if (paramLength == 1) {
2078 Class theType = paramTypes[0];
2079 if (theType.isPrimitive()) continue;
2080 if (closestClass == null || isAssignableFrom(closestClass, theType)) {
2081 closestClass = theType;
2082 answer = method;
2083 }
2084 }
2085 }
2086 return answer;
2087 }
2088
2089 /***
2090 * @return the method with 1 parameter which takes the most general type of
2091 * object (e.g. Object)
2092 */
2093 protected Object chooseEmptyMethodParams(List methods) {
2094 for (Iterator iter = methods.iterator(); iter.hasNext();) {
2095 Object method = iter.next();
2096 Class[] paramTypes = getParameterTypes(method);
2097 int paramLength = paramTypes.length;
2098 if (paramLength == 0) {
2099 return method;
2100 }
2101 }
2102 return null;
2103 }
2104
2105 protected static boolean isCompatibleInstance(Class type, Object value, boolean includeCoerce) {
2106 boolean answer = value == null || type.isInstance(value);
2107 if (!answer) {
2108 if (type.isPrimitive()) {
2109 if (type == int.class) {
2110 return value instanceof Integer;
2111 }
2112 else if (type == double.class) {
2113 return value instanceof Double || value instanceof Float || value instanceof Integer || value instanceof BigDecimal;
2114 }
2115 else if (type == boolean.class) {
2116 return value instanceof Boolean;
2117 }
2118 else if (type == long.class) {
2119 return value instanceof Long || value instanceof Integer;
2120 }
2121 else if (type == float.class) {
2122 return value instanceof Float || value instanceof Integer;
2123 }
2124 else if (type == char.class) {
2125 return value instanceof Character;
2126 }
2127 else if (type == byte.class) {
2128 return value instanceof Byte;
2129 }
2130 else if (type == short.class) {
2131 return value instanceof Short;
2132 }
2133 }
2134 else if(type.isArray() && value.getClass().isArray()) {
2135 return isCompatibleClass(type.getComponentType(), value.getClass().getComponentType(), false);
2136 }
2137 else if (includeCoerce) {
2138 if (type == String.class && value instanceof GString) {
2139 return true;
2140 }
2141 else if (value instanceof Number) {
2142
2143 return Number.class.isAssignableFrom(type);
2144 }
2145 }
2146 }
2147 return answer;
2148 }
2149 protected static boolean isCompatibleClass(Class type, Class value, boolean includeCoerce) {
2150 boolean answer = value == null || type.isAssignableFrom(value);
2151 if (!answer) {
2152 if (type.isPrimitive()) {
2153 if (type == int.class) {
2154 return value == Integer.class;
2155 }
2156 else if (type == double.class) {
2157 return value == Double.class || value == Float.class || value == Integer.class || value == BigDecimal.class;
2158 }
2159 else if (type == boolean.class) {
2160 return value == Boolean.class;
2161 }
2162 else if (type == long.class) {
2163 return value == Long.class || value == Integer.class;
2164 }
2165 else if (type == float.class) {
2166 return value == Float.class || value == Integer.class;
2167 }
2168 else if (type == char.class) {
2169 return value == Character.class;
2170 }
2171 else if (type == byte.class) {
2172 return value == Byte.class;
2173 }
2174 else if (type == short.class) {
2175 return value == Short.class;
2176 }
2177 } else if (type.isArray() && value.isArray()) {
2178 return isCompatibleClass(type.getComponentType(), value.getComponentType(), false);
2179 }
2180 else if (includeCoerce) {
2181
2182 if (type == String.class && GString.class.isAssignableFrom(value)) {
2183 return true;
2184 }
2185 else if (value == Number.class) {
2186
2187 return Number.class.isAssignableFrom(type);
2188 }
2189 }
2190 }
2191 return answer;
2192 }
2193
2194 protected boolean isAssignableFrom(Class mostSpecificType, Class type) {
2195 if (mostSpecificType==null) return true;
2196
2197 if (mostSpecificType.isPrimitive() && type.isPrimitive()) {
2198 if (mostSpecificType == type) {
2199 return true;
2200 }
2201 else {
2202 if (type == int.class) {
2203 return
2204 mostSpecificType == int.class
2205 || mostSpecificType == short.class
2206 || mostSpecificType == byte.class;
2207 }
2208 else if (type == double.class) {
2209 return
2210 mostSpecificType == double.class
2211 || mostSpecificType == int.class
2212 || mostSpecificType == long.class
2213 || mostSpecificType == short.class
2214 || mostSpecificType == byte.class
2215 || mostSpecificType == float.class;
2216 }
2217 else if (type == long.class) {
2218 return
2219 mostSpecificType == long.class
2220 || mostSpecificType == int.class
2221 || mostSpecificType == short.class
2222 || mostSpecificType == byte.class;
2223 }
2224 else if (type == float.class) {
2225 return
2226 mostSpecificType == float.class
2227 || mostSpecificType == int.class
2228 || mostSpecificType == long.class
2229 || mostSpecificType == short.class
2230 || mostSpecificType == byte.class;
2231 }
2232 else if (type == short.class) {
2233 return
2234 mostSpecificType == short.class
2235 || mostSpecificType == byte.class;
2236 }
2237 else {
2238 return false;
2239 }
2240 }
2241 }
2242 if (type==String.class) {
2243 return mostSpecificType == String.class ||
2244 GString.class.isAssignableFrom(mostSpecificType);
2245 }
2246
2247 boolean answer = type.isAssignableFrom(mostSpecificType);
2248 if (!answer) {
2249 answer = autoboxType(type).isAssignableFrom(autoboxType(mostSpecificType));
2250 }
2251 return answer;
2252 }
2253
2254 private Class autoboxType(Class type) {
2255 if (type.isPrimitive()) {
2256 if (type == int.class) {
2257 return Integer.class;
2258 }
2259 else if (type == double.class) {
2260 return Double.class;
2261 }
2262 else if (type == long.class) {
2263 return Long.class;
2264 }
2265 else if (type == boolean.class) {
2266 return Boolean.class;
2267 }
2268 else if (type == float.class) {
2269 return Float.class;
2270 }
2271 else if (type == char.class) {
2272 return Character.class;
2273 }
2274 else if (type == byte.class) {
2275 return Byte.class;
2276 }
2277 else if (type == short.class) {
2278 return Short.class;
2279 }
2280 }
2281 return type;
2282 }
2283
2284 /***
2285 * Coerces any GString instances into Strings
2286 *
2287 * @return true if some coercion was done.
2288 */
2289 protected static boolean coerceGStrings(Object[] arguments) {
2290 boolean coerced = false;
2291 for (int i = 0, size = arguments.length; i < size; i++) {
2292 Object argument = arguments[i];
2293 if (argument instanceof GString) {
2294 arguments[i] = argument.toString();
2295 coerced = true;
2296 }
2297 }
2298 return coerced;
2299 }
2300
2301 protected boolean isGenericSetMethod(MetaMethod method) {
2302 return (method.getName().equals("set"))
2303 && method.getParameterTypes().length == 2;
2304 }
2305
2306 protected boolean isGenericGetMethod(MetaMethod method) {
2307 if (method.getName().equals("get")) {
2308 Class[] parameterTypes = method.getParameterTypes();
2309 return parameterTypes.length == 1 && parameterTypes[0] == String.class;
2310 }
2311 return false;
2312 }
2313
2314 private void registerMethods(boolean instanceMethods) {
2315 Method[] methods = theClass.getMethods();
2316 for (int i = 0; i < methods.length; i++) {
2317 Method method = methods[i];
2318 if (MethodHelper.isStatic(method)) {
2319 Class[] paramTypes = method.getParameterTypes();
2320 if (paramTypes.length > 0) {
2321 Class owner = paramTypes[0];
2322 if (instanceMethods) {
2323 registry.lookup(owner).addNewInstanceMethod(method);
2324 } else {
2325 registry.lookup(owner).addNewStaticMethod(method);
2326 }
2327 }
2328 }
2329 }
2330 }
2331
2332 protected void registerStaticMethods() {
2333 registerMethods(false);
2334 }
2335
2336 protected void registerInstanceMethods() {
2337 registerMethods(true);
2338 }
2339
2340 protected String capitalize(String property) {
2341 return property.substring(0, 1).toUpperCase() + property.substring(1, property.length());
2342 }
2343
2344 /***
2345 * Call this method when any mutation method is called, such as adding a new
2346 * method to this MetaClass so that any caching or bytecode generation can be
2347 * regenerated.
2348 */
2349 protected synchronized void onMethodChange() {
2350 reflector = null;
2351 }
2352
2353 protected synchronized void checkInitialised() {
2354 if (!initialised) {
2355 initialised = true;
2356 addInheritedMethods();
2357 }
2358 if (reflector == null) {
2359 generateReflector();
2360 }
2361 }
2362
2363 protected MetaMethod createMetaMethod(final Method method) {
2364 if (registry.useAccessible()) {
2365 AccessController.doPrivileged(new PrivilegedAction() {
2366 public Object run() {
2367 method.setAccessible(true);
2368 return null;
2369 }
2370 });
2371 }
2372
2373 MetaMethod answer = new MetaMethod(method);
2374 if (isValidReflectorMethod(answer)) {
2375 allMethods.add(answer);
2376 answer.setMethodIndex(allMethods.size());
2377 }
2378 else {
2379
2380 answer = new ReflectionMetaMethod(method);
2381 }
2382
2383 if (useReflection) {
2384
2385 return new ReflectionMetaMethod(method);
2386 }
2387
2388 return answer;
2389 }
2390
2391 protected boolean isValidReflectorMethod(MetaMethod method) {
2392
2393 if (!method.isPublic()) {
2394 return false;
2395 }
2396
2397 List interfaceMethods = getInterfaceMethods();
2398 for (Iterator iter = interfaceMethods.iterator(); iter.hasNext();) {
2399 MetaMethod aMethod = (MetaMethod) iter.next();
2400 if (method.isSame(aMethod)) {
2401 method.setInterfaceClass(aMethod.getDeclaringClass());
2402 return true;
2403 }
2404 }
2405
2406
2407 Class declaringClass = method.getDeclaringClass();
2408 for (Class clazz=declaringClass; clazz!=null; clazz=clazz.getSuperclass()) {
2409 try {
2410 final Class klazz = clazz;
2411 final String mName = method.getName();
2412 final Class[] parms = method.getParameterTypes();
2413 try {
2414 Method m = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
2415 public Object run() throws NoSuchMethodException {
2416 return klazz.getDeclaredMethod(mName, parms);
2417 }
2418 });
2419 if (!Modifier.isPublic(clazz.getModifiers())) continue;
2420 if (!Modifier.isPublic(m.getModifiers())) continue;
2421 declaringClass = clazz;
2422 } catch (PrivilegedActionException pae) {
2423 if (pae.getException() instanceof NoSuchMethodException) {
2424 throw (NoSuchMethodException) pae.getException();
2425 } else {
2426 throw new RuntimeException(pae.getException());
2427 }
2428 }
2429 } catch (SecurityException e) {
2430 continue;
2431 } catch (NoSuchMethodException e) {
2432 continue;
2433 }
2434 }
2435 if (!Modifier.isPublic(declaringClass.getModifiers())) return false;
2436 method.setDeclaringClass(declaringClass);
2437
2438 return true;
2439 }
2440
2441 protected void generateReflector() {
2442 reflector = loadReflector(allMethods);
2443 if (reflector == null) {
2444 throw new RuntimeException("Should have a reflector for "+theClass.getName());
2445 }
2446
2447 for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
2448 MetaMethod metaMethod = (MetaMethod) iter.next();
2449
2450 metaMethod.setReflector(reflector);
2451 }
2452 }
2453
2454 private String getReflectorName() {
2455 String className = theClass.getName();
2456 String packagePrefix = "gjdk.";
2457 String name = packagePrefix + className + "_GroovyReflector";
2458 if (theClass.isArray()) {
2459 String componentName = theClass.getComponentType().getName();
2460 name = packagePrefix + componentName + "_GroovyReflectorArray";
2461 }
2462 return name;
2463 }
2464
2465 protected Reflector loadReflector(List methods) {
2466 ReflectorGenerator generator = new ReflectorGenerator(methods);
2467 String name = getReflectorName();
2468
2469
2470
2471 try {
2472 Class type = loadReflectorClass(name);
2473 return (Reflector) type.newInstance();
2474 }
2475 catch (ClassNotFoundException cnfe) {
2476
2477
2478
2479 try {
2480 ClassWriter cw = new ClassWriter(true);
2481 generator.generate(cw, name);
2482 byte[] bytecode = cw.toByteArray();
2483 Class type = loadReflectorClass(name, bytecode);
2484 return (Reflector) type.newInstance();
2485 }
2486 catch (Exception e) {
2487 throw new GroovyRuntimeException("Could not generate and load the reflector for class: " + name + ". Reason: " + e, e);
2488 }
2489 }
2490 catch (Throwable t) {
2491
2492
2493
2494 throw new GroovyRuntimeException("Could not load the reflector for class: " + name + ". Reason: " + t, t);
2495 }
2496 }
2497
2498 protected Class loadReflectorClass(final String name, final byte[] bytecode) throws ClassNotFoundException {
2499 ClassLoader loader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
2500 public Object run() {
2501 return theClass.getClassLoader();
2502 }
2503 });
2504 if (loader instanceof GroovyClassLoader) {
2505 final GroovyClassLoader gloader = (GroovyClassLoader) loader;
2506 return (Class) AccessController.doPrivileged(new PrivilegedAction() {
2507 public Object run() {
2508 return gloader.defineClass(name, bytecode, getClass().getProtectionDomain());
2509 }
2510 });
2511 }
2512 return registry.loadClass(loader, name, bytecode);
2513 }
2514
2515 protected Class loadReflectorClass(String name) throws ClassNotFoundException {
2516 ClassLoader loader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
2517 public Object run() {
2518 return theClass.getClassLoader();
2519 }
2520 });
2521 if (loader instanceof GroovyClassLoader) {
2522 GroovyClassLoader gloader = (GroovyClassLoader) loader;
2523 return gloader.loadClass(name);
2524 }
2525 return registry.loadClass(loader, name);
2526 }
2527
2528 public List getMethods() {
2529 return allMethods;
2530 }
2531
2532 public List getMetaMethods() {
2533 return new ArrayList(newGroovyMethodsList);
2534 }
2535
2536 protected synchronized List getInterfaceMethods() {
2537 if (interfaceMethods == null) {
2538 interfaceMethods = new ArrayList();
2539 Class type = theClass;
2540 while (type != null) {
2541 Class[] interfaces = type.getInterfaces();
2542 for (int i = 0; i < interfaces.length; i++) {
2543 Class iface = interfaces[i];
2544 Method[] methods = iface.getMethods();
2545 addInterfaceMethods(interfaceMethods, methods);
2546 }
2547 type = type.getSuperclass();
2548 }
2549 }
2550 return interfaceMethods;
2551 }
2552
2553 private void addInterfaceMethods(List list, Method[] methods) {
2554 for (int i = 0; i < methods.length; i++) {
2555 list.add(createMetaMethod(methods[i]));
2556 }
2557 }
2558
2559 /***
2560 * param instance array to the type array
2561 * @param args
2562 * @return
2563 */
2564 Class[] convertToTypeArray(Object[] args) {
2565 if (args == null)
2566 return null;
2567 int s = args.length;
2568 Class[] ans = new Class[s];
2569 for (int i = 0; i < s; i++) {
2570 Object o = args[i];
2571 if (o != null) {
2572 ans[i] = o.getClass();
2573 } else {
2574 ans[i] = null;
2575 }
2576 }
2577 return ans;
2578 }
2579
2580 }