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.Constructor;
54 import java.lang.reflect.Field;
55 import java.lang.reflect.Method;
56 import java.lang.reflect.Modifier;
57 import java.net.URL;
58 import java.security.AccessController;
59 import java.security.PrivilegedAction;
60 import java.security.PrivilegedActionException;
61 import java.security.PrivilegedExceptionAction;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collection;
65 import java.util.Collections;
66 import java.util.Comparator;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.Iterator;
70 import java.util.LinkedList;
71 import java.util.List;
72 import java.util.Map;
73 import java.util.Set;
74 import java.util.logging.Level;
75
76 import org.codehaus.groovy.GroovyBugError;
77 import org.codehaus.groovy.ast.ClassNode;
78 import org.codehaus.groovy.classgen.BytecodeHelper;
79 import org.codehaus.groovy.control.CompilationUnit;
80 import org.codehaus.groovy.control.Phases;
81 import org.codehaus.groovy.runtime.CurriedClosure;
82 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
83 import org.codehaus.groovy.runtime.DefaultMethodKey;
84 import org.codehaus.groovy.runtime.GroovyCategorySupport;
85 import org.codehaus.groovy.runtime.InvokerHelper;
86 import org.codehaus.groovy.runtime.MetaClassHelper;
87 import org.codehaus.groovy.runtime.MethodClosure;
88 import org.codehaus.groovy.runtime.MethodKey;
89 import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
90 import org.codehaus.groovy.runtime.NewStaticMetaMethod;
91 import org.codehaus.groovy.runtime.ReflectionMetaMethod;
92 import org.codehaus.groovy.runtime.Reflector;
93 import org.codehaus.groovy.runtime.TransformMetaMethod;
94 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
95 import org.codehaus.groovy.runtime.wrappers.Wrapper;
96 import org.objectweb.asm.ClassVisitor;
97
98 /***
99 * Allows methods to be dynamically added to existing classes at runtime
100 *
101 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
102 * @author Guillaume Laforge
103 * @author Jochen Theodorou
104 * @version $Revision: 4669 $
105 * @see groovy.lang.MetaClass
106 */
107 public class MetaClassImpl extends MetaClass {
108
109 protected MetaClassRegistry registry;
110 private ClassNode classNode;
111 private Map classMethodIndex = new HashMap();
112 private Map classMethodIndexForSuper;
113 private Map classStaticMethodIndex = new HashMap();
114 private Map classPropertyIndex = new HashMap();
115 private Map classPropertyIndexForSuper = new HashMap();
116 private Map staticPropertyIndex = new HashMap();
117 private Map listeners = new HashMap();
118 private Map methodCache = Collections.synchronizedMap(new HashMap());
119 private Map staticMethodCache = Collections.synchronizedMap(new HashMap());
120 private MetaMethod genericGetMethod;
121 private MetaMethod genericSetMethod;
122 private List constructors;
123 private List allMethods = new ArrayList();
124 private List interfaceMethods;
125 private Reflector reflector;
126 private boolean initialized;
127
128 private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
129 private final static MetaMethod AMBIGOUS_LISTENER_METHOD = new MetaMethod(null,null,new Class[]{},null,0);
130 private static final Object[] EMPTY_ARGUMENTS = {};
131 private List newGroovyMethodsList = new LinkedList();
132
133 public MetaClassImpl(MetaClassRegistry registry, final Class theClass) {
134 super(theClass);
135 this.registry = registry;
136
137 constructors = (List) AccessController.doPrivileged(new PrivilegedAction() {
138 public Object run() {
139 return Arrays.asList (theClass.getDeclaredConstructors());
140 }
141 });
142 }
143
144 private void fillMethodIndex() {
145 LinkedList superClasses = getSuperClasses();
146
147 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
148 Class c = (Class) iter.next();
149 addMethods(c);
150 }
151
152 Set interfaces = new HashSet();
153 makeInterfaceSet(theClass,interfaces);
154
155 inheritMethods(superClasses,classMethodIndex);
156 inheritInterfaceMethods(interfaces);
157 copyClassMethodIndexForSuper();
158
159 connectMultimethods(superClasses);
160 populateInterfaces(interfaces);
161 removeMultimethodsOverloadedWithPrivateMethods();
162
163 replaceWithMOPCalls();
164 }
165
166 private LinkedList getSuperClasses() {
167 LinkedList superClasses = new LinkedList();
168 for (Class c = theClass; c!= null; c = c.getSuperclass()) {
169 superClasses.addFirst(c);
170 }
171 if (theClass.isArray() && theClass!=Object[].class && !theClass.getComponentType().isPrimitive()) {
172 superClasses.addFirst(Object[].class);
173 }
174 return superClasses;
175 }
176
177 private void removeMultimethodsOverloadedWithPrivateMethods() {
178 Map privates = new HashMap();
179 MethodIndexAction mia = new MethodIndexAction() {
180 public List methodNameAction(Class clazz, String methodName, List methods) {
181 boolean hasPrivate=false;
182 for (Iterator iter = methods.iterator(); iter.hasNext();) {
183 MetaMethod method = (MetaMethod) iter.next();
184 if (method.isPrivate() && clazz == method.getDeclaringClass()) {
185 hasPrivate = true;
186 break;
187 }
188 }
189 if (!hasPrivate) return null;
190
191
192
193
194
195
196 methods.clear();
197 methods.addAll((Collection) ((Map) classMethodIndexForSuper.get(clazz)).get(methodName));
198 return methods;
199 }
200 public boolean replaceMethodList() {return false;}
201 };
202 mia.iterate(classMethodIndex);
203 }
204
205
206 private void replaceWithMOPCalls() {
207
208 if (!GroovyObject.class.isAssignableFrom(theClass)) return;
209
210 final Map mainClassMethodIndex = (Map) classMethodIndex.get(theClass);
211 class MOPIter extends MethodIndexAction {
212 boolean useThis;
213 public boolean skipClass(Class clazz) {
214 return !useThis && clazz==theClass;
215 }
216 public void methodListAction(Class clazz, String methodName, MetaMethod method, List oldList, List newList) {
217 String mopName = getMOPMethodName(method.getDeclaringClass(), methodName,useThis);
218 List matches = (List) mainClassMethodIndex.get(mopName);
219 if (matches==null) {
220 newList.add(method);
221 return;
222 }
223 matches = new ArrayList(matches);
224 MetaMethod matchingMethod = removeMatchingMethod(matches,method);
225 if (matchingMethod==null) {
226 newList.add(method);
227 return;
228 } else {
229 newList.add(matchingMethod);
230 }
231 }
232 }
233 MOPIter iter = new MOPIter();
234
235
236 iter.useThis = false;
237 iter.iterate(classMethodIndexForSuper);
238
239 iter.useThis = true;
240 iter.iterate(classMethodIndex);
241 }
242
243 private String getMOPMethodName(Class declaringClass, String name, boolean useThis) {
244 int distance = 0;
245 for (;declaringClass!=null; declaringClass=declaringClass.getSuperclass()) {
246 distance++;
247 }
248 return (useThis?"this":"super")+"$"+distance+"$"+name;
249 }
250
251 private void copyClassMethodIndexForSuper() {
252 classMethodIndexForSuper = new HashMap(classMethodIndex.size());
253 for (Iterator iter = classMethodIndex.entrySet().iterator(); iter.hasNext();) {
254 Map.Entry cmiEntry = (Map.Entry) iter.next();
255 Map methodIndex = (Map) cmiEntry.getValue();
256 Map copy = new HashMap (methodIndex.size());
257 for (Iterator iterator = methodIndex.entrySet().iterator(); iterator.hasNext();) {
258 Map.Entry mEntry = (Map.Entry) iterator.next();
259 copy.put(mEntry.getKey(), new ArrayList((List) mEntry.getValue()));
260 }
261 classMethodIndexForSuper.put(cmiEntry.getKey(),copy);
262 }
263 }
264
265 private void inheritInterfaceMethods(Set interfaces) {
266
267 List methods = registry.getInstanceMethods();
268 for (Iterator iter = methods.iterator(); iter.hasNext();) {
269 Method element = (Method) iter.next();
270 Class dgmClass = element.getParameterTypes()[0];
271 if (!interfaces.contains(dgmClass)) continue;
272 NewInstanceMetaMethod method = new NewInstanceMetaMethod(createMetaMethod(element));
273 if (! newGroovyMethodsList.contains(method)){
274 newGroovyMethodsList.add(method);
275 }
276 Map methodIndex = (Map) classMethodIndex.get(theClass);
277 List list = (List) methodIndex.get(method.getName());
278 if (list == null) {
279 list = new ArrayList();
280 methodIndex.put(method.getName(), list);
281 list.add(method);
282 } else {
283 addMethodToList(list,method);
284 }
285 }
286 methods = registry.getStaticMethods();
287 for (Iterator iter = methods.iterator(); iter.hasNext();) {
288 Method element = (Method) iter.next();
289 Class dgmClass = element.getParameterTypes()[0];
290 if (!interfaces.contains(dgmClass)) continue;
291 addNewStaticMethod(element);
292 }
293 }
294
295 private void populateInterfaces(Set interfaces){
296 Map currentIndex = (Map) classMethodIndex.get(theClass);
297 Map index = new HashMap();
298 copyNonPrivateMethods(currentIndex,index);
299 for (Iterator iter = interfaces.iterator(); iter.hasNext();) {
300 Class iClass = (Class) iter.next();
301 Map methodIndex = (Map) classMethodIndex.get(iClass);
302 if (methodIndex==null || methodIndex.size()==0) {
303 classMethodIndex.put(iClass,index);
304 continue;
305 }
306 copyNonPrivateMethods(currentIndex,methodIndex);
307 }
308 }
309
310 private static void makeInterfaceSet(Class c, Set s) {
311 if (c==null) return;
312 Class[] interfaces = c.getInterfaces();
313 for (int i = 0; i < interfaces.length; i++) {
314 if (!s.contains(interfaces[i])) {
315 s.add(interfaces[i]);
316 makeInterfaceSet(interfaces[i],s);
317 }
318 }
319 makeInterfaceSet(c.getSuperclass(),s);
320 }
321
322 private void copyNonPrivateMethods(Map from, Map to) {
323 for (Iterator iterator = from.entrySet().iterator(); iterator.hasNext();) {
324 Map.Entry element = (Map.Entry) iterator.next();
325 List oldList = (List) element.getValue();
326 List newList = (List) to.get(element.getKey());
327 if (newList==null) {
328 to.put(element.getKey(),new ArrayList(oldList));
329 } else {
330 addNonPrivateMethods(newList,oldList);
331 }
332 }
333 }
334
335 private void connectMultimethods(List superClasses){
336 superClasses = DefaultGroovyMethods.reverse(superClasses);
337 Map last = null;
338 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
339 Class c = (Class) iter.next();
340 Map methodIndex = (Map) classMethodIndex.get(c);
341 if (methodIndex==last) continue;
342 if (last!=null) copyNonPrivateMethods(last,methodIndex);
343 last = methodIndex;
344 }
345 }
346
347 private void inheritMethods(Collection superClasses, Map classMethodIndex){
348 Map last = null;
349 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
350 Class c = (Class) iter.next();
351 Map methodIndex = (Map) classMethodIndex.get(c);
352 if (last!=null) {
353 if (methodIndex.size()==0) {
354 classMethodIndex.put(c,last);
355 continue;
356 }
357 copyNonPrivateMethods(last,methodIndex);
358 }
359 last = methodIndex;
360 }
361 }
362
363 private void addNonPrivateMethods(List newList, List oldList) {
364 for (Iterator iter = oldList.iterator(); iter.hasNext();) {
365 MetaMethod element = (MetaMethod) iter.next();
366 if (element.isPrivate()) continue;
367 addMethodToList(newList,element);
368 }
369 }
370
371 /***
372 * @return all the normal instance methods avaiable on this class for the
373 * given name
374 */
375 private List getMethods(Class sender, String name, boolean isCallToSuper) {
376 Map methodIndex;
377 if (isCallToSuper) {
378 methodIndex = (Map) classMethodIndexForSuper.get(sender);
379 } else {
380 methodIndex = (Map) classMethodIndex.get(sender);
381 }
382 List answer;
383 if (methodIndex!=null) {
384 answer = (List) methodIndex.get(name);
385 if (answer == null) answer = Collections.EMPTY_LIST;
386 } else {
387 answer = Collections.EMPTY_LIST;
388 }
389
390 if (!isCallToSuper && GroovyCategorySupport.hasCategoryInAnyThread()) {
391 List used = GroovyCategorySupport.getCategoryMethods(sender, name);
392 if (used != null) {
393 answer = new ArrayList(answer);
394 for (Iterator iter = used.iterator(); iter.hasNext();) {
395 MetaMethod element = (MetaMethod) iter.next();
396 removeMatchingMethod(answer,element);
397 }
398 answer.addAll(used);
399 }
400 }
401 return answer;
402 }
403
404 /***
405 * @return all the normal static methods avaiable on this class for the
406 * given name
407 */
408 private List getStaticMethods(Class sender, String name) {
409 Map methodIndex = (Map) classStaticMethodIndex.get(sender);
410 if (methodIndex == null) return Collections.EMPTY_LIST;
411 List answer = (List) methodIndex.get(name);
412 if (answer == null) return Collections.EMPTY_LIST;
413 return answer;
414 }
415
416 public void addNewInstanceMethod(Method method) {
417 NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method));
418 if (! newGroovyMethodsList.contains(newMethod)){
419 newGroovyMethodsList.add(newMethod);
420 addMetaMethod(newMethod);
421 }
422 }
423
424 public void addNewStaticMethod(Method method) {
425 NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method));
426 if (! newGroovyMethodsList.contains(newMethod)){
427 newGroovyMethodsList.add(newMethod);
428 addMetaMethod(newMethod);
429 }
430 }
431
432 private void unwrap(Object[] arguments) {
433
434
435
436
437 for (int i = 0; i != arguments.length; i++) {
438 if (arguments[i] instanceof Wrapper) {
439 arguments[i] = ((Wrapper)arguments[i]).unwrap();
440 }
441 }
442 }
443
444
445 /***
446 * Invokes the given method on the object.
447 * @deprecated
448 */
449 public Object invokeMethod(Object object, String methodName, Object[] originalArguments) {
450 return invokeMethod(theClass,object,methodName,originalArguments,false,false);
451 }
452
453
454 /***
455 * Invokes the given method on the object.
456 *
457 */
458 public Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
459 checkInitalised();
460 if (object == null) {
461 throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
462 }
463 if (log.isLoggable(Level.FINER)){
464 MetaClassHelper.logMethodCall(object, methodName, originalArguments);
465 }
466 Object[] arguments = originalArguments;
467 if (arguments==null) arguments = EMPTY_ARGUMENTS;
468 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
469 unwrap(arguments);
470
471 MetaMethod method = getMethodWithCaching(sender, methodName, argClasses, isCallToSuper);
472
473 if (method==null && arguments.length==1 && arguments[0] instanceof List) {
474 Object[] newArguments = ((List) arguments[0]).toArray();
475 Class[] newArgClasses = MetaClassHelper.convertToTypeArray(newArguments);
476 method = getMethodWithCaching(sender, methodName, newArgClasses, isCallToSuper);
477 if (method!=null) {
478 MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, isCallToSuper);
479 method = new TransformMetaMethod(method) {
480 public Object invoke(Object object, Object[] arguments) {
481 Object firstArgument = arguments[0];
482 List list = (List) firstArgument;
483 arguments = list.toArray();
484 return super.invoke(object, arguments);
485 }
486 };
487 cacheInstanceMethod(methodKey, method);
488 return invokeMethod(sender,object,methodName, originalArguments, isCallToSuper, fromInsideClass);
489 }
490 }
491
492 boolean isClosure = object instanceof Closure;
493 if (isClosure) {
494 Closure closure = (Closure) object;
495 Object delegate = closure.getDelegate();
496 Object owner = closure.getOwner();
497
498
499 if ("call".equals(methodName) || "doCall".equals(methodName)) {
500 if (object.getClass()==MethodClosure.class) {
501 MethodClosure mc = (MethodClosure) object;
502 methodName = mc.getMethod();
503 Class ownerClass = owner.getClass();
504 if (owner instanceof Class) ownerClass = (Class) owner;
505 MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
506 return ownerMetaClass.invokeMethod(ownerClass,owner,methodName,arguments,false,false);
507 } else if (object.getClass()==CurriedClosure.class) {
508 CurriedClosure cc = (CurriedClosure) object;
509
510 arguments = cc.getUncurriedArguments(arguments);
511 Class ownerClass = owner.getClass();
512 if (owner instanceof Class) ownerClass = (Class) owner;
513 MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
514 return ownerMetaClass.invokeMethod(owner,methodName,arguments);
515 }
516 } else if ("curry".equals(methodName)) {
517 return closure.curry(arguments);
518 }
519
520 if (method==null && owner!=closure) {
521 Class ownerClass = owner.getClass();
522 if (owner instanceof Class) ownerClass = (Class) owner;
523 MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
524 method = ownerMetaClass.pickMethod(methodName,argClasses);
525 if (method!=null) return ownerMetaClass.invokeMethod(owner,methodName,originalArguments);
526 }
527 if (method==null && delegate!=closure && delegate!=null) {
528 Class delegateClass = delegate.getClass();
529 if (delegate instanceof Class) delegateClass = (Class) delegate;
530 MetaClass delegateMetaClass = registry.getMetaClass(delegateClass);
531 method = delegateMetaClass.pickMethod(methodName,argClasses);
532 if (method!=null) return delegateMetaClass.invokeMethod(delegate,methodName,originalArguments);
533 }
534 if (method==null) {
535
536
537 MissingMethodException last = null;
538 if (owner!=closure && (owner instanceof GroovyObject)) {
539 try {
540 GroovyObject go = (GroovyObject) owner;
541 return go.invokeMethod(methodName,originalArguments);
542 } catch (MissingMethodException mme) {
543 if (last==null) last = mme;
544 }
545 }
546 if (delegate!=closure && (delegate instanceof GroovyObject)) {
547 try {
548 GroovyObject go = (GroovyObject) delegate;
549 return go.invokeMethod(methodName,originalArguments);
550 } catch (MissingMethodException mme) {
551 last = mme;
552 }
553 }
554 if (last!=null) throw last;
555 }
556
557 }
558
559 if (method != null) {
560 return MetaClassHelper.doMethodInvoke(object, method, arguments);
561 } else {
562
563 try {
564 Object value = this.getProperty(object, methodName);
565 if (value instanceof Closure) {
566 Closure closure = (Closure) value;
567 MetaClass delegateMetaClass = closure.getMetaClass();
568 return delegateMetaClass.invokeMethod(closure.getClass(),closure,"doCall",originalArguments,false,fromInsideClass);
569 }
570 } catch (MissingPropertyException mpe) {}
571
572 throw new MissingMethodException(methodName, theClass, originalArguments, false);
573 }
574 }
575
576 public MetaMethod getMethodWithCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
577
578 if (GroovyCategorySupport.hasCategoryInAnyThread() && !isCallToSuper) {
579 return getMethodWithoutCaching(sender, methodName, arguments, isCallToSuper);
580 } else {
581 MethodKey methodKey = new DefaultMethodKey(sender, methodName, arguments, isCallToSuper);
582 MetaMethod method = (MetaMethod) methodCache.get(methodKey);
583 if (method == null) {
584 method = getMethodWithoutCaching(sender, methodName, arguments, isCallToSuper);
585 cacheInstanceMethod(methodKey, method);
586 }
587 return method;
588 }
589 }
590
591 protected void cacheInstanceMethod(MethodKey key, MetaMethod method) {
592 if (method != null && method.isCacheable()) {
593 methodCache.put(key, method);
594 }
595 }
596
597 protected void cacheStaticMethod(MethodKey key, MetaMethod method) {
598 if (method != null && method.isCacheable()) {
599 staticMethodCache.put(key, method);
600 }
601 }
602
603
604 public Constructor retrieveConstructor(Class[] arguments) {
605 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, arguments, false);
606 if (constructor != null) {
607 return constructor;
608 }
609 constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
610 if (constructor != null) {
611 return constructor;
612 }
613 return null;
614 }
615
616 public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
617 MethodKey methodKey = new DefaultMethodKey(theClass, methodName, arguments, false);
618 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
619 if (method == null) {
620 method = pickStaticMethod(theClass,methodName, arguments);
621 cacheStaticMethod(methodKey, method);
622 }
623 return method;
624 }
625
626 public MetaMethod getMethodWithoutCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
627 MetaMethod method = null;
628 List methods = getMethods(sender,methodName,isCallToSuper);
629 if (methods!=null && !methods.isEmpty()) {
630 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
631 }
632 return method;
633 }
634
635 public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
636 checkInitalised();
637 if (log.isLoggable(Level.FINER)){
638 MetaClassHelper.logMethodCall(object, methodName, arguments);
639 }
640
641 Class sender = object.getClass();
642 if (object instanceof Class) sender = (Class) object;
643 if (sender!=theClass) {
644 MetaClass mc = registry.getMetaClass(sender);
645 return mc.invokeStaticMethod(sender,methodName,arguments);
646 }
647 if (sender==Class.class) {
648 return invokeMethod(object,methodName,arguments);
649 }
650
651 if (arguments==null) arguments = EMPTY_ARGUMENTS;
652 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
653 unwrap(arguments);
654
655
656 MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, false);
657 MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
658 if (method == null) {
659 method = pickStaticMethod(sender, methodName, argClasses);
660 cacheStaticMethod(methodKey.createCopy(), method);
661 }
662
663 if (method != null) {
664 return MetaClassHelper.doMethodInvoke(object, method, arguments);
665 }
666
667 throw new MissingMethodException(methodName, sender, arguments, true);
668 }
669
670 private MetaMethod pickStaticMethod(Class sender, String methodName, Class[] arguments) {
671 MetaMethod method = null;
672 List methods = getStaticMethods(sender,methodName);
673
674 if (!methods.isEmpty()) {
675 method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
676 }
677 if (method == null && theClass != Class.class) {
678 MetaClass classMetaClass = registry.getMetaClass(Class.class);
679 method = classMetaClass.pickMethod(methodName, arguments);
680 }
681 if (method == null) {
682 method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), true);
683 }
684 return method;
685 }
686
687 public Object invokeConstructor(Object[] arguments) {
688 return invokeConstructor(theClass,arguments,false);
689 }
690
691 public int selectConstructorAndTransformArguments(int numberOfCosntructors, Object[] arguments) {
692
693 if (numberOfCosntructors != constructors.size()) {
694 throw new IncompatibleClassChangeError("the number of constructors during runtime and compile time for "+
695 this.theClass.getName()+" do not match. Expected "+numberOfCosntructors+" but got "+constructors.size());
696 }
697
698 if (arguments==null) arguments = EMPTY_ARGUMENTS;
699 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
700 unwrap(arguments);
701 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
702 if (constructor == null) {
703 constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
704 }
705 if (constructor==null) {
706 throw new GroovyRuntimeException(
707 "Could not find matching constructor for: "
708 + theClass.getName()
709 + "("+InvokerHelper.toTypeString(arguments)+")");
710 }
711 List l = new ArrayList(constructors);
712 Comparator comp = new Comparator() {
713 public int compare(Object arg0, Object arg1) {
714 Constructor c0 = (Constructor) arg0;
715 Constructor c1 = (Constructor) arg1;
716 String descriptor0 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c0.getParameterTypes());
717 String descriptor1 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c1.getParameterTypes());
718 return descriptor0.compareTo(descriptor1);
719 }
720 };
721 Collections.sort(l,comp);
722 int found = -1;
723 for (int i=0; i<l.size(); i++) {
724 if (l.get(i)!=constructor) continue;
725 found = i;
726 break;
727 }
728
729 int ret = 0 | (found << 8);
730 return ret;
731 }
732
733 /***
734 * checks if the initialisation of the class id complete.
735 * This method should be called as a form of assert, it is no
736 * way to test if there is still initialisation work to be done.
737 * Such logic must be implemented in a different way.
738 * @throws IllegalStateException if the initialisation is incomplete yet
739 */
740 protected void checkInitalised() {
741 if (!isInitialized())
742 throw new IllegalStateException(
743 "initialize must be called for meta " +
744 "class of "+ theClass +
745 "("+this.getClass() + ") " +
746 "to complete initialisation process " +
747 "before any invocation or field/property " +
748 "access can be done");
749 }
750
751 private Object invokeConstructor(Class at, Object[] arguments, boolean setAccessible) {
752 checkInitalised();
753 if (arguments==null) arguments = EMPTY_ARGUMENTS;
754 Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
755 unwrap(arguments);
756 Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
757 if (constructor != null) {
758 return doConstructorInvoke(at, constructor, arguments, true);
759 }
760 constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
761 if (constructor != null) {
762 return doConstructorInvoke(at, constructor, arguments, true);
763 }
764
765 if (arguments.length == 1) {
766 Object firstArgument = arguments[0];
767 if (firstArgument instanceof Map) {
768 constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
769 if (constructor != null) {
770 Object bean = doConstructorInvoke(at, constructor, MetaClassHelper.EMPTY_ARRAY, true);
771 setProperties(bean, ((Map) firstArgument));
772 return bean;
773 }
774 }
775 }
776 throw new GroovyRuntimeException(
777 "Could not find matching constructor for: "
778 + theClass.getName()
779 + "("+InvokerHelper.toTypeString(arguments)+")");
780 }
781
782 /***
783 * Sets a number of bean properties from the given Map where the keys are
784 * the String names of properties and the values are the values of the
785 * properties to set
786 */
787 public void setProperties(Object bean, Map map) {
788 checkInitalised();
789 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
790 Map.Entry entry = (Map.Entry) iter.next();
791 String key = entry.getKey().toString();
792
793 Object value = entry.getValue();
794 setProperty(bean, key, value);
795 }
796 }
797
798 /***
799 * @return the given property's value on the object
800 */
801 public Object getProperty(Class sender, Object object, String name, boolean useSuper, boolean fromInsideClass) {
802 checkInitalised();
803
804
805
806
807 boolean isStatic = theClass != Class.class && object instanceof Class;
808 if (isStatic && object != theClass) {
809 MetaClass mc = registry.getMetaClass((Class) object);
810 return mc.getProperty(sender,object,name,useSuper,false);
811 }
812
813 MetaMethod method = null;
814 Object[] arguments = EMPTY_ARGUMENTS;
815
816
817
818
819 MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
820 if (mp != null) {
821 if (mp instanceof MetaBeanProperty) {
822 MetaBeanProperty mbp = (MetaBeanProperty) mp;
823 method = mbp.getGetter();
824 mp = mbp.getField();
825 }
826 }
827
828
829 if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
830 String getterName = "get"+MetaClassHelper.capitalize(name);
831 method = getCategoryMethodGetter(sender,getterName,false);
832 }
833
834
835
836
837 if (method==null && mp!=null) {
838 return mp.getProperty(object);
839 }
840
841
842
843
844
845
846 if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
847 method = getCategoryMethodGetter(sender,"get",true);
848 if (method!=null) arguments = new Object[]{name};
849 }
850
851
852
853 if (method==null && genericGetMethod != null && !(!genericGetMethod.isStatic() && isStatic)) {
854 arguments = new Object[]{ name };
855 method = genericGetMethod;
856 }
857
858
859
860
861 if (method==null) {
862 /*** todo these special cases should be special MetaClasses maybe */
863 if (theClass != Class.class && object instanceof Class) {
864 MetaClass mc = registry.getMetaClass(Class.class);
865 return mc.getProperty(Class.class,object,name,useSuper,false);
866 } else if (object instanceof Collection) {
867 return DefaultGroovyMethods.getAt((Collection) object, name);
868 } else if (object instanceof Object[]) {
869 return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), name);
870 } else {
871 MetaMethod addListenerMethod = (MetaMethod) listeners.get(name);
872 if (addListenerMethod != null) {
873
874 return null;
875 }
876 }
877 } else {
878
879
880
881
882 return MetaClassHelper.doMethodInvoke(object,method,arguments);
883 }
884
885
886
887
888 throw new MissingPropertyException(name, theClass);
889 }
890
891 private MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
892 List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
893 if (possibleGenericMethods != null) {
894 for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
895 MetaMethod mmethod = (MetaMethod) iter.next();
896 Class[] paramTypes = mmethod.getParameterTypes();
897 if (useLongVersion) {
898 if (paramTypes.length==1 && paramTypes[0] == String.class) {
899 return mmethod;
900 }
901 } else {
902 if (paramTypes.length==0) return mmethod;
903 }
904 }
905 }
906 return null;
907 }
908
909 private MetaMethod getCategoryMethodSetter(Class sender, String name, boolean useLongVersion) {
910 List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
911 if (possibleGenericMethods != null) {
912 for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
913 MetaMethod mmethod = (MetaMethod) iter.next();
914 Class[] paramTypes = mmethod.getParameterTypes();
915 if (useLongVersion) {
916 if (paramTypes.length==2 && paramTypes[0] == String.class) {
917 return mmethod;
918 }
919 } else {
920 if (paramTypes.length==1) return mmethod;
921 }
922 }
923 }
924 return null;
925 }
926
927 /***
928 * Get all the properties defined for this type
929 * @return a list of MetaProperty objects
930 */
931 public List getProperties() {
932 checkInitalised();
933 Map propertyMap = (Map) classPropertyIndex.get(theClass);
934
935 List ret = new ArrayList(propertyMap.size());
936 for (Iterator iter = propertyMap.values().iterator(); iter.hasNext();) {
937 MetaProperty element = (MetaProperty) iter.next();
938 if (element instanceof MetaFieldProperty) continue;
939
940 if (element instanceof MetaBeanProperty) {
941 MetaBeanProperty mp = (MetaBeanProperty) element;
942 boolean setter = true;
943 boolean getter = true;
944 if (mp.getGetter()==null || mp.getGetter() instanceof NewInstanceMetaMethod) {
945 getter=false;
946 }
947 if (mp.getSetter()==null || mp.getSetter() instanceof NewInstanceMetaMethod) {
948 setter=false;
949 }
950 if (!setter && !getter) continue;
951 if (!setter && mp.getSetter()!=null) {
952 element = new MetaBeanProperty(mp.getName(),mp.getType(),mp.getGetter(),null);
953 }
954 if (!getter && mp.getGetter()!=null) {
955 element = new MetaBeanProperty(mp.getName(),mp.getType(), null, mp.getSetter());
956 }
957 }
958 ret.add(element);
959 }
960 return ret;
961 }
962
963 private MetaMethod findPropertyMethod(List methods, boolean isGetter) {
964 LinkedList ret = new LinkedList();
965 for (Iterator iter = methods.iterator(); iter.hasNext();) {
966 MetaMethod element = (MetaMethod) iter.next();
967 if ( !isGetter &&
968
969 element.getParameterTypes().length == 1)
970 {
971 ret.add(element);
972 }
973 if ( isGetter &&
974 !(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) &&
975 element.getParameterTypes().length == 0)
976 {
977 ret.add(element);
978 }
979 }
980 if (ret.size() == 0) return null;
981 if (ret.size() == 1) return (MetaMethod) ret.getFirst();
982
983
984
985
986
987
988 MetaMethod method = null;
989 int distance = -1;
990 for (Iterator iter = ret.iterator(); iter.hasNext();) {
991 MetaMethod element = (MetaMethod) iter.next();
992 Class c;
993 if (isGetter) {
994 c = element.getReturnType();
995 } else {
996 c = element.getParameterTypes()[0];
997 }
998 int localDistance = distanceToObject(c);
999
1000 if (distance==-1 || distance>localDistance) {
1001 distance = localDistance;
1002 method = element;
1003 }
1004 }
1005 return method;
1006 }
1007
1008 private static int distanceToObject(Class c) {
1009 int count;
1010 for (count=0; c!=null; count++) {
1011 c=c.getSuperclass();
1012 }
1013 return count;
1014 }
1015
1016
1017 /***
1018 * This will build up the property map (Map of MetaProperty objects, keyed on
1019 * property name).
1020 */
1021 private void setupProperties(PropertyDescriptor[] propertyDescriptors) {
1022 LinkedList superClasses = getSuperClasses();
1023 Set interfaces = new HashSet();
1024 makeInterfaceSet(theClass,interfaces);
1025
1026
1027 if (theClass.isArray()) {
1028 Map map = new HashMap();
1029 map.put("length", arrayLengthProperty);
1030 classPropertyIndex.put(theClass,map);
1031 }
1032
1033 inheritStaticInterfaceFields(superClasses, interfaces);
1034 inheritFields(superClasses);
1035 applyPropertyDescriptors(propertyDescriptors);
1036
1037 applyStrayPropertyMethods(superClasses,classMethodIndex,classPropertyIndex);
1038 applyStrayPropertyMethods(superClasses,classMethodIndexForSuper,classPropertyIndexForSuper);
1039
1040 copyClassPropertyIndexForSuper();
1041 makeStaticPropertyIndex();
1042 }
1043
1044 private void makeStaticPropertyIndex() {
1045 Map propertyMap = (Map) classPropertyIndex.get(theClass);
1046 for (Iterator iter = propertyMap.entrySet().iterator(); iter.hasNext();) {
1047 Map.Entry entry = (Map.Entry) iter.next();
1048 MetaProperty mp = (MetaProperty) entry.getValue();
1049 if (mp instanceof MetaFieldProperty) {
1050 MetaFieldProperty mfp = (MetaFieldProperty) mp;
1051 if (!mfp.isStatic()) continue;
1052 } else if (mp instanceof MetaBeanProperty) {
1053 MetaBeanProperty mbp = (MetaBeanProperty) mp;
1054 boolean getter = mbp.getGetter()==null || mbp.getGetter().isStatic();
1055 boolean setter = mbp.getSetter()==null || mbp.getSetter().isStatic();
1056 boolean field = mbp.getField()==null || mbp.getField().isStatic();
1057
1058 if (!getter && !setter && !field) {
1059 continue;
1060 } else if (setter && getter) {
1061 if (field) {
1062 mp = mbp;
1063 } else {
1064 mp = new MetaBeanProperty(mbp.getName(),mbp.getType(),mbp.getGetter(),mbp.getSetter());
1065 }
1066 } else if (getter && !setter) {
1067 if (mbp.getGetter()==null) {
1068 mp = mbp.getField();
1069 } else {
1070 MetaBeanProperty newmp = new MetaBeanProperty(mbp.getName(),mbp.getType(),mbp.getGetter(),null);
1071 if (field) newmp.setField(mbp.getField());
1072 mp = newmp;
1073 }
1074 } else if (setter && !getter) {
1075 if (mbp.getSetter()==null) {
1076 mp = mbp.getField();
1077 } else {
1078 MetaBeanProperty newmp = new MetaBeanProperty(mbp.getName(),mbp.getType(),null,mbp.getSetter());
1079 if (field) newmp.setField(mbp.getField());
1080 mp = newmp;
1081 }
1082 } else if (field) {
1083 mp = mbp.getField();
1084 }
1085 } else {
1086 continue;
1087 }
1088 if (mp==null) continue;
1089 staticPropertyIndex.put(entry.getKey(),mp);
1090 }
1091
1092 }
1093
1094 private void copyClassPropertyIndexForSuper() {
1095 for (Iterator iter = classPropertyIndex.entrySet().iterator(); iter.hasNext();) {
1096 Map.Entry entry = (Map.Entry) iter.next();
1097 HashMap newVal = new HashMap((Map)entry.getValue());
1098 classPropertyIndexForSuper.put(entry.getKey(),newVal);
1099 }
1100 }
1101
1102 private Map getMap2MapNotNull(Map m, Object key) {
1103 Map ret = (Map) m.get(key);
1104 if (ret==null) {
1105 ret = new HashMap();
1106 m.put(key,ret);
1107 }
1108 return ret;
1109 }
1110
1111 private void inheritStaticInterfaceFields(LinkedList superClasses, Set interfaces) {
1112 for (Iterator interfaceIter = interfaces.iterator(); interfaceIter.hasNext();) {
1113 Class iclass = (Class) interfaceIter.next();
1114 Map iPropertyIndex = getMap2MapNotNull(classPropertyIndex,iclass);
1115 addFields(iclass,iPropertyIndex);
1116 for (Iterator classIter = superClasses.iterator(); classIter.hasNext();) {
1117 Class sclass = (Class) classIter.next();
1118 if (! iclass.isAssignableFrom(sclass)) continue;
1119 Map sPropertyIndex = getMap2MapNotNull(classPropertyIndex,sclass);
1120 copyNonPrivateFields(iPropertyIndex,sPropertyIndex);
1121 }
1122 }
1123 }
1124
1125 private void inheritFields(LinkedList superClasses) {
1126 Map last = null;
1127 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
1128 Class klass = (Class) iter.next();
1129 Map propertyIndex = getMap2MapNotNull(classPropertyIndex,klass);
1130 if (last != null) {
1131 copyNonPrivateFields(last,propertyIndex);
1132 }
1133 last = propertyIndex;
1134 addFields(klass,propertyIndex);
1135 }
1136 }
1137
1138 private void addFields(final Class klass, Map propertyIndex) {
1139 Field[] fields = (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
1140 public Object run() {
1141 return klass.getDeclaredFields();
1142 }
1143 });
1144 for(int i = 0; i < fields.length; i++) {
1145 MetaFieldProperty mfp = new MetaFieldProperty(fields[i]);
1146 propertyIndex.put(fields[i].getName(), mfp);
1147 }
1148 }
1149
1150 private void copyNonPrivateFields(Map from, Map to) {
1151 for (Iterator iter = from.entrySet().iterator(); iter.hasNext();) {
1152 Map.Entry entry = (Map.Entry) iter.next();
1153 MetaFieldProperty mfp = (MetaFieldProperty) entry.getValue();
1154 if (!Modifier.isPublic(mfp.getModifiers()) && !Modifier.isProtected(mfp.getModifiers())) continue;
1155 to.put(entry.getKey(),mfp);
1156 }
1157 }
1158
1159 private void applyStrayPropertyMethods(LinkedList superClasses, Map classMethodIndex, Map classPropertyIndex) {
1160
1161 for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
1162 Class klass = (Class) iter.next();
1163 Map methodIndex = (Map) classMethodIndex.get(klass);
1164 Map propertyIndex = getMap2MapNotNull(classPropertyIndex,klass);
1165 for (Iterator nameMethodIterator = methodIndex.entrySet().iterator(); nameMethodIterator.hasNext();) {
1166 Map.Entry entry = (Map.Entry) nameMethodIterator.next();
1167 String methodName = (String) entry.getKey();
1168
1169 if (methodName.length() < 4) continue;
1170
1171 boolean isGetter = methodName.startsWith("get");
1172 boolean isSetter = methodName.startsWith("set");
1173 if (!isGetter && !isSetter) continue;
1174
1175
1176 String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
1177 MetaMethod propertyMethod = findPropertyMethod((List) entry.getValue(), isGetter);
1178 if (propertyMethod==null) continue;
1179
1180 createMetaBeanProperty(propertyIndex, propName, isGetter, propertyMethod);
1181 }
1182 }
1183 }
1184
1185 private void createMetaBeanProperty(Map propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod){
1186
1187 MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
1188 if (mp == null) {
1189 if (isGetter) {
1190 mp = new MetaBeanProperty(propName,
1191 propertyMethod.getReturnType(),
1192 propertyMethod, null);
1193 } else {
1194
1195 mp = new MetaBeanProperty(propName,
1196 propertyMethod.getParameterTypes()[0],
1197 null, propertyMethod);
1198 }
1199 } else {
1200 MetaBeanProperty mbp;
1201 MetaFieldProperty mfp;
1202 if (mp instanceof MetaBeanProperty) {
1203 mbp = (MetaBeanProperty) mp;
1204 mfp = mbp.getField();
1205 } else if (mp instanceof MetaFieldProperty){
1206 mfp = (MetaFieldProperty) mp;
1207 mbp = new MetaBeanProperty(propName,
1208 mfp.getType(),
1209 null, null);
1210 } else {
1211 throw new GroovyBugError("unknown MetaProperty class used. Class is "+mp.getClass());
1212 }
1213
1214 if (isGetter && mbp.getGetter()==null) {
1215 mbp.setGetter(propertyMethod);
1216 } else if (!isGetter && mbp.getSetter()==null) {
1217 mbp.setSetter(propertyMethod);
1218 }
1219 mbp.setField(mfp);
1220 mp = mbp;
1221 }
1222 propertyIndex.put(propName, mp);
1223 }
1224
1225 private void applyPropertyDescriptors(PropertyDescriptor[] propertyDescriptors) {
1226 Map propertyMap = (Map) classPropertyIndex.get(theClass);
1227
1228
1229 for(int i=0; i<propertyDescriptors.length; i++) {
1230 PropertyDescriptor pd = propertyDescriptors[i];
1231
1232
1233
1234
1235 if(pd.getPropertyType() == null)
1236 continue;
1237
1238
1239 Method method = pd.getReadMethod();
1240 MetaMethod getter;
1241 if(method != null)
1242 getter = findMethod(method);
1243 else
1244 getter = null;
1245
1246
1247 MetaMethod setter;
1248 method = pd.getWriteMethod();
1249 if(method != null)
1250 setter = findMethod(method);
1251 else
1252 setter = null;
1253
1254
1255 MetaBeanProperty mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter);
1256
1257
1258 MetaFieldProperty field = null;
1259 MetaProperty old = (MetaProperty) propertyMap.get(pd.getName());
1260 if (old!=null) {
1261 if (old instanceof MetaBeanProperty) {
1262 field = ((MetaBeanProperty) old).getField();
1263 } else {
1264 field = (MetaFieldProperty) old;
1265 }
1266 mp.setField(field);
1267 }
1268
1269
1270
1271 propertyMap.put(pd.getName(), mp);
1272 }
1273 }
1274
1275 /***
1276 * Sets the property value on an object
1277 */
1278 public void setProperty(Class sender,Object object, String name, Object newValue, boolean useSuper, boolean fromInsideClass) {
1279 checkInitalised();
1280
1281
1282
1283
1284 boolean isStatic = theClass != Class.class && object instanceof Class;
1285 if (isStatic && object != theClass) {
1286 MetaClass mc = registry.getMetaClass((Class) object);
1287 mc.getProperty(sender,object,name,useSuper,fromInsideClass);
1288 return;
1289 }
1290
1291
1292
1293
1294 if (newValue instanceof Wrapper) newValue = ((Wrapper)newValue).unwrap();
1295
1296
1297
1298 MetaMethod method = null;
1299 Object[] arguments = null;
1300
1301
1302
1303
1304 MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
1305 MetaProperty field = null;
1306 if (mp != null) {
1307 if (mp instanceof MetaBeanProperty) {
1308 MetaBeanProperty mbp = (MetaBeanProperty) mp;
1309 method = mbp.getSetter();
1310 if (method!=null) arguments = new Object[] { newValue };
1311 field = mbp.getField();
1312 } else {
1313 field = mp;
1314 }
1315 }
1316
1317
1318 if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
1319 String getterName = "set"+MetaClassHelper.capitalize(name);
1320 method = getCategoryMethodSetter(sender,getterName,false);
1321 if (method!=null) arguments = new Object[] { newValue };
1322 }
1323
1324
1325
1326
1327 boolean ambigousListener = false;
1328 boolean usesProxy = false;
1329 if (method==null) {
1330 method = (MetaMethod) listeners.get(name);
1331 ambigousListener = method == AMBIGOUS_LISTENER_METHOD;
1332 if ( method != null &&
1333 !ambigousListener &&
1334 newValue instanceof Closure)
1335 {
1336
1337 Object proxy =
1338 MetaClassHelper.createListenerProxy(method.getParameterTypes()[0], name, (Closure) newValue);
1339 arguments = new Object[] { proxy };
1340 newValue = proxy;
1341 usesProxy = true;
1342 } else {
1343 method = null;
1344 }
1345 }
1346
1347
1348
1349
1350 if (method==null && field!=null) {
1351 field.setProperty(object,newValue);
1352 return;
1353 }
1354
1355
1356
1357
1358
1359 if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
1360 method = getCategoryMethodSetter(sender,"set",true);
1361 if (method!=null) arguments = new Object[]{name,newValue};
1362 }
1363
1364
1365
1366 if (method==null && genericSetMethod != null && !(!genericSetMethod.isStatic() && isStatic)) {
1367 arguments = new Object[]{ name, newValue };
1368 method = genericSetMethod;
1369 }
1370
1371
1372
1373
1374 if (method!=null) {
1375 if (arguments.length==1) {
1376 newValue = DefaultTypeTransformation.castToType(
1377 newValue,
1378 method.getParameterTypes()[0]);
1379 arguments[0] = newValue;
1380 } else {
1381 newValue = DefaultTypeTransformation.castToType(
1382 newValue,
1383 method.getParameterTypes()[1]);
1384 arguments[1] = newValue;
1385 }
1386 MetaClassHelper.doMethodInvoke(object,method,arguments);
1387 return;
1388 }
1389
1390
1391
1392
1393 if (ambigousListener){
1394 throw new GroovyRuntimeException("There are multiple listeners for the property "+name+". Please do not use the bean short form to access this listener.");
1395 }
1396 throw new MissingPropertyException(name, theClass);
1397 }
1398
1399 private MetaProperty getMetaProperty(Class clazz, String name, boolean useSuper, boolean useStatic) {
1400 Map propertyMap;
1401 if (useStatic) {
1402 propertyMap = staticPropertyIndex;
1403 } else if (useSuper){
1404 propertyMap = (Map) classPropertyIndexForSuper.get(clazz);
1405 } else {
1406 propertyMap = (Map) classPropertyIndex.get(clazz);
1407 }
1408 if (propertyMap==null) {
1409 if (clazz!=theClass) {
1410 return getMetaProperty(theClass,name,useSuper, useStatic);
1411 } else {
1412 return null;
1413 }
1414 }
1415 return (MetaProperty) propertyMap.get(name);
1416 }
1417
1418
1419 /***
1420 * Looks up the given attribute (field) on the given object
1421 */
1422 public Object getAttribute(Class sender, Object object, String attribute, boolean useSuper, boolean fromInsideClass) {
1423 checkInitalised();
1424
1425 boolean isStatic = theClass != Class.class && object instanceof Class;
1426 if (isStatic && object != theClass) {
1427 MetaClass mc = registry.getMetaClass((Class) object);
1428 return mc.getAttribute(sender,object,attribute,useSuper);
1429 }
1430
1431 MetaProperty mp = getMetaProperty(sender,attribute,useSuper, isStatic);
1432
1433 if (mp != null) {
1434 if (mp instanceof MetaBeanProperty) {
1435 MetaBeanProperty mbp = (MetaBeanProperty) mp;
1436 mp = mbp.getField();
1437 }
1438 try {
1439
1440 if (mp != null) return mp.getProperty(object);
1441 } catch(Exception e) {
1442 throw new GroovyRuntimeException("Cannot read field: " + attribute,e);
1443 }
1444 }
1445
1446 throw new MissingFieldException(attribute, theClass);
1447 }
1448
1449 /***
1450 * Sets the given attribute (field) on the given object
1451 */
1452 public void setAttribute(Class sender, Object object, String attribute, Object newValue, boolean useSuper, boolean fromInsideClass) {
1453 checkInitalised();
1454
1455 boolean isStatic = theClass != Class.class && object instanceof Class;
1456 if (isStatic && object != theClass) {
1457 MetaClass mc = registry.getMetaClass((Class) object);
1458 mc.setAttribute(sender,object,attribute,newValue,useSuper,fromInsideClass);
1459 return;
1460 }
1461
1462 MetaProperty mp = getMetaProperty(sender,attribute,useSuper, isStatic);
1463
1464 if (mp != null) {
1465 if (mp instanceof MetaBeanProperty) {
1466 MetaBeanProperty mbp = (MetaBeanProperty) mp;
1467 mp = mbp.getField();
1468 }
1469 if (mp != null) {
1470 mp.setProperty(object,newValue);
1471 return;
1472 }
1473 }
1474
1475 throw new MissingFieldException(attribute, theClass);
1476 }
1477
1478 public ClassNode getClassNode() {
1479 if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) {
1480
1481 String className = theClass.getName();
1482 String groovyFile = className;
1483 int idx = groovyFile.indexOf('$');
1484 if (idx > 0) {
1485 groovyFile = groovyFile.substring(0, idx);
1486 }
1487 groovyFile = groovyFile.replace('.', '/') + ".groovy";
1488
1489
1490 URL url = theClass.getClassLoader().getResource(groovyFile);
1491 if (url == null) {
1492 url = Thread.currentThread().getContextClassLoader().getResource(groovyFile);
1493 }
1494 if (url != null) {
1495 try {
1496
1497 /***
1498 * todo there is no CompileUnit in scope so class name
1499 * checking won't work but that mostly affects the bytecode
1500 * generation rather than viewing the AST
1501 */
1502 CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
1503 public void call( ClassVisitor writer, ClassNode node ) {
1504 if( node.getName().equals(theClass.getName()) ) {
1505 MetaClassImpl.this.classNode = node;
1506 }
1507 }
1508 };
1509
1510 final ClassLoader parent = theClass.getClassLoader();
1511 GroovyClassLoader gcl = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
1512 public Object run() {
1513 return new GroovyClassLoader(parent);
1514 }
1515 });
1516 CompilationUnit unit = new CompilationUnit( );
1517 unit.setClassgenCallback( search );
1518 unit.addSource( url );
1519 unit.compile( Phases.CLASS_GENERATION );
1520 }
1521 catch (Exception e) {
1522 throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e);
1523 }
1524 }
1525
1526 }
1527 return classNode;
1528 }
1529
1530 public String toString() {
1531 return super.toString() + "[" + theClass + "]";
1532 }
1533
1534
1535
1536
1537 /***
1538 * Adds all the methods declared in the given class to the metaclass
1539 * ignoring any matching methods already defined by a derived class
1540 *
1541 * @param theClass
1542 */
1543 private void addMethods(final Class theClass) {
1544 Map methodIndex = (Map) classMethodIndex.get(theClass);
1545 if (methodIndex==null) {
1546 methodIndex = new HashMap();
1547 classMethodIndex.put(theClass,methodIndex);
1548 }
1549
1550 Method[] methodArray = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
1551 public Object run() {
1552 return theClass.getDeclaredMethods();
1553 }
1554 });
1555 for (int i = 0; i < methodArray.length; i++) {
1556 Method reflectionMethod = methodArray[i];
1557 if ( reflectionMethod.getName().indexOf('+') >= 0 ) {
1558
1559 continue;
1560 } else if (Modifier.isAbstract(reflectionMethod.getModifiers())) {
1561 continue;
1562 }
1563 MetaMethod method = createMetaMethod(reflectionMethod);
1564 addMetaMethod(method);
1565 }
1566
1567 List methods = registry.getInstanceMethods();
1568 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1569 Method element = (Method) iter.next();
1570 if (element.getParameterTypes()[0]!=theClass) continue;
1571 addNewInstanceMethod(element);
1572 }
1573
1574 methods = registry.getStaticMethods();
1575 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1576 Method element = (Method) iter.next();
1577 if (element.getParameterTypes()[0]!=theClass) continue;
1578 addNewStaticMethod(element);
1579 }
1580 }
1581
1582 private void addToClassMethodIndex(MetaMethod method, Map classMethodIndex) {
1583 Map methodIndex = (Map) classMethodIndex.get(method.getDeclaringClass());
1584 if (methodIndex==null) {
1585 methodIndex = new HashMap();
1586 classMethodIndex.put(method.getDeclaringClass(),methodIndex);
1587 }
1588 String name = method.getName();
1589 List list = (List) methodIndex.get(name);
1590 if (list == null) {
1591 list = new ArrayList();
1592 methodIndex.put(name, list);
1593 list.add(method);
1594 } else {
1595 addMethodToList(list,method);
1596 }
1597 }
1598
1599 /***
1600 * adds a MetaMethod to this class. WARNING: this method will not
1601 * do the neccessary steps for multimethod logic and using this
1602 * method doesn't mean, that a method added here is replacing another
1603 * method from a parent class completely. These steps are usually done
1604 * by initalize, which means if you need these steps, you have to add
1605 * the method before running initialize the first time.
1606 * @see #initialize()
1607 * @param method the MetaMethod
1608 */
1609 protected void addMetaMethod(MetaMethod method) {
1610 if (isInitialized()) {
1611 throw new RuntimeException("Already initialized, cannot add new method: " + method);
1612 }
1613 if (isGenericGetMethod(method) && genericGetMethod == null) {
1614 genericGetMethod = method;
1615 }
1616 else if (MetaClassHelper.isGenericSetMethod(method) && genericSetMethod == null) {
1617 genericSetMethod = method;
1618 }
1619 if (method.isStatic()) {
1620 addToClassMethodIndex(method,classStaticMethodIndex);
1621 }
1622 addToClassMethodIndex(method,classMethodIndex);
1623 }
1624
1625 protected boolean isInitialized(){
1626 return initialized;
1627 }
1628
1629 private void addMethodToList(List list, MetaMethod method) {
1630 MetaMethod match = removeMatchingMethod(list,method);
1631 if (match==null) {
1632 list.add(method);
1633 } else if (match.isPrivate()){
1634
1635
1636
1637
1638
1639 list.add(match);
1640 } else {
1641 Class methodC = method.getDeclaringClass();
1642 Class matchC = match.getDeclaringClass();
1643 if (methodC == matchC){
1644 if (method instanceof NewInstanceMetaMethod) {
1645
1646 list.add(method);
1647 } else {
1648 list.add(match);
1649 }
1650 } else if (MetaClassHelper.isAssignableFrom(methodC,matchC)){
1651 list.add(match);
1652 } else {
1653 list.add(method);
1654 }
1655 }
1656 }
1657
1658 /***
1659 * remove a method of the same matching prototype was found in the list
1660 */
1661 private MetaMethod removeMatchingMethod(List list, MetaMethod method) {
1662 for (Iterator iter = list.iterator(); iter.hasNext();) {
1663 MetaMethod aMethod = (MetaMethod) iter.next();
1664 Class[] params1 = aMethod.getParameterTypes();
1665 Class[] params2 = method.getParameterTypes();
1666 if (params1.length == params2.length) {
1667 boolean matches = true;
1668 for (int i = 0; i < params1.length; i++) {
1669 if (params1[i] != params2[i]) {
1670 matches = false;
1671 break;
1672 }
1673 }
1674 if (matches) {
1675 iter.remove();
1676 return (MetaMethod) aMethod;
1677 }
1678 }
1679 }
1680 return null;
1681 }
1682
1683 /***
1684 * @return the matching method which should be found
1685 */
1686 private MetaMethod findMethod(Method aMethod) {
1687 List methods = getMethods(theClass,aMethod.getName(),false);
1688 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1689 MetaMethod method = (MetaMethod) iter.next();
1690 if (method.isMethod(aMethod)) {
1691 return method;
1692 }
1693 }
1694
1695 return new ReflectionMetaMethod(aMethod);
1696 }
1697
1698 /***
1699 * @return the getter method for the given object
1700 */
1701 private MetaMethod findGetter(Object object, String name) {
1702 List methods = getMethods(theClass,name,false);
1703 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1704 MetaMethod method = (MetaMethod) iter.next();
1705 if (method.getParameterTypes().length == 0) {
1706 return method;
1707 }
1708 }
1709 return null;
1710 }
1711
1712 /***
1713 * @return the Method of the given name with no parameters or null
1714 */
1715 private MetaMethod findStaticGetter(Class type, String name) {
1716 List methods = getStaticMethods(type, name);
1717 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1718 MetaMethod method = (MetaMethod) iter.next();
1719 if (method.getParameterTypes().length == 0) {
1720 return method;
1721 }
1722 }
1723
1724 /*** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
1725 try {
1726 Method method = type.getMethod(name, MetaClassHelper.EMPTY_TYPE_ARRAY);
1727 if ((method.getModifiers() & Modifier.STATIC) != 0) {
1728 return findMethod(method);
1729 }
1730 else {
1731 return null;
1732 }
1733 }
1734 catch (Exception e) {
1735 return null;
1736 }
1737 }
1738
1739 private static Object doConstructorInvoke(final Class at, Constructor constructor, Object[] argumentArray, boolean setAccessible) {
1740 if (log.isLoggable(Level.FINER)) {
1741 MetaClassHelper.logMethodCall(constructor.getDeclaringClass(), constructor.getName(), argumentArray);
1742 }
1743
1744 if (setAccessible) {
1745
1746
1747 final boolean accessible = MetaClassHelper.accessibleToConstructor(at, constructor);
1748 final Constructor ctor = constructor;
1749 AccessController.doPrivileged(new PrivilegedAction() {
1750 public Object run() {
1751 ctor.setAccessible(accessible);
1752 return null;
1753 }
1754 });
1755 }
1756 return MetaClassHelper.doConstructorInvoke(constructor,argumentArray);
1757 }
1758
1759 /***
1760 * Chooses the correct method to use from a list of methods which match by
1761 * name.
1762 *
1763 * @param methods
1764 * the possible methods to choose from
1765 * @param arguments
1766 * the original argument to the method
1767 */
1768 private Object chooseMethod(String methodName, List methods, Class[] arguments, boolean coerce) {
1769 int methodCount = methods.size();
1770 if (methodCount <= 0) {
1771 return null;
1772 }
1773 else if (methodCount == 1) {
1774 Object method = methods.get(0);
1775 if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
1776 return method;
1777 }
1778 return null;
1779 }
1780 Object answer = null;
1781 if (arguments == null || arguments.length == 0) {
1782 answer = MetaClassHelper.chooseEmptyMethodParams(methods);
1783 }
1784 else if (arguments.length == 1 && arguments[0] == null) {
1785 answer = MetaClassHelper.chooseMostGeneralMethodWith1NullParam(methods);
1786 }
1787 else {
1788 List matchingMethods = new ArrayList();
1789
1790 for (Iterator iter = methods.iterator(); iter.hasNext();) {
1791 Object method = iter.next();
1792
1793
1794 if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
1795 matchingMethods.add(method);
1796 }
1797 }
1798 if (matchingMethods.isEmpty()) {
1799 return null;
1800 }
1801 else if (matchingMethods.size() == 1) {
1802 return matchingMethods.get(0);
1803 }
1804 return chooseMostSpecificParams(methodName, matchingMethods, arguments);
1805
1806 }
1807 if (answer != null) {
1808 return answer;
1809 }
1810 throw new GroovyRuntimeException(
1811 "Could not find which method to invoke from this list: "
1812 + methods
1813 + " for arguments: "
1814 + InvokerHelper.toString(arguments));
1815 }
1816
1817 private Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
1818
1819 long matchesDistance = -1;
1820 LinkedList matches = new LinkedList();
1821 for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
1822 Object method = iter.next();
1823 Class[] paramTypes = MetaClassHelper.getParameterTypes(method);
1824 if (!MetaClassHelper.parametersAreCompatible(arguments, paramTypes)) continue;
1825 long dist = MetaClassHelper.calculateParameterDistance(arguments, paramTypes);
1826 if (dist==0) return method;
1827 if (matches.size()==0) {
1828 matches.add(method);
1829 matchesDistance = dist;
1830 } else if (dist<matchesDistance) {
1831 matchesDistance=dist;
1832 matches.clear();
1833 matches.add(method);
1834 } else if (dist==matchesDistance) {
1835 matches.add(method);
1836 }
1837
1838 }
1839 if (matches.size()==1) {
1840 return matches.getFirst();
1841 }
1842 if (matches.size()==0) {
1843 return null;
1844 }
1845
1846
1847 String msg = "Ambiguous method overloading for method ";
1848 msg+= theClass.getName()+"#"+name;
1849 msg+= ".\nCannot resolve which method to invoke for ";
1850 msg+= InvokerHelper.toString(arguments);
1851 msg+= " due to overlapping prototypes between:";
1852 for (Iterator iter = matches.iterator(); iter.hasNext();) {
1853 Class[] types=MetaClassHelper.getParameterTypes(iter.next());
1854 msg+= "\n\t"+InvokerHelper.toString(types);
1855 }
1856 throw new GroovyRuntimeException(msg);
1857 }
1858
1859 private boolean isGenericGetMethod(MetaMethod method) {
1860 if (method.getName().equals("get")) {
1861 Class[] parameterTypes = method.getParameterTypes();
1862 return parameterTypes.length == 1 && parameterTypes[0] == String.class;
1863 }
1864 return false;
1865 }
1866
1867 /***
1868 * Call this method when any mutation method is called, such as adding a new
1869 * method to this MetaClass so that any caching or bytecode generation can be
1870 * regenerated.
1871 */
1872 private synchronized void onMethodChange() {
1873 reflector = null;
1874 }
1875
1876
1877 public synchronized void initialize() {
1878 if (!isInitialized()) {
1879 fillMethodIndex();
1880 addProperties();
1881 initialized = true;
1882 }
1883 if (reflector == null) {
1884 generateReflector();
1885 }
1886 }
1887
1888 private void addProperties() {
1889 BeanInfo info;
1890
1891 try {
1892 info =(BeanInfo) AccessController.doPrivileged(new PrivilegedExceptionAction() {
1893 public Object run() throws IntrospectionException {
1894 return Introspector.getBeanInfo(theClass);
1895 }
1896 });
1897 } catch (PrivilegedActionException pae) {
1898 throw new GroovyRuntimeException("exception while bean introspection",pae.getException());
1899 }
1900 PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
1901
1902
1903
1904 setupProperties(descriptors);
1905
1906 EventSetDescriptor[] eventDescriptors = info.getEventSetDescriptors();
1907 for (int i = 0; i < eventDescriptors.length; i++) {
1908 EventSetDescriptor descriptor = eventDescriptors[i];
1909 Method[] listenerMethods = descriptor.getListenerMethods();
1910 for (int j = 0; j < listenerMethods.length; j++) {
1911 Method listenerMethod = listenerMethods[j];
1912 MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod());
1913 String name = listenerMethod.getName();
1914 if (listeners.containsKey(name)) {
1915 listeners.put(name, AMBIGOUS_LISTENER_METHOD);
1916 } else{
1917 listeners.put(name, metaMethod);
1918 }
1919 }
1920 }
1921 }
1922
1923 private MetaMethod createMetaMethod(final Method method) {
1924 if (registry.useAccessible()) {
1925 AccessController.doPrivileged(new PrivilegedAction() {
1926 public Object run() {
1927 method.setAccessible(true);
1928 return null;
1929 }
1930 });
1931 }
1932
1933 MetaMethod answer = new MetaMethod(method);
1934 if (isValidReflectorMethod(answer)) {
1935 allMethods.add(answer);
1936 answer.setMethodIndex(allMethods.size());
1937 }
1938 else {
1939
1940 answer = new ReflectionMetaMethod(method);
1941 }
1942
1943 if (useReflection) {
1944
1945 return new ReflectionMetaMethod(method);
1946 }
1947
1948 return answer;
1949 }
1950
1951 private boolean isValidReflectorMethod(MetaMethod method) {
1952
1953 if (!method.isPublic()) {
1954 return false;
1955 }
1956
1957 List interfaceMethods = getInterfaceMethods();
1958 for (Iterator iter = interfaceMethods.iterator(); iter.hasNext();) {
1959 MetaMethod aMethod = (MetaMethod) iter.next();
1960 if (method.isSame(aMethod)) {
1961 method.setInterfaceClass(aMethod.getCallClass());
1962 return true;
1963 }
1964 }
1965
1966
1967 Class declaringClass = method.getCallClass();
1968 for (Class clazz=declaringClass; clazz!=null; clazz=clazz.getSuperclass()) {
1969 try {
1970 final Class klazz = clazz;
1971 final String mName = method.getName();
1972 final Class[] parms = method.getParameterTypes();
1973 try {
1974 Method m = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
1975 public Object run() throws NoSuchMethodException {
1976 return klazz.getDeclaredMethod(mName, parms);
1977 }
1978 });
1979 if (!Modifier.isPublic(clazz.getModifiers())) continue;
1980 if (!Modifier.isPublic(m.getModifiers())) continue;
1981 declaringClass = clazz;
1982 } catch (PrivilegedActionException pae) {
1983 if (pae.getException() instanceof NoSuchMethodException) {
1984 throw (NoSuchMethodException) pae.getException();
1985 } else {
1986 throw new RuntimeException(pae.getException());
1987 }
1988 }
1989 } catch (SecurityException e) {
1990 continue;
1991 } catch (NoSuchMethodException e) {
1992 continue;
1993 }
1994 }
1995 if (!Modifier.isPublic(declaringClass.getModifiers())) return false;
1996 method.setCallClass(declaringClass);
1997
1998 return true;
1999 }
2000
2001 private void generateReflector() {
2002 reflector = registry.loadReflector(theClass, allMethods);
2003 if (reflector == null) {
2004 throw new RuntimeException("Should have a reflector for "+theClass.getName());
2005 }
2006
2007 for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
2008 MetaMethod metaMethod = (MetaMethod) iter.next();
2009 metaMethod.setReflector(reflector);
2010 }
2011 }
2012
2013 public List getMethods() {
2014 return allMethods;
2015 }
2016
2017 public List getMetaMethods() {
2018 return new ArrayList(newGroovyMethodsList);
2019 }
2020
2021 private synchronized List getInterfaceMethods() {
2022 if (interfaceMethods == null) {
2023 interfaceMethods = new ArrayList();
2024 Class type = theClass;
2025 while (type != null) {
2026 Class[] interfaces = type.getInterfaces();
2027 for (int i = 0; i < interfaces.length; i++) {
2028 Class iface = interfaces[i];
2029 Method[] methods = iface.getMethods();
2030 addInterfaceMethods(interfaceMethods, methods);
2031 }
2032 type = type.getSuperclass();
2033 }
2034 }
2035 return interfaceMethods;
2036 }
2037
2038 private void addInterfaceMethods(List list, Method[] methods) {
2039 for (int i = 0; i < methods.length; i++) {
2040 list.add(createMetaMethod(methods[i]));
2041 }
2042 }
2043
2044 private static class MethodIndexAction {
2045 public void iterate(Map classMethodIndex){
2046 for (Iterator iter = classMethodIndex.entrySet().iterator(); iter.hasNext();) {
2047 Map.Entry classEntry = (Map.Entry) iter.next();
2048 Map methodIndex = (Map) classEntry.getValue();
2049 Class clazz = (Class) classEntry.getKey();
2050 if (skipClass(clazz)) continue;
2051 for (Iterator iterator = methodIndex.entrySet().iterator(); iterator.hasNext();) {
2052 Map.Entry nameEntry = (Map.Entry) iterator.next();
2053 String name = (String) nameEntry.getKey();
2054 List oldList = (List) nameEntry.getValue();
2055 List newList = methodNameAction(clazz, name, oldList);
2056 if (replaceMethodList()) nameEntry.setValue(newList);
2057 }
2058 }
2059 }
2060 public List methodNameAction(Class clazz, String methodName, List methods) {
2061 List newList = new ArrayList(methods.size());
2062 for (Iterator methodIter = methods.iterator(); methodIter.hasNext();) {
2063 MetaMethod method = (MetaMethod) methodIter.next();
2064 methodListAction(clazz,methodName,method,methods,newList);
2065 }
2066 return newList;
2067 }
2068 public boolean skipClass(Class clazz) {return false;}
2069 public void methodListAction(Class clazz, String methodName, MetaMethod method, List oldList, List newList) {}
2070 public boolean replaceMethodList(){return true;}
2071 }
2072
2073 /***
2074 * @deprecated
2075 */
2076 public Object getProperty(Object object, String property) {
2077 return getProperty(theClass,object,property,false,false);
2078 }
2079
2080 /***
2081 * @deprecated
2082 */
2083 public void setProperty(Object object, String property, Object newValue) {
2084 setProperty(theClass,object,property,newValue,false,false);
2085 }
2086
2087 /***
2088 * @deprecated
2089 */
2090 public Object getAttribute(Object object, String attribute) {
2091 return getAttribute(theClass,object,attribute,false,false);
2092 }
2093
2094 /***
2095 * @deprecated
2096 */
2097 public void setAttribute(Object object, String attribute, Object newValue) {
2098 setAttribute(theClass,object,attribute,newValue,false,false);
2099 }
2100
2101 public MetaMethod pickMethod(String methodName, Class[] arguments) {
2102 return getMethodWithoutCaching(theClass,methodName,arguments,false);
2103 }
2104
2105 /***
2106 * @deprecated use pickMethod instead
2107 */
2108 protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
2109 return pickMethod(methodName,arguments);
2110 }
2111
2112 /***
2113 * remove all method call cache entries. This should be done if a
2114 * method is added during runtime, but not by using a category.
2115 */
2116 protected void clearInvocationCaches() {
2117 staticMethodCache.clear();
2118 methodCache.clear();
2119 }
2120 }