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.Method;
57 import java.lang.reflect.Modifier;
58 import java.net.URL;
59 import java.security.AccessController;
60 import java.security.PrivilegedAction;
61 import java.security.PrivilegedActionException;
62 import java.security.PrivilegedExceptionAction;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.Collection;
66 import java.util.Collections;
67 import java.util.HashMap;
68 import java.util.Iterator;
69 import java.util.LinkedList;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.logging.Level;
73
74 import org.codehaus.groovy.ast.ClassNode;
75 import org.codehaus.groovy.classgen.ReflectorGenerator;
76 import org.codehaus.groovy.control.CompilationUnit;
77 import org.codehaus.groovy.control.CompilerConfiguration;
78 import org.codehaus.groovy.control.Phases;
79 import org.codehaus.groovy.runtime.CurriedClosure;
80 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
81 import org.codehaus.groovy.runtime.GroovyCategorySupport;
82 import org.codehaus.groovy.runtime.Invoker;
83 import org.codehaus.groovy.runtime.InvokerHelper;
84 import org.codehaus.groovy.runtime.MetaClassHelper;
85 import org.codehaus.groovy.runtime.MethodClosure;
86 import org.codehaus.groovy.runtime.MethodKey;
87 import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
88 import org.codehaus.groovy.runtime.NewStaticMetaMethod;
89 import org.codehaus.groovy.runtime.ReflectionMetaMethod;
90 import org.codehaus.groovy.runtime.Reflector;
91 import org.codehaus.groovy.runtime.TemporaryMethodKey;
92 import org.codehaus.groovy.runtime.TransformMetaMethod;
93 import org.codehaus.groovy.runtime.wrappers.Wrapper;
94 import org.objectweb.asm.ClassVisitor;
95 import org.objectweb.asm.ClassWriter;
96
97 /***
98 * Allows methods to be dynamically added to existing classes at runtime
99 *
100 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
101 * @author Guillaume Laforge
102 * @author Jochen Theodorou
103 * @version $Revision: 1.18 $
104 */
105 public class MetaClassImpl extends MetaClass {
106
107 protected MetaClassRegistry registry;
108 private ClassNode classNode;
109 private Map methodIndex = new HashMap();
110 private Map staticMethodIndex = new HashMap();
111
112 private Map propertyMap = Collections.synchronizedMap(new HashMap());
113 private Map listeners = new HashMap();
114 private Map methodCache = Collections.synchronizedMap(new HashMap());
115 private Map staticMethodCache = Collections.synchronizedMap(new HashMap());
116 private MetaMethod genericGetMethod;
117 private MetaMethod genericSetMethod;
118 private List constructors;
119 private List allMethods = new ArrayList();
120 private List interfaceMethods;
121 private Reflector reflector;
122 private boolean initialised;
123
124 private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
125 private final static MetaMethod AMBIGOUS_LISTENER_METHOD = new MetaMethod(null,null,new Class[]{},null,0);
126 private static final Object[] EMPTY_ARGUMENTS = {};
127
128 public MetaClassImpl(MetaClassRegistry registry, final Class theClass) throws IntrospectionException {
129 super(theClass);
130 this.registry = registry;
131
132 constructors = (List) AccessController.doPrivileged(new PrivilegedAction() {
133 public Object run() {
134 return Arrays.asList (theClass.getDeclaredConstructors());
135 }
136 });
137
138 addMethods(theClass,true);
139
140
141 BeanInfo info = null;
142 try {
143 info =(BeanInfo) AccessController.doPrivileged(new PrivilegedExceptionAction() {
144 public Object run() throws IntrospectionException {
145 return Introspector.getBeanInfo(theClass);
146 }
147 });
148 } catch (PrivilegedActionException pae) {
149 if (pae.getException() instanceof IntrospectionException) {
150 throw (IntrospectionException) pae.getException();
151 } else {
152 throw new RuntimeException(pae.getException());
153 }
154 }
155
156 PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
157
158
159
160 setupProperties(descriptors);
161
162
163
164
165
166
167
168
169 EventSetDescriptor[] eventDescriptors = info.getEventSetDescriptors();
170 for (int i = 0; i < eventDescriptors.length; i++) {
171 EventSetDescriptor descriptor = eventDescriptors[i];
172 Method[] listenerMethods = descriptor.getListenerMethods();
173 for (int j = 0; j < listenerMethods.length; j++) {
174 Method listenerMethod = listenerMethods[j];
175 MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod());
176 String name = listenerMethod.getName();
177 if (listeners.containsKey(name)) {
178 listeners.put(name, AMBIGOUS_LISTENER_METHOD);
179 } else{
180 listeners.put(name, metaMethod);
181 }
182 }
183 }
184 }
185
186 private void addInheritedMethods() {
187 LinkedList superClasses = new LinkedList();
188 for (Class c = theClass.getSuperclass(); c!=Object.class && c!= null; c = c.getSuperclass()) {
189 superClasses.addFirst(c);
190 }
191
192 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
193 Class c = (Class) iter.next();
194 addMethods(c,true);
195 addNewStaticMethodsFrom(c);
196 }
197
198
199 Class[] interfaces = theClass.getInterfaces();
200 for (int i = 0; i < interfaces.length; i++) {
201 addNewStaticMethodsFrom(interfaces[i]);
202 }
203
204
205
206 if (theClass != Object.class) {
207 addMethods(Object.class, false);
208 addNewStaticMethodsFrom(Object.class);
209 }
210
211 if (theClass.isArray() && !theClass.equals(Object[].class)) {
212 addNewStaticMethodsFrom(Object[].class);
213 }
214 }
215
216 /***
217 * @return all the normal instance methods avaiable on this class for the
218 * given name
219 */
220 private List getMethods(String name) {
221 List answer = (List) methodIndex.get(name);
222 List used = GroovyCategorySupport.getCategoryMethods(theClass, name);
223 if (used != null) {
224 if (answer != null) {
225 used.addAll(answer);
226 }
227 answer = used;
228 }
229 if (answer == null) {
230 answer = Collections.EMPTY_LIST;
231 }
232 return answer;
233 }
234
235 /***
236 * @return all the normal static methods avaiable on this class for the
237 * given name
238 */
239 private List getStaticMethods(String name) {
240 List answer = (List) staticMethodIndex.get(name);
241 if (answer == null) {
242 return Collections.EMPTY_LIST;
243 }
244 return answer;
245 }
246
247 /***
248 * Allows static method definitions to be added to a meta class as if it
249 * was an instance method
250 *
251 * @param method
252 */
253 public void addNewInstanceMethod(Method method) {
254 if (initialised) {
255 throw new RuntimeException("Already initialized, cannot add new method: " + method);
256 }
257 else {
258 NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method));
259 if (! newGroovyMethodsList.contains(newMethod)){
260 newGroovyMethodsList.add(newMethod);
261 addMethod(newMethod,false);
262 }
263 }
264 }
265
266 public void addNewStaticMethod(Method method) {
267 if (initialised) {
268 throw new RuntimeException("Already initialized, cannot add new method: " + method);
269 }
270 else {
271 NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method));
272 if (! newGroovyMethodsList.contains(newMethod)){
273 newGroovyMethodsList.add(newMethod);
274 addMethod(newMethod,false);
275 }
276 }
277 }
278
279 /***
280 * Invokes the given method on the object.
281 *
282 */
283 public Object invokeMethod(Object object, String methodName, Object[] arguments) {
284 if (object == null) {
285 throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
286 }
287 if (log.isLoggable(Level.FINER)){
288 MetaClassHelper.logMethodCall(object, methodName, arguments);
289 }
290 if (arguments==null) arguments = EMPTY_ARGUMENTS;
291
292
293
294
295
296 for (int i = 0; i != arguments.length; i++) {
297 if (arguments[i] instanceof Wrapper) {
298 arguments[i] = ((Wrapper)arguments[i]).unwrap();
299 }
300 }
301
302 MetaMethod method = retrieveMethod(object, methodName, arguments);
303
304 boolean isClosure = object instanceof Closure;
305 if (isClosure) {
306 Closure closure = (Closure) object;
307 Object delegate = closure.getDelegate();
308 Object owner = closure.getOwner();
309
310 if ("call".equals(methodName) || "doCall".equals(methodName)) {
311 if (object.getClass()==MethodClosure.class) {
312 MethodClosure mc = (MethodClosure) object;
313 methodName = mc.getMethod();
314 MetaClass ownerMetaClass = registry.getMetaClass(owner.getClass());
315 return ownerMetaClass.invokeMethod(owner,methodName,arguments);
316 } else if (object.getClass()==CurriedClosure.class) {
317 CurriedClosure cc = (CurriedClosure) object;
318
319 arguments = cc.getUncurriedArguments(arguments);
320 MetaClass ownerMetaClass = registry.getMetaClass(owner.getClass());
321 return ownerMetaClass.invokeMethod(owner,methodName,arguments);
322 }
323 } else if ("curry".equals(methodName)) {
324 return closure.curry(arguments);
325 }
326
327 if (method==null && owner!=closure) {
328 MetaClass ownerMetaClass = registry.getMetaClass(owner.getClass());
329 method = ownerMetaClass.retrieveMethod(owner,methodName,arguments);
330 if (method!=null) return ownerMetaClass.invokeMethod(owner,methodName,arguments);
331 }
332 if (method==null && delegate!=closure && delegate!=null) {
333 MetaClass delegateMetaClass = registry.getMetaClass(delegate.getClass());
334 method = delegateMetaClass.retrieveMethod(delegate,methodName,arguments);
335 if (method!=null) return delegateMetaClass.invokeMethod(delegate,methodName,arguments);
336 }
337 if (method==null) {
338
339
340 MissingMethodException last = null;
341 if (owner!=closure && (owner instanceof GroovyObject)) {
342 try {
343 GroovyObject go = (GroovyObject) owner;
344 return go.invokeMethod(methodName,arguments);
345 } catch (MissingMethodException mme) {
346 if (last==null) last = mme;
347 }
348 }
349 if (delegate!=closure && (delegate instanceof GroovyObject)) {
350 try {
351 GroovyObject go = (GroovyObject) delegate;
352 return go.invokeMethod(methodName,arguments);
353 } catch (MissingMethodException mme) {
354 last = mme;
355 }
356 }
357 if (last!=null) throw last;
358 }
359
360 }
361
362 if (method != null) {
363 return MetaClassHelper.doMethodInvoke(object, method, arguments);
364 } else {
365
366 try {
367 Object value = this.getProperty(object, methodName);
368 if (value instanceof Closure) {
369 Closure closure = (Closure) value;
370 MetaClass delegateMetaClass = registry.getMetaClass(closure.getClass());
371 return delegateMetaClass.invokeMethod(closure,"doCall",arguments);
372 }
373 } catch (MissingPropertyException mpe) {}
374
375 throw new MissingMethodException(methodName, theClass, arguments);
376 }
377 }
378
379 public MetaMethod retrieveMethod(Object owner, String methodName, Object[] arguments) {
380
381 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
382 MetaMethod method = (MetaMethod) methodCache.get(methodKey);
383 if (method == null) {
384 method = pickMethod(owner, methodName, arguments);
385 if (method != null && method.isCacheable()) {
386 methodCache.put(methodKey.createCopy(), method);
387 }
388 }
389 return method;
390 }
391
392 public MetaMethod retrieveMethod(String methodName, Class[] arguments) {
393
394 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
395 MetaMethod method = (MetaMethod) methodCache.get(methodKey);
396 if (method == null) {
397 method = pickMethod(methodName, arguments);
398 if (method != null && method.isCacheable()) {
399 methodCache.put(methodKey.createCopy(), method);
400 }
401 }
402 return method;
403 }
404
405 public Constructor retrieveConstructor(Class[] arguments) {
406 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, arguments, false);
407 if (constructor != null) {
408 return constructor;
409 }
410 else {
411 constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
412 if (constructor != null) {
413 return constructor;
414 }
415 }
416 return null;
417 }
418
419 public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
420 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
421 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
422 if (method == null) {
423 method = pickStaticMethod(methodName, arguments);
424 if (method != null) {
425 staticMethodCache.put(methodKey.createCopy(), method);
426 }
427 }
428 return method;
429 }
430 /***
431 * Picks which method to invoke for the given object, method name and arguments
432 */
433 public MetaMethod pickMethod(Object object, String methodName, Object[] arguments) {
434 MetaMethod method = null;
435 List methods = getMethods(methodName);
436 if (!methods.isEmpty()) {
437 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
438 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
439 if (method == null) {
440 int size = (arguments != null) ? arguments.length : 0;
441 if (size == 1) {
442 Object firstArgument = arguments[0];
443 if (firstArgument instanceof List) {
444
445
446
447
448 List list = (List) firstArgument;
449 arguments = list.toArray();
450 argClasses = MetaClassHelper.convertToTypeArray(arguments);
451 method = (MetaMethod) chooseMethod(methodName, methods, argClasses, true);
452 if (method==null) return null;
453 return new TransformMetaMethod(method) {
454 public Object invoke(Object object, Object[] arguments) throws Exception {
455 Object firstArgument = arguments[0];
456 List list = (List) firstArgument;
457 arguments = list.toArray();
458 return super.invoke(object, arguments);
459 }
460 };
461 }
462 }
463 }
464 }
465 return method;
466 }
467
468 /***
469 * pick a method in a strict manner, i.e., without reinterpreting the first List argument.
470 * this method is used only by ClassGenerator for static binding
471 * @param methodName
472 * @param arguments
473 * @return
474 */
475 public MetaMethod pickMethod(String methodName, Class[] arguments) {
476 MetaMethod method = null;
477 List methods = getMethods(methodName);
478 if (!methods.isEmpty()) {
479 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
480
481
482
483
484 }
485 return method;
486 }
487
488 public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
489 if (log.isLoggable(Level.FINER)){
490 MetaClassHelper.logMethodCall(object, methodName, arguments);
491 }
492 if (arguments==null) arguments = EMPTY_ARGUMENTS;
493
494 MethodKey methodKey = new TemporaryMethodKey(methodName, arguments);
495 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
496 if (method == null) {
497 method = pickStaticMethod(object, methodName, arguments);
498 if (method != null) {
499 staticMethodCache.put(methodKey.createCopy(), method);
500 }
501 }
502
503 if (method != null) {
504 return MetaClassHelper.doMethodInvoke(object, method, arguments);
505 }
506
507 throw new MissingMethodException(methodName, theClass, arguments);
508 }
509
510 private MetaMethod pickStaticMethod(Object object, String methodName, Object[] arguments) {
511 MetaMethod method = null;
512 List methods = getStaticMethods(methodName);
513
514 if (!methods.isEmpty()) {
515 method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), false);
516 }
517
518 if (method == null && theClass != Class.class) {
519 MetaClass classMetaClass = registry.getMetaClass(Class.class);
520 method = classMetaClass.pickMethod(object, methodName, arguments);
521 }
522 if (method == null) {
523 method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), true);
524 }
525 return method;
526 }
527
528 private MetaMethod pickStaticMethod(String methodName, Class[] arguments) {
529 MetaMethod method = null;
530 List methods = getStaticMethods(methodName);
531
532 if (!methods.isEmpty()) {
533 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
534
535
536
537
538 }
539
540 if (method == null && theClass != Class.class) {
541 MetaClass classMetaClass = registry.getMetaClass(Class.class);
542 method = classMetaClass.pickMethod(methodName, arguments);
543 }
544 return method;
545 }
546
547 public Object invokeConstructor(Object[] arguments) {
548 if (arguments==null) arguments = EMPTY_ARGUMENTS;
549 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
550 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
551 if (constructor != null) {
552 return MetaClassHelper.doConstructorInvoke(constructor, arguments);
553 }
554 else {
555 constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
556 if (constructor != null) {
557 return MetaClassHelper.doConstructorInvoke(constructor, arguments);
558 }
559 }
560
561 if (arguments.length == 1) {
562 Object firstArgument = arguments[0];
563 if (firstArgument instanceof Map) {
564 constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
565 if (constructor != null) {
566 Object bean = MetaClassHelper.doConstructorInvoke(constructor, MetaClassHelper.EMPTY_ARRAY);
567 setProperties(bean, ((Map) firstArgument));
568 return bean;
569 }
570 }
571 }
572 throw new GroovyRuntimeException(
573 "Could not find matching constructor for: "
574 + theClass.getName()
575 + "("+InvokerHelper.toTypeString(arguments)+")");
576 }
577
578 public Object invokeConstructorAt(Class at, Object[] arguments) {
579 if (arguments==null) arguments = EMPTY_ARGUMENTS;
580 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
581 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
582 if (constructor != null) {
583 return doConstructorInvokeAt(at, constructor, arguments);
584 }
585 else {
586 constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
587 if (constructor != null) {
588 return doConstructorInvokeAt(at, constructor, arguments);
589 }
590 }
591
592 if (arguments.length == 1) {
593 Object firstArgument = arguments[0];
594 if (firstArgument instanceof Map) {
595 constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
596 if (constructor != null) {
597 Object bean = doConstructorInvokeAt(at, constructor, MetaClassHelper.EMPTY_ARRAY);
598 setProperties(bean, ((Map) firstArgument));
599 return bean;
600 }
601 }
602 }
603 throw new GroovyRuntimeException(
604 "Could not find matching constructor for: "
605 + theClass.getName()
606 + "("+InvokerHelper.toTypeString(arguments)+")");
607 }
608
609 /***
610 * Sets a number of bean properties from the given Map where the keys are
611 * the String names of properties and the values are the values of the
612 * properties to set
613 */
614 public void setProperties(Object bean, Map map) {
615 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
616 Map.Entry entry = (Map.Entry) iter.next();
617 String key = entry.getKey().toString();
618
619 Object value = entry.getValue();
620 try {
621 setProperty(bean, key, value);
622 }
623 catch (GroovyRuntimeException e) {
624
625 /*** todo should replace this code with a getMetaProperty(key) != null check
626 i.e. don't try and set a non-existent property
627 */
628 }
629 }
630 }
631
632 /***
633 * @return the given property's value on the object
634 */
635 public Object getProperty(final Object object, final String property) {
636
637 MetaProperty mp = (MetaProperty) propertyMap.get(property);
638 if (mp != null) {
639 try {
640
641
642
643 return mp.getProperty(object);
644 }
645 catch(Exception e) {
646 throw new GroovyRuntimeException("Cannot read property: " + property);
647 }
648 }
649
650 if (genericGetMethod == null) {
651
652 List possibleGenericMethods = getMethods("get");
653 if (possibleGenericMethods != null) {
654 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
655 MetaMethod mmethod = (MetaMethod) i.next();
656 Class[] paramTypes = mmethod.getParameterTypes();
657 if (paramTypes.length == 1 && paramTypes[0] == String.class) {
658 Object[] arguments = {property};
659 Object answer = MetaClassHelper.doMethodInvoke(object, mmethod, arguments);
660 return answer;
661 }
662 }
663 }
664 }
665 else {
666 Object[] arguments = { property };
667 Object answer = MetaClassHelper.doMethodInvoke(object, genericGetMethod, arguments);
668
669 if (answer != null) {
670 return answer;
671 }
672 }
673
674 if (!CompilerConfiguration.isJsrGroovy()) {
675
676
677 List methods = getMethods(property);
678 if (!methods.isEmpty()) {
679 return new MethodClosure(object, property);
680 }
681 }
682
683
684
685 Exception lastException = null;
686 try {
687 if ( !(object instanceof Class) ) {
688 MetaMethod method = findGetter(object, "get" + MetaClassHelper.capitalize(property));
689 if (method != null) {
690 return MetaClassHelper.doMethodInvoke(object, method, MetaClassHelper.EMPTY_ARRAY);
691 }
692 }
693 }
694 catch (GroovyRuntimeException e) {
695 lastException = e;
696 }
697
698 /*** todo or are we an extensible groovy class? */
699 if (genericGetMethod != null) {
700 return null;
701 }
702 else {
703 /*** todo these special cases should be special MetaClasses maybe */
704 if (object instanceof Class) {
705
706 return getStaticProperty((Class) object, property);
707 }
708 if (object instanceof Collection) {
709 return DefaultGroovyMethods.getAt((Collection) object, property);
710 }
711 if (object instanceof Object[]) {
712 return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), property);
713 }
714 if (object instanceof Object) {
715 try {
716 return getAttribute(object,property);
717 } catch (MissingFieldException mfe) {
718
719 }
720 }
721
722 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
723 if (addListenerMethod != null) {
724
725 return null;
726 }
727
728 if (lastException == null)
729 throw new MissingPropertyException(property, theClass);
730 else
731 throw new MissingPropertyException(property, theClass, lastException);
732 }
733 }
734
735 /***
736 * Get all the properties defined for this type
737 * @return a list of MetaProperty objects
738 */
739 public List getProperties() {
740
741 return new ArrayList(propertyMap.values());
742 }
743
744 /***
745 * This will build up the property map (Map of MetaProperty objects, keyed on
746 * property name).
747 */
748 private void setupProperties(PropertyDescriptor[] propertyDescriptors) {
749 MetaProperty mp;
750 Method method;
751 MetaMethod getter = null;
752 MetaMethod setter = null;
753 Class klass;
754
755
756 klass = theClass;
757 while(klass != null) {
758 final Class clazz = klass;
759 Field[] fields = (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
760 public Object run() {
761 return clazz.getDeclaredFields();
762 }
763 });
764 for(int i = 0; i < fields.length; i++) {
765
766
767 if ((fields[i].getModifiers() & (java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.PROTECTED)) == 0)
768 continue;
769
770
771 if(propertyMap.get(fields[i].getName()) != null)
772 continue;
773
774
775
776
777 propertyMap.put(fields[i].getName(), new MetaFieldProperty(fields[i]));
778 }
779
780
781 klass = klass.getSuperclass();
782 }
783
784
785 if (theClass.isArray()) {
786 propertyMap.put("length", arrayLengthProperty);
787 }
788
789
790
791 for(int i=0; i<propertyDescriptors.length; i++) {
792 PropertyDescriptor pd = propertyDescriptors[i];
793
794
795
796
797 if(pd.getPropertyType() == null)
798 continue;
799
800
801 method = pd.getReadMethod();
802 if(method != null)
803 getter = findMethod(method);
804 else
805 getter = null;
806
807
808 method = pd.getWriteMethod();
809 if(method != null)
810 setter = findMethod(method);
811 else
812 setter = null;
813
814
815
816
817
818 mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter);
819
820
821
822 propertyMap.put(pd.getName(), mp);
823 }
824
825
826 klass = theClass;
827 while(klass != null) {
828 final Class clazz = klass;
829 Method[] methods = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
830 public Object run() {
831 return clazz.getDeclaredMethods();
832 }
833 });
834 for (int i = 0; i < methods.length; i++) {
835
836 if(Modifier.isPublic(methods[i].getModifiers()) == false)
837 continue;
838
839 method = methods[i];
840
841 String methodName = method.getName();
842
843
844 if(methodName.startsWith("get") &&
845 methodName.length() > 3 &&
846 method.getParameterTypes().length == 0) {
847
848
849 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
850
851
852 mp = (MetaProperty) propertyMap.get(propName);
853 if(mp != null) {
854
855 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getGetter() == null) {
856
857 ((MetaBeanProperty) mp).setGetter(findMethod(method));
858 }
859 }
860 else {
861
862
863 MetaBeanProperty mbp = new MetaBeanProperty(propName,
864 method.getReturnType(),
865 findMethod(method), null);
866
867
868 propertyMap.put(propName, mbp);
869 }
870 }
871 else if(methodName.startsWith("set") &&
872 methodName.length() > 3 &&
873 method.getParameterTypes().length == 1) {
874
875
876 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
877
878
879 mp = (MetaProperty) propertyMap.get(propName);
880 if(mp != null) {
881 if(mp instanceof MetaBeanProperty && ((MetaBeanProperty) mp).getSetter() == null) {
882
883 ((MetaBeanProperty) mp).setSetter(findMethod(method));
884 }
885 }
886 else {
887
888 MetaBeanProperty mbp = new MetaBeanProperty(propName,
889 method.getParameterTypes()[0],
890 null,
891 findMethod(method));
892
893
894 propertyMap.put(propName, mbp);
895 }
896 }
897 }
898
899
900 klass = klass.getSuperclass();
901 }
902 }
903
904 /***
905 * Sets the property value on an object
906 */
907 public void setProperty(Object object, String property, Object newValue) {
908
909
910
911 if (newValue instanceof Wrapper) newValue = ((Wrapper)newValue).unwrap();
912
913 MetaProperty mp = (MetaProperty) propertyMap.get(property);
914 if(mp != null) {
915 try {
916 mp.setProperty(object, newValue);
917 return;
918 }
919 catch(ReadOnlyPropertyException e) {
920
921 throw e;
922 }
923 catch (TypeMismatchException e) {
924
925 throw e;
926 }
927 catch (Exception e) {
928
929
930 if (newValue == null)
931 return;
932 if (newValue instanceof List) {
933 List list = (List) newValue;
934 int params = list.size();
935 Constructor[] constructors = mp.getType().getConstructors();
936 for (int i = 0; i < constructors.length; i++) {
937 Constructor constructor = constructors[i];
938 if (constructor.getParameterTypes().length == params) {
939 Object value = MetaClassHelper.doConstructorInvoke(constructor, list.toArray());
940 mp.setProperty(object, value);
941 return;
942 }
943 }
944
945
946 Class parameterType = mp.getType();
947 if (parameterType.isArray()) {
948 Object objArray = MetaClassHelper.asPrimitiveArray(list, parameterType);
949 mp.setProperty(object, objArray);
950 return;
951 }
952 }
953
954
955
956
957
958 if (newValue.getClass().isArray() && mp instanceof MetaBeanProperty) {
959 MetaBeanProperty mbp = (MetaBeanProperty) mp;
960 List list = Arrays.asList((Object[])newValue);
961 MetaMethod setter = mbp.getSetter();
962
963 Class parameterType = setter.getParameterTypes()[0];
964 Class arrayType = parameterType.getComponentType();
965 Object objArray = Array.newInstance(arrayType, list.size());
966
967 for (int i = 0; i < list.size(); i++) {
968 List list2 =Arrays.asList((Object[]) list.get(i));
969 Object objArray2 = MetaClassHelper.asPrimitiveArray(list2, arrayType);
970 Array.set(objArray, i, objArray2);
971 }
972
973 MetaClassHelper.doMethodInvoke(object, setter, new Object[]{
974 objArray
975 });
976 return;
977 }
978
979 throw new MissingPropertyException(property, theClass, e);
980 }
981 }
982
983 RuntimeException runtimeException = null;
984 MetaMethod addListenerMethod = (MetaMethod) listeners.get(property);
985
986 try {
987 if (addListenerMethod != null && newValue instanceof Closure) {
988
989 Object proxy =
990 MetaClassHelper.createListenerProxy(addListenerMethod.getParameterTypes()[0], property, (Closure) newValue);
991 MetaClassHelper.doMethodInvoke(object, addListenerMethod, new Object[] { proxy });
992 return;
993 }
994
995 if (genericSetMethod == null) {
996
997 List possibleGenericMethods = getMethods("set");
998 if (possibleGenericMethods != null) {
999 for (Iterator i = possibleGenericMethods.iterator(); i.hasNext(); ) {
1000 MetaMethod mmethod = (MetaMethod) i.next();
1001 Class[] paramTypes = mmethod.getParameterTypes();
1002 if (paramTypes.length == 2 && paramTypes[0] == String.class) {
1003 Object[] arguments = {property, newValue};
1004 Object answer = MetaClassHelper.doMethodInvoke(object, mmethod, arguments);
1005 return;
1006 }
1007 }
1008 }
1009 }
1010 else {
1011 Object[] arguments = { property, newValue };
1012 MetaClassHelper.doMethodInvoke(object, genericSetMethod, arguments);
1013 return;
1014 }
1015
1016 /*** todo or are we an extensible class? */
1017
1018
1019
1020
1021
1022
1023 String method = "set" + MetaClassHelper.capitalize(property);
1024 try {
1025 invokeMethod(object, method, new Object[] { newValue });
1026 }
1027 catch (MissingMethodException e1) {
1028 setAttribute(object,property,newValue);
1029 }
1030
1031 }
1032 catch (GroovyRuntimeException e) {
1033 runtimeException = e;
1034 }
1035
1036 if (addListenerMethod==AMBIGOUS_LISTENER_METHOD){
1037 throw new GroovyRuntimeException("There are multiple listeners for the property "+property+". Please do not use the bean short form to access this listener.");
1038 } else if (runtimeException!=null) {
1039 throw new MissingPropertyException(property, theClass, runtimeException);
1040 }
1041
1042
1043 }
1044
1045
1046 /***
1047 * Looks up the given attribute (field) on the given object
1048 */
1049 public Object getAttribute(final Object object, final String attribute) {
1050 PrivilegedActionException firstException = null;
1051
1052 final Class clazz;
1053 if (object instanceof Class) {
1054 clazz=(Class) object;
1055 } else {
1056 clazz=theClass;
1057 }
1058
1059 try {
1060 return AccessController.doPrivileged(new PrivilegedExceptionAction() {
1061 public Object run() throws NoSuchFieldException, IllegalAccessException {
1062 final Field field = clazz.getDeclaredField(attribute);
1063
1064 field.setAccessible(true);
1065 return field.get(object);
1066 }
1067 });
1068 } catch (final PrivilegedActionException pae) {
1069 firstException = pae;
1070 }
1071
1072 try {
1073 return AccessController.doPrivileged(new PrivilegedExceptionAction() {
1074 public Object run() throws NoSuchFieldException, IllegalAccessException {
1075 final Field field = clazz.getField(attribute);
1076
1077 field.setAccessible(true);
1078 return field.get(object);
1079 }
1080 });
1081 } catch (final PrivilegedActionException pae) {
1082
1083 }
1084
1085
1086 if (firstException.getException() instanceof NoSuchFieldException) {
1087 throw new MissingFieldException(attribute, theClass);
1088 } else {
1089 throw new RuntimeException(firstException.getException());
1090 }
1091 }
1092
1093 /***
1094 * Sets the given attribute (field) on the given object
1095 */
1096 public void setAttribute(final Object object, final String attribute, final Object newValue) {
1097 PrivilegedActionException firstException = null;
1098
1099 final Class clazz;
1100 if (object instanceof Class) {
1101 clazz=(Class) object;
1102 } else {
1103 clazz=theClass;
1104 }
1105
1106 try {
1107 AccessController.doPrivileged(new PrivilegedExceptionAction() {
1108 public Object run() throws NoSuchFieldException, IllegalAccessException {
1109 final Field field = clazz.getDeclaredField(attribute);
1110
1111 field.setAccessible(true);
1112 field.set(object,newValue);
1113 return null;
1114 }
1115 });
1116 return;
1117 } catch (final PrivilegedActionException pae) {
1118 firstException = pae;
1119 }
1120
1121 try {
1122 AccessController.doPrivileged(new PrivilegedExceptionAction() {
1123 public Object run() throws NoSuchFieldException, IllegalAccessException {
1124 final Field field = clazz.getField(attribute);
1125
1126 field.setAccessible(true);
1127 field.set(object, newValue);
1128 return null;
1129 }
1130 });
1131 return;
1132 } catch (final PrivilegedActionException pae) {
1133
1134 }
1135
1136 if (firstException.getException() instanceof NoSuchFieldException) {
1137 throw new MissingFieldException(attribute, theClass);
1138 } else {
1139 throw new RuntimeException(firstException.getException());
1140 }
1141 }
1142
1143 public ClassNode getClassNode() {
1144 if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) {
1145
1146 String className = theClass.getName();
1147 String groovyFile = className;
1148 int idx = groovyFile.indexOf('$');
1149 if (idx > 0) {
1150 groovyFile = groovyFile.substring(0, idx);
1151 }
1152 groovyFile = groovyFile.replace('.', '/') + ".groovy";
1153
1154
1155 URL url = theClass.getClassLoader().getResource(groovyFile);
1156 if (url == null) {
1157 url = Thread.currentThread().getContextClassLoader().getResource(groovyFile);
1158 }
1159 if (url != null) {
1160 try {
1161
1162 /***
1163 * todo there is no CompileUnit in scope so class name
1164 * checking won't work but that mostly affects the bytecode
1165 * generation rather than viewing the AST
1166 */
1167 CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
1168 public void call( ClassVisitor writer, ClassNode node ) {
1169 if( node.getName().equals(theClass.getName()) ) {
1170 MetaClassImpl.this.classNode = node;
1171 }
1172 }
1173 };
1174
1175 final ClassLoader parent = theClass.getClassLoader();
1176 GroovyClassLoader gcl = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
1177 public Object run() {
1178 return new GroovyClassLoader(parent);
1179 }
1180 });
1181 CompilationUnit unit = new CompilationUnit( );
1182 unit.setClassgenCallback( search );
1183 unit.addSource( url );
1184 unit.compile( Phases.CLASS_GENERATION );
1185 }
1186 catch (Exception e) {
1187 throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e);
1188 }
1189 }
1190
1191 }
1192 return classNode;
1193 }
1194
1195 public String toString() {
1196 return super.toString() + "[" + theClass + "]";
1197 }
1198
1199
1200
1201
1202 /***
1203 * Adds all the methods declared in the given class to the metaclass
1204 * ignoring any matching methods already defined by a derived class
1205 *
1206 * @param theClass
1207 */
1208 private void addMethods(final Class theClass, boolean forceOverwrite) {
1209
1210 Method[] methodArray = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
1211 public Object run() {
1212 return theClass.getDeclaredMethods();
1213 }
1214 });
1215 for (int i = 0; i < methodArray.length; i++) {
1216 Method reflectionMethod = methodArray[i];
1217 if ( reflectionMethod.getName().indexOf('+') >= 0 ) {
1218
1219 continue;
1220 }
1221 MetaMethod method = createMetaMethod(reflectionMethod);
1222 addMethod(method,forceOverwrite);
1223 }
1224 }
1225
1226 private void addMethod(MetaMethod method, boolean forceOverwrite) {
1227 String name = method.getName();
1228
1229
1230
1231 if (isGenericGetMethod(method) && genericGetMethod == null) {
1232 genericGetMethod = method;
1233 }
1234 else if (MetaClassHelper.isGenericSetMethod(method) && genericSetMethod == null) {
1235 genericSetMethod = method;
1236 }
1237 if (method.isStatic()) {
1238 List list = (List) staticMethodIndex.get(name);
1239 if (list == null) {
1240 list = new ArrayList();
1241 staticMethodIndex.put(name, list);
1242 list.add(method);
1243 }
1244 else {
1245 if (!MetaClassHelper.containsMatchingMethod(list, method)) {
1246 list.add(method);
1247 }
1248 }
1249 }
1250
1251 List list = (List) methodIndex.get(name);
1252 if (list == null) {
1253 list = new ArrayList();
1254 methodIndex.put(name, list);
1255 list.add(method);
1256 }
1257 else {
1258 if (forceOverwrite) {
1259 removeMatchingMethod(list,method);
1260 list.add(method);
1261 } else if (!MetaClassHelper.containsMatchingMethod(list, method)) {
1262 list.add(method);
1263 }
1264 }
1265 }
1266
1267 /***
1268 * remove a method of the same matching prototype was found in the list
1269 */
1270 private void removeMatchingMethod(List list, MetaMethod method) {
1271 for (Iterator iter = list.iterator(); iter.hasNext();) {
1272 MetaMethod aMethod = (MetaMethod) iter.next();
1273 Class[] params1 = aMethod.getParameterTypes();
1274 Class[] params2 = method.getParameterTypes();
1275 if (params1.length == params2.length) {
1276 boolean matches = true;
1277 for (int i = 0; i < params1.length; i++) {
1278 if (params1[i] != params2[i]) {
1279 matches = false;
1280 break;
1281 }
1282 }
1283 if (matches) {
1284 iter.remove();
1285 return;
1286 }
1287 }
1288 }
1289 return;
1290 }
1291
1292
1293 /***
1294 * Adds all of the newly defined methods from the given class to this
1295 * metaclass
1296 *
1297 * @param theClass
1298 */
1299 private void addNewStaticMethodsFrom(Class theClass) {
1300 MetaClass interfaceMetaClass = registry.getMetaClass(theClass);
1301 Iterator iter = interfaceMetaClass.newGroovyMethodsList.iterator();
1302 while (iter.hasNext()) {
1303 MetaMethod method = (MetaMethod) iter.next();
1304 if (! newGroovyMethodsList.contains(method)){
1305 newGroovyMethodsList.add(method);
1306 addMethod(method,false);
1307 }
1308 }
1309 }
1310
1311 /***
1312 * @return the value of the static property of the given class
1313 */
1314 private Object getStaticProperty(Class aClass, String property) {
1315
1316
1317
1318
1319 MetaMethod method = findStaticGetter(aClass, "get" + MetaClassHelper.capitalize(property));
1320 if (method != null) {
1321 return MetaClassHelper.doMethodInvoke(aClass, method, MetaClassHelper.EMPTY_ARRAY);
1322 }
1323
1324
1325 try {
1326 return getAttribute(aClass,property);
1327 } catch (MissingFieldException mfe) {
1328 throw new MissingPropertyException(property, aClass, mfe);
1329 }
1330 }
1331
1332 /***
1333 * @return the matching method which should be found
1334 */
1335 private MetaMethod findMethod(Method aMethod) {
1336 List methods = getMethods(aMethod.getName());
1337 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1338 MetaMethod method = (MetaMethod) iter.next();
1339 if (method.isMethod(aMethod)) {
1340 return method;
1341 }
1342 }
1343
1344 return new ReflectionMetaMethod(aMethod);
1345 }
1346
1347 /***
1348 * @return the getter method for the given object
1349 */
1350 private MetaMethod findGetter(Object object, String name) {
1351 List methods = getMethods(name);
1352 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1353 MetaMethod method = (MetaMethod) iter.next();
1354 if (method.getParameterTypes().length == 0) {
1355 return method;
1356 }
1357 }
1358 return null;
1359 }
1360
1361 /***
1362 * @return the Method of the given name with no parameters or null
1363 */
1364 private MetaMethod findStaticGetter(Class type, String name) {
1365 List methods = getStaticMethods(name);
1366 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1367 MetaMethod method = (MetaMethod) iter.next();
1368 if (method.getParameterTypes().length == 0) {
1369 return method;
1370 }
1371 }
1372
1373 /*** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
1374 try {
1375 Method method = type.getMethod(name, MetaClassHelper.EMPTY_TYPE_ARRAY);
1376 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1377 return findMethod(method);
1378 }
1379 else {
1380 return null;
1381 }
1382 }
1383 catch (Exception e) {
1384 return null;
1385 }
1386 }
1387
1388 private static Object doConstructorInvokeAt(final Class at, Constructor constructor, Object[] argumentArray) {
1389 if (log.isLoggable(Level.FINER)) {
1390 MetaClassHelper.logMethodCall(constructor.getDeclaringClass(), constructor.getName(), argumentArray);
1391 }
1392
1393
1394
1395 final boolean accessible = MetaClassHelper.accessibleToConstructor(at, constructor);
1396
1397 final Constructor ctor = constructor;
1398 AccessController.doPrivileged(new PrivilegedAction() {
1399 public Object run() {
1400 ctor.setAccessible(accessible);
1401 return null;
1402 }
1403 });
1404 return MetaClassHelper.doConstructorInvoke(constructor,argumentArray);
1405 }
1406
1407 /***
1408 * Chooses the correct method to use from a list of methods which match by
1409 * name.
1410 *
1411 * @param methods
1412 * the possible methods to choose from
1413 * @param arguments
1414 * the original argument to the method
1415 * @return
1416 */
1417 private Object chooseMethod(String methodName, List methods, Class[] arguments, boolean coerce) {
1418 int methodCount = methods.size();
1419 if (methodCount <= 0) {
1420 return null;
1421 }
1422 else if (methodCount == 1) {
1423 Object method = methods.get(0);
1424 if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
1425 return method;
1426 }
1427 return null;
1428 }
1429 Object answer = null;
1430 if (arguments == null || arguments.length == 0) {
1431 answer = MetaClassHelper.chooseEmptyMethodParams(methods);
1432 }
1433 else if (arguments.length == 1 && arguments[0] == null) {
1434 answer = MetaClassHelper.chooseMostGeneralMethodWith1NullParam(methods);
1435 }
1436 else {
1437 List matchingMethods = new ArrayList();
1438
1439 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1440 Object method = iter.next();
1441
1442
1443 if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
1444 matchingMethods.add(method);
1445 }
1446 }
1447 if (matchingMethods.isEmpty()) {
1448 return null;
1449 }
1450 else if (matchingMethods.size() == 1) {
1451 return matchingMethods.get(0);
1452 }
1453 return chooseMostSpecificParams(methodName, matchingMethods, arguments);
1454
1455 }
1456 if (answer != null) {
1457 return answer;
1458 }
1459 throw new GroovyRuntimeException(
1460 "Could not find which method to invoke from this list: "
1461 + methods
1462 + " for arguments: "
1463 + InvokerHelper.toString(arguments));
1464 }
1465
1466 private Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
1467
1468 Class[] wrappedArguments = MetaClassHelper.wrap(arguments);
1469
1470 int matchesDistance = -1;
1471 LinkedList matches = new LinkedList();
1472 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
1473 Object method = iter.next();
1474 Class[] paramTypes = MetaClassHelper.getParameterTypes(method);
1475 if (!MetaClassHelper.parametersAreCompatible(arguments, paramTypes)) continue;
1476 int dist = MetaClassHelper.calculateParameterDistance(arguments, paramTypes);
1477 if (matches.size()==0) {
1478 matches.add(method);
1479 matchesDistance = dist;
1480 } else if (dist<matchesDistance) {
1481 matchesDistance=dist;
1482 matches.clear();
1483 matches.add(method);
1484 } else if (dist==matchesDistance) {
1485 matches.add(method);
1486 }
1487
1488 }
1489 if (matches.size()==1) {
1490 return matches.getFirst();
1491 }
1492 if (matches.size()==0) {
1493 return null;
1494 }
1495
1496
1497 String msg = "Ambiguous method overloading for method ";
1498 msg+= theClass.getName()+"#"+name;
1499 msg+= ".\nCannot resolve which method to invoke for ";
1500 msg+= InvokerHelper.toString(arguments);
1501 msg+= " due to overlapping prototypes between:";
1502 for (Iterator iter = matches.iterator(); iter.hasNext();) {
1503 Class[] types=MetaClassHelper.getParameterTypes(iter.next());
1504 msg+= "\n\t"+InvokerHelper.toString(types);
1505 }
1506 throw new GroovyRuntimeException(msg);
1507 }
1508
1509 private boolean isGenericGetMethod(MetaMethod method) {
1510 if (method.getName().equals("get")) {
1511 Class[] parameterTypes = method.getParameterTypes();
1512 return parameterTypes.length == 1 && parameterTypes[0] == String.class;
1513 }
1514 return false;
1515 }
1516
1517 /***
1518 * Call this method when any mutation method is called, such as adding a new
1519 * method to this MetaClass so that any caching or bytecode generation can be
1520 * regenerated.
1521 */
1522 private synchronized void onMethodChange() {
1523 reflector = null;
1524 }
1525
1526 public synchronized void checkInitialised() {
1527 if (!initialised) {
1528 initialised = true;
1529 addInheritedMethods();
1530 }
1531 if (reflector == null) {
1532 generateReflector();
1533 }
1534 }
1535
1536 private MetaMethod createMetaMethod(final Method method) {
1537 if (registry.useAccessible()) {
1538 AccessController.doPrivileged(new PrivilegedAction() {
1539 public Object run() {
1540 method.setAccessible(true);
1541 return null;
1542 }
1543 });
1544 }
1545
1546 MetaMethod answer = new MetaMethod(method);
1547 if (isValidReflectorMethod(answer)) {
1548 allMethods.add(answer);
1549 answer.setMethodIndex(allMethods.size());
1550 }
1551 else {
1552
1553 answer = new ReflectionMetaMethod(method);
1554 }
1555
1556 if (useReflection) {
1557
1558 return new ReflectionMetaMethod(method);
1559 }
1560
1561 return answer;
1562 }
1563
1564 private boolean isValidReflectorMethod(MetaMethod method) {
1565
1566 if (!method.isPublic()) {
1567 return false;
1568 }
1569
1570 List interfaceMethods = getInterfaceMethods();
1571 for (Iterator iter = interfaceMethods.iterator(); iter.hasNext();) {
1572 MetaMethod aMethod = (MetaMethod) iter.next();
1573 if (method.isSame(aMethod)) {
1574 method.setInterfaceClass(aMethod.getDeclaringClass());
1575 return true;
1576 }
1577 }
1578
1579
1580 Class declaringClass = method.getDeclaringClass();
1581 for (Class clazz=declaringClass; clazz!=null; clazz=clazz.getSuperclass()) {
1582 try {
1583 final Class klazz = clazz;
1584 final String mName = method.getName();
1585 final Class[] parms = method.getParameterTypes();
1586 try {
1587 Method m = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
1588 public Object run() throws NoSuchMethodException {
1589 return klazz.getDeclaredMethod(mName, parms);
1590 }
1591 });
1592 if (!Modifier.isPublic(clazz.getModifiers())) continue;
1593 if (!Modifier.isPublic(m.getModifiers())) continue;
1594 declaringClass = clazz;
1595 } catch (PrivilegedActionException pae) {
1596 if (pae.getException() instanceof NoSuchMethodException) {
1597 throw (NoSuchMethodException) pae.getException();
1598 } else {
1599 throw new RuntimeException(pae.getException());
1600 }
1601 }
1602 } catch (SecurityException e) {
1603 continue;
1604 } catch (NoSuchMethodException e) {
1605 continue;
1606 }
1607 }
1608 if (!Modifier.isPublic(declaringClass.getModifiers())) return false;
1609 method.setDeclaringClass(declaringClass);
1610
1611 return true;
1612 }
1613
1614 private void generateReflector() {
1615 reflector = loadReflector(allMethods);
1616 if (reflector == null) {
1617 throw new RuntimeException("Should have a reflector for "+theClass.getName());
1618 }
1619
1620 for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
1621 MetaMethod metaMethod = (MetaMethod) iter.next();
1622 metaMethod.setReflector(reflector);
1623 }
1624 }
1625
1626 private String getReflectorName() {
1627 String className = theClass.getName();
1628 String packagePrefix = "gjdk.";
1629 String name = packagePrefix + className + "_GroovyReflector";
1630 if (theClass.isArray()) {
1631 Class clazz = theClass;
1632 name = packagePrefix;
1633 int level = 0;
1634 while (clazz.isArray()) {
1635 clazz = clazz.getComponentType();
1636 level++;
1637 }
1638 String componentName = clazz.getName();
1639 name = packagePrefix + componentName + "_GroovyReflectorArray";
1640 if (level>1) name += level;
1641 }
1642 return name;
1643 }
1644
1645 private Reflector loadReflector(List methods) {
1646 String name = getReflectorName();
1647
1648
1649
1650 ReflectorGenerator generator = new ReflectorGenerator(methods);
1651 try {
1652 ClassWriter cw = new ClassWriter(true);
1653 generator.generate(cw, name);
1654 byte[] bytecode = cw.toByteArray();
1655
1656
1657
1658
1659
1660
1661 ClassLoader loader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
1662 public Object run() {
1663 return theClass.getClassLoader();
1664 }
1665 });
1666 Class type = registry.createReflectorClass(loader, name, bytecode);
1667 return (Reflector) type.newInstance();
1668 }
1669 catch (Exception e) {
1670 e.printStackTrace();
1671 throw new GroovyRuntimeException("Could not generate and load the reflector for class: " + name + ". Reason: " + e, e);
1672 }
1673 }
1674
1675 public List getMethods() {
1676 return allMethods;
1677 }
1678
1679 public List getMetaMethods() {
1680 return new ArrayList(newGroovyMethodsList);
1681 }
1682
1683 private synchronized List getInterfaceMethods() {
1684 if (interfaceMethods == null) {
1685 interfaceMethods = new ArrayList();
1686 Class type = theClass;
1687 while (type != null) {
1688 Class[] interfaces = type.getInterfaces();
1689 for (int i = 0; i < interfaces.length; i++) {
1690 Class iface = interfaces[i];
1691 Method[] methods = iface.getMethods();
1692 addInterfaceMethods(interfaceMethods, methods);
1693 }
1694 type = type.getSuperclass();
1695 }
1696 }
1697 return interfaceMethods;
1698 }
1699
1700 private void addInterfaceMethods(List list, Method[] methods) {
1701 for (int i = 0; i < methods.length; i++) {
1702 list.add(createMetaMethod(methods[i]));
1703 }
1704 }
1705 }