Source Code Cross Referenced for MetaClassImpl.java in  » Scripting » groovy-1.0 » groovy » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » groovy 1.0 » groovy.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:        $Id: MetaClassImpl.java 4669 2007-01-02 19:35:47Z blackdrag $
0003:
0004:        Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
0005:
0006:        Redistribution and use of this software and associated documentation
0007:        ("Software"), with or without modification, are permitted provided
0008:        that the following conditions are met:
0009:
0010:        1. Redistributions of source code must retain copyright
0011:           statements and notices.  Redistributions must also contain a
0012:           copy of this document.
0013:
0014:        2. Redistributions in binary form must reproduce the
0015:           above copyright notice, this list of conditions and the
0016:           following disclaimer in the documentation and/or other
0017:           materials provided with the distribution.
0018:
0019:        3. The name "groovy" must not be used to endorse or promote
0020:           products derived from this Software without prior written
0021:           permission of The Codehaus.  For written permission,
0022:           please contact info@codehaus.org.
0023:
0024:        4. Products derived from this Software may not be called "groovy"
0025:           nor may "groovy" appear in their names without prior written
0026:           permission of The Codehaus. "groovy" is a registered
0027:           trademark of The Codehaus.
0028:
0029:        5. Due credit should be given to The Codehaus -
0030:           http://groovy.codehaus.org/
0031:
0032:        THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
0033:        ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
0034:        NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0035:        FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
0036:        THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
0037:        INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0038:        (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
0039:        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0040:        HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
0041:        STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0042:        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
0043:        OF THE POSSIBILITY OF SUCH DAMAGE.
0044:
0045:         */
0046:        package groovy.lang;
0047:
0048:        import java.beans.BeanInfo;
0049:        import java.beans.EventSetDescriptor;
0050:        import java.beans.IntrospectionException;
0051:        import java.beans.Introspector;
0052:        import java.beans.PropertyDescriptor;
0053:        import java.lang.reflect.Constructor;
0054:        import java.lang.reflect.Field;
0055:        import java.lang.reflect.Method;
0056:        import java.lang.reflect.Modifier;
0057:        import java.net.URL;
0058:        import java.security.AccessController;
0059:        import java.security.PrivilegedAction;
0060:        import java.security.PrivilegedActionException;
0061:        import java.security.PrivilegedExceptionAction;
0062:        import java.util.ArrayList;
0063:        import java.util.Arrays;
0064:        import java.util.Collection;
0065:        import java.util.Collections;
0066:        import java.util.Comparator;
0067:        import java.util.HashMap;
0068:        import java.util.HashSet;
0069:        import java.util.Iterator;
0070:        import java.util.LinkedList;
0071:        import java.util.List;
0072:        import java.util.Map;
0073:        import java.util.Set;
0074:        import java.util.logging.Level;
0075:
0076:        import org.codehaus.groovy.GroovyBugError;
0077:        import org.codehaus.groovy.ast.ClassNode;
0078:        import org.codehaus.groovy.classgen.BytecodeHelper;
0079:        import org.codehaus.groovy.control.CompilationUnit;
0080:        import org.codehaus.groovy.control.Phases;
0081:        import org.codehaus.groovy.runtime.CurriedClosure;
0082:        import org.codehaus.groovy.runtime.DefaultGroovyMethods;
0083:        import org.codehaus.groovy.runtime.DefaultMethodKey;
0084:        import org.codehaus.groovy.runtime.GroovyCategorySupport;
0085:        import org.codehaus.groovy.runtime.InvokerHelper;
0086:        import org.codehaus.groovy.runtime.MetaClassHelper;
0087:        import org.codehaus.groovy.runtime.MethodClosure;
0088:        import org.codehaus.groovy.runtime.MethodKey;
0089:        import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
0090:        import org.codehaus.groovy.runtime.NewStaticMetaMethod;
0091:        import org.codehaus.groovy.runtime.ReflectionMetaMethod;
0092:        import org.codehaus.groovy.runtime.Reflector;
0093:        import org.codehaus.groovy.runtime.TransformMetaMethod;
0094:        import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
0095:        import org.codehaus.groovy.runtime.wrappers.Wrapper;
0096:        import org.objectweb.asm.ClassVisitor;
0097:
0098:        /**
0099:         * Allows methods to be dynamically added to existing classes at runtime
0100:         *
0101:         * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
0102:         * @author Guillaume Laforge
0103:         * @author Jochen Theodorou
0104:         * @version $Revision: 4669 $
0105:         * @see groovy.lang.MetaClass
0106:         */
0107:        public class MetaClassImpl extends MetaClass {
0108:
0109:            protected MetaClassRegistry registry;
0110:            private ClassNode classNode;
0111:            private Map classMethodIndex = new HashMap();
0112:            private Map classMethodIndexForSuper;
0113:            private Map classStaticMethodIndex = new HashMap();
0114:            private Map classPropertyIndex = new HashMap();
0115:            private Map classPropertyIndexForSuper = new HashMap();
0116:            private Map staticPropertyIndex = new HashMap();
0117:            private Map listeners = new HashMap();
0118:            private Map methodCache = Collections
0119:                    .synchronizedMap(new HashMap());
0120:            private Map staticMethodCache = Collections
0121:                    .synchronizedMap(new HashMap());
0122:            private MetaMethod genericGetMethod;
0123:            private MetaMethod genericSetMethod;
0124:            private List constructors;
0125:            private List allMethods = new ArrayList();
0126:            private List interfaceMethods;
0127:            private Reflector reflector;
0128:            private boolean initialized;
0129:            // we only need one of these that can be reused over and over.
0130:            private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
0131:            private final static MetaMethod AMBIGOUS_LISTENER_METHOD = new MetaMethod(
0132:                    null, null, new Class[] {}, null, 0);
0133:            private static final Object[] EMPTY_ARGUMENTS = {};
0134:            private List newGroovyMethodsList = new LinkedList();
0135:
0136:            public MetaClassImpl(MetaClassRegistry registry,
0137:                    final Class theClass) {
0138:                super (theClass);
0139:                this .registry = registry;
0140:
0141:                constructors = (List) AccessController
0142:                        .doPrivileged(new PrivilegedAction() {
0143:                            public Object run() {
0144:                                return Arrays.asList(theClass
0145:                                        .getDeclaredConstructors());
0146:                            }
0147:                        });
0148:            }
0149:
0150:            private void fillMethodIndex() {
0151:                LinkedList super Classes = getSuperClasses();
0152:                // let's add all the base class methods
0153:                for (Iterator iter = super Classes.iterator(); iter.hasNext();) {
0154:                    Class c = (Class) iter.next();
0155:                    addMethods(c);
0156:                }
0157:
0158:                Set interfaces = new HashSet();
0159:                makeInterfaceSet(theClass, interfaces);
0160:
0161:                inheritMethods(super Classes, classMethodIndex);
0162:                inheritInterfaceMethods(interfaces);
0163:                copyClassMethodIndexForSuper();
0164:
0165:                connectMultimethods(super Classes);
0166:                populateInterfaces(interfaces);
0167:                removeMultimethodsOverloadedWithPrivateMethods();
0168:
0169:                replaceWithMOPCalls();
0170:            }
0171:
0172:            private LinkedList getSuperClasses() {
0173:                LinkedList super Classes = new LinkedList();
0174:                for (Class c = theClass; c != null; c = c.getSuperclass()) {
0175:                    super Classes.addFirst(c);
0176:                }
0177:                if (theClass.isArray() && theClass != Object[].class
0178:                        && !theClass.getComponentType().isPrimitive()) {
0179:                    super Classes.addFirst(Object[].class);
0180:                }
0181:                return super Classes;
0182:            }
0183:
0184:            private void removeMultimethodsOverloadedWithPrivateMethods() {
0185:                Map privates = new HashMap();
0186:                MethodIndexAction mia = new MethodIndexAction() {
0187:                    public List methodNameAction(Class clazz,
0188:                            String methodName, List methods) {
0189:                        boolean hasPrivate = false;
0190:                        for (Iterator iter = methods.iterator(); iter.hasNext();) {
0191:                            MetaMethod method = (MetaMethod) iter.next();
0192:                            if (method.isPrivate()
0193:                                    && clazz == method.getDeclaringClass()) {
0194:                                hasPrivate = true;
0195:                                break;
0196:                            }
0197:                        }
0198:                        if (!hasPrivate)
0199:                            return null;
0200:                        // We have private methods for that name, so remove the
0201:                        // multimethods. That is the same as in our index for 
0202:                        // super, so just copy the list from there. It is not
0203:                        // possible to use a pointer here, because the methods
0204:                        // in the index for super are replaced later by MOP 
0205:                        // methods like super$5$foo              
0206:                        methods.clear();
0207:                        methods
0208:                                .addAll((Collection) ((Map) classMethodIndexForSuper
0209:                                        .get(clazz)).get(methodName));
0210:                        return methods;
0211:                    }
0212:
0213:                    public boolean replaceMethodList() {
0214:                        return false;
0215:                    }
0216:                };
0217:                mia.iterate(classMethodIndex);
0218:            }
0219:
0220:            private void replaceWithMOPCalls() {
0221:                // no MOP methods if not a child of GroovyObject
0222:                if (!GroovyObject.class.isAssignableFrom(theClass))
0223:                    return;
0224:
0225:                final Map mainClassMethodIndex = (Map) classMethodIndex
0226:                        .get(theClass);
0227:                class MOPIter extends MethodIndexAction {
0228:                    boolean useThis;
0229:
0230:                    public boolean skipClass(Class clazz) {
0231:                        return !useThis && clazz == theClass;
0232:                    }
0233:
0234:                    public void methodListAction(Class clazz,
0235:                            String methodName, MetaMethod method, List oldList,
0236:                            List newList) {
0237:                        String mopName = getMOPMethodName(method
0238:                                .getDeclaringClass(), methodName, useThis);
0239:                        List matches = (List) mainClassMethodIndex.get(mopName);
0240:                        if (matches == null) {
0241:                            newList.add(method);
0242:                            return;
0243:                        }
0244:                        matches = new ArrayList(matches);
0245:                        MetaMethod matchingMethod = removeMatchingMethod(
0246:                                matches, method);
0247:                        if (matchingMethod == null) {
0248:                            newList.add(method);
0249:                            return;
0250:                        } else {
0251:                            newList.add(matchingMethod);
0252:                        }
0253:                    }
0254:                }
0255:                MOPIter iter = new MOPIter();
0256:
0257:                // replace all calls for super with the correct MOP method
0258:                iter.useThis = false;
0259:                iter.iterate(classMethodIndexForSuper);
0260:                // replace all calls for this with the correct MOP method
0261:                iter.useThis = true;
0262:                iter.iterate(classMethodIndex);
0263:            }
0264:
0265:            private String getMOPMethodName(Class declaringClass, String name,
0266:                    boolean useThis) {
0267:                int distance = 0;
0268:                for (; declaringClass != null; declaringClass = declaringClass
0269:                        .getSuperclass()) {
0270:                    distance++;
0271:                }
0272:                return (useThis ? "this" : "super") + "$" + distance + "$"
0273:                        + name;
0274:            }
0275:
0276:            private void copyClassMethodIndexForSuper() {
0277:                classMethodIndexForSuper = new HashMap(classMethodIndex.size());
0278:                for (Iterator iter = classMethodIndex.entrySet().iterator(); iter
0279:                        .hasNext();) {
0280:                    Map.Entry cmiEntry = (Map.Entry) iter.next();
0281:                    Map methodIndex = (Map) cmiEntry.getValue();
0282:                    Map copy = new HashMap(methodIndex.size());
0283:                    for (Iterator iterator = methodIndex.entrySet().iterator(); iterator
0284:                            .hasNext();) {
0285:                        Map.Entry mEntry = (Map.Entry) iterator.next();
0286:                        copy.put(mEntry.getKey(), new ArrayList((List) mEntry
0287:                                .getValue()));
0288:                    }
0289:                    classMethodIndexForSuper.put(cmiEntry.getKey(), copy);
0290:                }
0291:            }
0292:
0293:            private void inheritInterfaceMethods(Set interfaces) {
0294:                // add methods declared by DGM for interfaces
0295:                List methods = registry.getInstanceMethods();
0296:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0297:                    Method element = (Method) iter.next();
0298:                    Class dgmClass = element.getParameterTypes()[0];
0299:                    if (!interfaces.contains(dgmClass))
0300:                        continue;
0301:                    NewInstanceMetaMethod method = new NewInstanceMetaMethod(
0302:                            createMetaMethod(element));
0303:                    if (!newGroovyMethodsList.contains(method)) {
0304:                        newGroovyMethodsList.add(method);
0305:                    }
0306:                    Map methodIndex = (Map) classMethodIndex.get(theClass);
0307:                    List list = (List) methodIndex.get(method.getName());
0308:                    if (list == null) {
0309:                        list = new ArrayList();
0310:                        methodIndex.put(method.getName(), list);
0311:                        list.add(method);
0312:                    } else {
0313:                        addMethodToList(list, method);
0314:                    }
0315:                }
0316:                methods = registry.getStaticMethods();
0317:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0318:                    Method element = (Method) iter.next();
0319:                    Class dgmClass = element.getParameterTypes()[0];
0320:                    if (!interfaces.contains(dgmClass))
0321:                        continue;
0322:                    addNewStaticMethod(element);
0323:                }
0324:            }
0325:
0326:            private void populateInterfaces(Set interfaces) {
0327:                Map currentIndex = (Map) classMethodIndex.get(theClass);
0328:                Map index = new HashMap();
0329:                copyNonPrivateMethods(currentIndex, index);
0330:                for (Iterator iter = interfaces.iterator(); iter.hasNext();) {
0331:                    Class iClass = (Class) iter.next();
0332:                    Map methodIndex = (Map) classMethodIndex.get(iClass);
0333:                    if (methodIndex == null || methodIndex.size() == 0) {
0334:                        classMethodIndex.put(iClass, index);
0335:                        continue;
0336:                    }
0337:                    copyNonPrivateMethods(currentIndex, methodIndex);
0338:                }
0339:            }
0340:
0341:            private static void makeInterfaceSet(Class c, Set s) {
0342:                if (c == null)
0343:                    return;
0344:                Class[] interfaces = c.getInterfaces();
0345:                for (int i = 0; i < interfaces.length; i++) {
0346:                    if (!s.contains(interfaces[i])) {
0347:                        s.add(interfaces[i]);
0348:                        makeInterfaceSet(interfaces[i], s);
0349:                    }
0350:                }
0351:                makeInterfaceSet(c.getSuperclass(), s);
0352:            }
0353:
0354:            private void copyNonPrivateMethods(Map from, Map to) {
0355:                for (Iterator iterator = from.entrySet().iterator(); iterator
0356:                        .hasNext();) {
0357:                    Map.Entry element = (Map.Entry) iterator.next();
0358:                    List oldList = (List) element.getValue();
0359:                    List newList = (List) to.get(element.getKey());
0360:                    if (newList == null) {
0361:                        to.put(element.getKey(), new ArrayList(oldList));
0362:                    } else {
0363:                        addNonPrivateMethods(newList, oldList);
0364:                    }
0365:                }
0366:            }
0367:
0368:            private void connectMultimethods(List super Classes) {
0369:                super Classes = DefaultGroovyMethods.reverse(super Classes);
0370:                Map last = null;
0371:                for (Iterator iter = super Classes.iterator(); iter.hasNext();) {
0372:                    Class c = (Class) iter.next();
0373:                    Map methodIndex = (Map) classMethodIndex.get(c);
0374:                    if (methodIndex == last)
0375:                        continue;
0376:                    if (last != null)
0377:                        copyNonPrivateMethods(last, methodIndex);
0378:                    last = methodIndex;
0379:                }
0380:            }
0381:
0382:            private void inheritMethods(Collection super Classes,
0383:                    Map classMethodIndex) {
0384:                Map last = null;
0385:                for (Iterator iter = super Classes.iterator(); iter.hasNext();) {
0386:                    Class c = (Class) iter.next();
0387:                    Map methodIndex = (Map) classMethodIndex.get(c);
0388:                    if (last != null) {
0389:                        if (methodIndex.size() == 0) {
0390:                            classMethodIndex.put(c, last);
0391:                            continue;
0392:                        }
0393:                        copyNonPrivateMethods(last, methodIndex);
0394:                    }
0395:                    last = methodIndex;
0396:                }
0397:            }
0398:
0399:            private void addNonPrivateMethods(List newList, List oldList) {
0400:                for (Iterator iter = oldList.iterator(); iter.hasNext();) {
0401:                    MetaMethod element = (MetaMethod) iter.next();
0402:                    if (element.isPrivate())
0403:                        continue;
0404:                    addMethodToList(newList, element);
0405:                }
0406:            }
0407:
0408:            /**
0409:             * @return all the normal instance methods avaiable on this class for the
0410:             *         given name
0411:             */
0412:            private List getMethods(Class sender, String name,
0413:                    boolean isCallToSuper) {
0414:                Map methodIndex;
0415:                if (isCallToSuper) {
0416:                    methodIndex = (Map) classMethodIndexForSuper.get(sender);
0417:                } else {
0418:                    methodIndex = (Map) classMethodIndex.get(sender);
0419:                }
0420:                List answer;
0421:                if (methodIndex != null) {
0422:                    answer = (List) methodIndex.get(name);
0423:                    if (answer == null)
0424:                        answer = Collections.EMPTY_LIST;
0425:                } else {
0426:                    answer = Collections.EMPTY_LIST;
0427:                }
0428:
0429:                if (!isCallToSuper
0430:                        && GroovyCategorySupport.hasCategoryInAnyThread()) {
0431:                    List used = GroovyCategorySupport.getCategoryMethods(
0432:                            sender, name);
0433:                    if (used != null) {
0434:                        answer = new ArrayList(answer);
0435:                        for (Iterator iter = used.iterator(); iter.hasNext();) {
0436:                            MetaMethod element = (MetaMethod) iter.next();
0437:                            removeMatchingMethod(answer, element);
0438:                        }
0439:                        answer.addAll(used);
0440:                    }
0441:                }
0442:                return answer;
0443:            }
0444:
0445:            /**
0446:             * @return all the normal static methods avaiable on this class for the
0447:             *         given name
0448:             */
0449:            private List getStaticMethods(Class sender, String name) {
0450:                Map methodIndex = (Map) classStaticMethodIndex.get(sender);
0451:                if (methodIndex == null)
0452:                    return Collections.EMPTY_LIST;
0453:                List answer = (List) methodIndex.get(name);
0454:                if (answer == null)
0455:                    return Collections.EMPTY_LIST;
0456:                return answer;
0457:            }
0458:
0459:            public void addNewInstanceMethod(Method method) {
0460:                NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(
0461:                        createMetaMethod(method));
0462:                if (!newGroovyMethodsList.contains(newMethod)) {
0463:                    newGroovyMethodsList.add(newMethod);
0464:                    addMetaMethod(newMethod);
0465:                }
0466:            }
0467:
0468:            public void addNewStaticMethod(Method method) {
0469:                NewStaticMetaMethod newMethod = new NewStaticMetaMethod(
0470:                        createMetaMethod(method));
0471:                if (!newGroovyMethodsList.contains(newMethod)) {
0472:                    newGroovyMethodsList.add(newMethod);
0473:                    addMetaMethod(newMethod);
0474:                }
0475:            }
0476:
0477:            private void unwrap(Object[] arguments) {
0478:                //
0479:                // Temp code to ignore wrapped parameters
0480:                // The New MOP will deal with these properly
0481:                //
0482:                for (int i = 0; i != arguments.length; i++) {
0483:                    if (arguments[i] instanceof  Wrapper) {
0484:                        arguments[i] = ((Wrapper) arguments[i]).unwrap();
0485:                    }
0486:                }
0487:            }
0488:
0489:            /**
0490:             * Invokes the given method on the object.
0491:             * @deprecated
0492:             */
0493:            public Object invokeMethod(Object object, String methodName,
0494:                    Object[] originalArguments) {
0495:                return invokeMethod(theClass, object, methodName,
0496:                        originalArguments, false, false);
0497:            }
0498:
0499:            /**
0500:             * Invokes the given method on the object.
0501:             *
0502:             */
0503:            public Object invokeMethod(Class sender, Object object,
0504:                    String methodName, Object[] originalArguments,
0505:                    boolean isCallToSuper, boolean fromInsideClass) {
0506:                checkInitalised();
0507:                if (object == null) {
0508:                    throw new NullPointerException("Cannot invoke method: "
0509:                            + methodName + " on null object");
0510:                }
0511:                if (log.isLoggable(Level.FINER)) {
0512:                    MetaClassHelper.logMethodCall(object, methodName,
0513:                            originalArguments);
0514:                }
0515:                Object[] arguments = originalArguments;
0516:                if (arguments == null)
0517:                    arguments = EMPTY_ARGUMENTS;
0518:                Class[] argClasses = MetaClassHelper
0519:                        .convertToTypeArray(arguments);
0520:                unwrap(arguments);
0521:
0522:                MetaMethod method = getMethodWithCaching(sender, methodName,
0523:                        argClasses, isCallToSuper);
0524:
0525:                if (method == null && arguments.length == 1
0526:                        && arguments[0] instanceof  List) {
0527:                    Object[] newArguments = ((List) arguments[0]).toArray();
0528:                    Class[] newArgClasses = MetaClassHelper
0529:                            .convertToTypeArray(newArguments);
0530:                    method = getMethodWithCaching(sender, methodName,
0531:                            newArgClasses, isCallToSuper);
0532:                    if (method != null) {
0533:                        MethodKey methodKey = new DefaultMethodKey(sender,
0534:                                methodName, argClasses, isCallToSuper);
0535:                        method = new TransformMetaMethod(method) {
0536:                            public Object invoke(Object object,
0537:                                    Object[] arguments) {
0538:                                Object firstArgument = arguments[0];
0539:                                List list = (List) firstArgument;
0540:                                arguments = list.toArray();
0541:                                return super .invoke(object, arguments);
0542:                            }
0543:                        };
0544:                        cacheInstanceMethod(methodKey, method);
0545:                        return invokeMethod(sender, object, methodName,
0546:                                originalArguments, isCallToSuper,
0547:                                fromInsideClass);
0548:                    }
0549:                }
0550:
0551:                boolean isClosure = object instanceof  Closure;
0552:                if (isClosure) {
0553:                    Closure closure = (Closure) object;
0554:                    Object delegate = closure.getDelegate();
0555:                    Object owner = closure.getOwner();
0556:
0557:                    if ("call".equals(methodName)
0558:                            || "doCall".equals(methodName)) {
0559:                        if (object.getClass() == MethodClosure.class) {
0560:                            MethodClosure mc = (MethodClosure) object;
0561:                            methodName = mc.getMethod();
0562:                            Class ownerClass = owner.getClass();
0563:                            if (owner instanceof  Class)
0564:                                ownerClass = (Class) owner;
0565:                            MetaClass ownerMetaClass = registry
0566:                                    .getMetaClass(ownerClass);
0567:                            return ownerMetaClass.invokeMethod(ownerClass,
0568:                                    owner, methodName, arguments, false, false);
0569:                        } else if (object.getClass() == CurriedClosure.class) {
0570:                            CurriedClosure cc = (CurriedClosure) object;
0571:                            // change the arguments for an uncurried call
0572:                            arguments = cc.getUncurriedArguments(arguments);
0573:                            Class ownerClass = owner.getClass();
0574:                            if (owner instanceof  Class)
0575:                                ownerClass = (Class) owner;
0576:                            MetaClass ownerMetaClass = registry
0577:                                    .getMetaClass(ownerClass);
0578:                            return ownerMetaClass.invokeMethod(owner,
0579:                                    methodName, arguments);
0580:                        }
0581:                    } else if ("curry".equals(methodName)) {
0582:                        return closure.curry(arguments);
0583:                    }
0584:
0585:                    if (method == null && owner != closure) {
0586:                        Class ownerClass = owner.getClass();
0587:                        if (owner instanceof  Class)
0588:                            ownerClass = (Class) owner;
0589:                        MetaClass ownerMetaClass = registry
0590:                                .getMetaClass(ownerClass);
0591:                        method = ownerMetaClass.pickMethod(methodName,
0592:                                argClasses);
0593:                        if (method != null)
0594:                            return ownerMetaClass.invokeMethod(owner,
0595:                                    methodName, originalArguments);
0596:                    }
0597:                    if (method == null && delegate != closure
0598:                            && delegate != null) {
0599:                        Class delegateClass = delegate.getClass();
0600:                        if (delegate instanceof  Class)
0601:                            delegateClass = (Class) delegate;
0602:                        MetaClass delegateMetaClass = registry
0603:                                .getMetaClass(delegateClass);
0604:                        method = delegateMetaClass.pickMethod(methodName,
0605:                                argClasses);
0606:                        if (method != null)
0607:                            return delegateMetaClass.invokeMethod(delegate,
0608:                                    methodName, originalArguments);
0609:                    }
0610:                    if (method == null) {
0611:                        // still no methods found, test if delegate or owner are GroovyObjects
0612:                        // and invoke the method on them if so.
0613:                        MissingMethodException last = null;
0614:                        if (owner != closure && (owner instanceof  GroovyObject)) {
0615:                            try {
0616:                                GroovyObject go = (GroovyObject) owner;
0617:                                return go.invokeMethod(methodName,
0618:                                        originalArguments);
0619:                            } catch (MissingMethodException mme) {
0620:                                if (last == null)
0621:                                    last = mme;
0622:                            }
0623:                        }
0624:                        if (delegate != closure
0625:                                && (delegate instanceof  GroovyObject)) {
0626:                            try {
0627:                                GroovyObject go = (GroovyObject) delegate;
0628:                                return go.invokeMethod(methodName,
0629:                                        originalArguments);
0630:                            } catch (MissingMethodException mme) {
0631:                                last = mme;
0632:                            }
0633:                        }
0634:                        if (last != null)
0635:                            throw last;
0636:                    }
0637:
0638:                }
0639:
0640:                if (method != null) {
0641:                    return MetaClassHelper.doMethodInvoke(object, method,
0642:                            arguments);
0643:                } else {
0644:                    // if no method was found, try to find a closure defined as a field of the class and run it
0645:                    try {
0646:                        Object value = this .getProperty(object, methodName);
0647:                        if (value instanceof  Closure) { // This test ensures that value != this If you ever change this ensure that value != this
0648:                            Closure closure = (Closure) value;
0649:                            MetaClass delegateMetaClass = closure
0650:                                    .getMetaClass();
0651:                            return delegateMetaClass.invokeMethod(closure
0652:                                    .getClass(), closure, "doCall",
0653:                                    originalArguments, false, fromInsideClass);
0654:                        }
0655:                    } catch (MissingPropertyException mpe) {
0656:                    }
0657:
0658:                    throw new MissingMethodException(methodName, theClass,
0659:                            originalArguments, false);
0660:                }
0661:            }
0662:
0663:            public MetaMethod getMethodWithCaching(Class sender,
0664:                    String methodName, Class[] arguments, boolean isCallToSuper) {
0665:                // lets try use the cache to find the method
0666:                if (GroovyCategorySupport.hasCategoryInAnyThread()
0667:                        && !isCallToSuper) {
0668:                    return getMethodWithoutCaching(sender, methodName,
0669:                            arguments, isCallToSuper);
0670:                } else {
0671:                    MethodKey methodKey = new DefaultMethodKey(sender,
0672:                            methodName, arguments, isCallToSuper);
0673:                    MetaMethod method = (MetaMethod) methodCache.get(methodKey);
0674:                    if (method == null) {
0675:                        method = getMethodWithoutCaching(sender, methodName,
0676:                                arguments, isCallToSuper);
0677:                        cacheInstanceMethod(methodKey, method);
0678:                    }
0679:                    return method;
0680:                }
0681:            }
0682:
0683:            protected void cacheInstanceMethod(MethodKey key, MetaMethod method) {
0684:                if (method != null && method.isCacheable()) {
0685:                    methodCache.put(key, method);
0686:                }
0687:            }
0688:
0689:            protected void cacheStaticMethod(MethodKey key, MetaMethod method) {
0690:                if (method != null && method.isCacheable()) {
0691:                    staticMethodCache.put(key, method);
0692:                }
0693:            }
0694:
0695:            public Constructor retrieveConstructor(Class[] arguments) {
0696:                Constructor constructor = (Constructor) chooseMethod("<init>",
0697:                        constructors, arguments, false);
0698:                if (constructor != null) {
0699:                    return constructor;
0700:                }
0701:                constructor = (Constructor) chooseMethod("<init>",
0702:                        constructors, arguments, true);
0703:                if (constructor != null) {
0704:                    return constructor;
0705:                }
0706:                return null;
0707:            }
0708:
0709:            public MetaMethod retrieveStaticMethod(String methodName,
0710:                    Class[] arguments) {
0711:                MethodKey methodKey = new DefaultMethodKey(theClass,
0712:                        methodName, arguments, false);
0713:                MetaMethod method = (MetaMethod) staticMethodCache
0714:                        .get(methodKey);
0715:                if (method == null) {
0716:                    method = pickStaticMethod(theClass, methodName, arguments);
0717:                    cacheStaticMethod(methodKey, method);
0718:                }
0719:                return method;
0720:            }
0721:
0722:            public MetaMethod getMethodWithoutCaching(Class sender,
0723:                    String methodName, Class[] arguments, boolean isCallToSuper) {
0724:                MetaMethod method = null;
0725:                List methods = getMethods(sender, methodName, isCallToSuper);
0726:                if (methods != null && !methods.isEmpty()) {
0727:                    method = (MetaMethod) chooseMethod(methodName, methods,
0728:                            arguments, false);
0729:                }
0730:                return method;
0731:            }
0732:
0733:            public Object invokeStaticMethod(Object object, String methodName,
0734:                    Object[] arguments) {
0735:                checkInitalised();
0736:                if (log.isLoggable(Level.FINER)) {
0737:                    MetaClassHelper
0738:                            .logMethodCall(object, methodName, arguments);
0739:                }
0740:
0741:                Class sender = object.getClass();
0742:                if (object instanceof  Class)
0743:                    sender = (Class) object;
0744:                if (sender != theClass) {
0745:                    MetaClass mc = registry.getMetaClass(sender);
0746:                    return mc.invokeStaticMethod(sender, methodName, arguments);
0747:                }
0748:                if (sender == Class.class) {
0749:                    return invokeMethod(object, methodName, arguments);
0750:                }
0751:
0752:                if (arguments == null)
0753:                    arguments = EMPTY_ARGUMENTS;
0754:                Class[] argClasses = MetaClassHelper
0755:                        .convertToTypeArray(arguments);
0756:                unwrap(arguments);
0757:
0758:                // lets try use the cache to find the method
0759:                MethodKey methodKey = new DefaultMethodKey(sender, methodName,
0760:                        argClasses, false);
0761:                MetaMethod method = (MetaMethod) staticMethodCache
0762:                        .get(methodKey);
0763:                if (method == null) {
0764:                    method = pickStaticMethod(sender, methodName, argClasses);
0765:                    cacheStaticMethod(methodKey.createCopy(), method);
0766:                }
0767:
0768:                if (method != null) {
0769:                    return MetaClassHelper.doMethodInvoke(object, method,
0770:                            arguments);
0771:                }
0772:
0773:                throw new MissingMethodException(methodName, sender, arguments,
0774:                        true);
0775:            }
0776:
0777:            private MetaMethod pickStaticMethod(Class sender,
0778:                    String methodName, Class[] arguments) {
0779:                MetaMethod method = null;
0780:                List methods = getStaticMethods(sender, methodName);
0781:
0782:                if (!methods.isEmpty()) {
0783:                    method = (MetaMethod) chooseMethod(methodName, methods,
0784:                            arguments, false);
0785:                }
0786:                if (method == null && theClass != Class.class) {
0787:                    MetaClass classMetaClass = registry
0788:                            .getMetaClass(Class.class);
0789:                    method = classMetaClass.pickMethod(methodName, arguments);
0790:                }
0791:                if (method == null) {
0792:                    method = (MetaMethod) chooseMethod(methodName, methods,
0793:                            MetaClassHelper.convertToTypeArray(arguments), true);
0794:                }
0795:                return method;
0796:            }
0797:
0798:            public Object invokeConstructor(Object[] arguments) {
0799:                return invokeConstructor(theClass, arguments, false);
0800:            }
0801:
0802:            public int selectConstructorAndTransformArguments(
0803:                    int numberOfCosntructors, Object[] arguments) {
0804:                //TODO: that is just a quick prototype, not the real thing!
0805:                if (numberOfCosntructors != constructors.size()) {
0806:                    throw new IncompatibleClassChangeError(
0807:                            "the number of constructors during runtime and compile time for "
0808:                                    + this .theClass.getName()
0809:                                    + " do not match. Expected "
0810:                                    + numberOfCosntructors + " but got "
0811:                                    + constructors.size());
0812:                }
0813:
0814:                if (arguments == null)
0815:                    arguments = EMPTY_ARGUMENTS;
0816:                Class[] argClasses = MetaClassHelper
0817:                        .convertToTypeArray(arguments);
0818:                unwrap(arguments);
0819:                Constructor constructor = (Constructor) chooseMethod("<init>",
0820:                        constructors, argClasses, false);
0821:                if (constructor == null) {
0822:                    constructor = (Constructor) chooseMethod("<init>",
0823:                            constructors, argClasses, true);
0824:                }
0825:                if (constructor == null) {
0826:                    throw new GroovyRuntimeException(
0827:                            "Could not find matching constructor for: "
0828:                                    + theClass.getName() + "("
0829:                                    + InvokerHelper.toTypeString(arguments)
0830:                                    + ")");
0831:                }
0832:                List l = new ArrayList(constructors);
0833:                Comparator comp = new Comparator() {
0834:                    public int compare(Object arg0, Object arg1) {
0835:                        Constructor c0 = (Constructor) arg0;
0836:                        Constructor c1 = (Constructor) arg1;
0837:                        String descriptor0 = BytecodeHelper
0838:                                .getMethodDescriptor(Void.TYPE, c0
0839:                                        .getParameterTypes());
0840:                        String descriptor1 = BytecodeHelper
0841:                                .getMethodDescriptor(Void.TYPE, c1
0842:                                        .getParameterTypes());
0843:                        return descriptor0.compareTo(descriptor1);
0844:                    }
0845:                };
0846:                Collections.sort(l, comp);
0847:                int found = -1;
0848:                for (int i = 0; i < l.size(); i++) {
0849:                    if (l.get(i) != constructor)
0850:                        continue;
0851:                    found = i;
0852:                    break;
0853:                }
0854:                // NOTE: must be changed to "1 |" if constructor was vargs
0855:                int ret = 0 | (found << 8);
0856:                return ret;
0857:            }
0858:
0859:            /**
0860:             * checks if the initialisation of the class id complete.
0861:             * This method should be called as a form of assert, it is no
0862:             * way to test if there is still initialisation work to be done. 
0863:             * Such logic must be implemented in a different way.
0864:             * @throws IllegalStateException if the initialisation is incomplete yet
0865:             */
0866:            protected void checkInitalised() {
0867:                if (!isInitialized())
0868:                    throw new IllegalStateException(
0869:                            "initialize must be called for meta "
0870:                                    + "class of "
0871:                                    + theClass
0872:                                    + "("
0873:                                    + this .getClass()
0874:                                    + ") "
0875:                                    + "to complete initialisation process "
0876:                                    + "before any invocation or field/property "
0877:                                    + "access can be done");
0878:            }
0879:
0880:            private Object invokeConstructor(Class at, Object[] arguments,
0881:                    boolean setAccessible) {
0882:                checkInitalised();
0883:                if (arguments == null)
0884:                    arguments = EMPTY_ARGUMENTS;
0885:                Class[] argClasses = MetaClassHelper
0886:                        .convertToTypeArray(arguments);
0887:                unwrap(arguments);
0888:                Constructor constructor = (Constructor) chooseMethod("<init>",
0889:                        constructors, argClasses, false);
0890:                if (constructor != null) {
0891:                    return doConstructorInvoke(at, constructor, arguments, true);
0892:                }
0893:                constructor = (Constructor) chooseMethod("<init>",
0894:                        constructors, argClasses, true);
0895:                if (constructor != null) {
0896:                    return doConstructorInvoke(at, constructor, arguments, true);
0897:                }
0898:
0899:                if (arguments.length == 1) {
0900:                    Object firstArgument = arguments[0];
0901:                    if (firstArgument instanceof  Map) {
0902:                        constructor = (Constructor) chooseMethod("<init>",
0903:                                constructors, MetaClassHelper.EMPTY_TYPE_ARRAY,
0904:                                false);
0905:                        if (constructor != null) {
0906:                            Object bean = doConstructorInvoke(at, constructor,
0907:                                    MetaClassHelper.EMPTY_ARRAY, true);
0908:                            setProperties(bean, ((Map) firstArgument));
0909:                            return bean;
0910:                        }
0911:                    }
0912:                }
0913:                throw new GroovyRuntimeException(
0914:                        "Could not find matching constructor for: "
0915:                                + theClass.getName() + "("
0916:                                + InvokerHelper.toTypeString(arguments) + ")");
0917:            }
0918:
0919:            /**
0920:             * Sets a number of bean properties from the given Map where the keys are
0921:             * the String names of properties and the values are the values of the
0922:             * properties to set
0923:             */
0924:            public void setProperties(Object bean, Map map) {
0925:                checkInitalised();
0926:                for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
0927:                    Map.Entry entry = (Map.Entry) iter.next();
0928:                    String key = entry.getKey().toString();
0929:
0930:                    Object value = entry.getValue();
0931:                    setProperty(bean, key, value);
0932:                }
0933:            }
0934:
0935:            /**
0936:             * @return the given property's value on the object
0937:             */
0938:            public Object getProperty(Class sender, Object object, String name,
0939:                    boolean useSuper, boolean fromInsideClass) {
0940:                checkInitalised();
0941:
0942:                //----------------------------------------------------------------------
0943:                // handling of static
0944:                //----------------------------------------------------------------------
0945:                boolean isStatic = theClass != Class.class
0946:                        && object instanceof  Class;
0947:                if (isStatic && object != theClass) {
0948:                    MetaClass mc = registry.getMetaClass((Class) object);
0949:                    return mc
0950:                            .getProperty(sender, object, name, useSuper, false);
0951:                }
0952:
0953:                MetaMethod method = null;
0954:                Object[] arguments = EMPTY_ARGUMENTS;
0955:
0956:                //----------------------------------------------------------------------
0957:                // getter
0958:                //----------------------------------------------------------------------
0959:                MetaProperty mp = getMetaProperty(sender, name, useSuper,
0960:                        isStatic);
0961:                if (mp != null) {
0962:                    if (mp instanceof  MetaBeanProperty) {
0963:                        MetaBeanProperty mbp = (MetaBeanProperty) mp;
0964:                        method = mbp.getGetter();
0965:                        mp = mbp.getField();
0966:                    }
0967:                }
0968:
0969:                // check for a category method named like a getter 
0970:                if (method == null && !useSuper && !isStatic
0971:                        && GroovyCategorySupport.hasCategoryInAnyThread()) {
0972:                    String getterName = "get"
0973:                            + MetaClassHelper.capitalize(name);
0974:                    method = getCategoryMethodGetter(sender, getterName, false);
0975:                }
0976:
0977:                //----------------------------------------------------------------------
0978:                // field
0979:                //----------------------------------------------------------------------
0980:                if (method == null && mp != null) {
0981:                    return mp.getProperty(object);
0982:                }
0983:
0984:                //----------------------------------------------------------------------
0985:                // generic get method
0986:                //----------------------------------------------------------------------       
0987:                // check for a generic get method provided through a category
0988:                if (method == null && !useSuper && !isStatic
0989:                        && GroovyCategorySupport.hasCategoryInAnyThread()) {
0990:                    method = getCategoryMethodGetter(sender, "get", true);
0991:                    if (method != null)
0992:                        arguments = new Object[] { name };
0993:                }
0994:
0995:                // the generic method is valid, if available (!=null), if static or
0996:                // if it is not static and we do no static access
0997:                if (method == null && genericGetMethod != null
0998:                        && !(!genericGetMethod.isStatic() && isStatic)) {
0999:                    arguments = new Object[] { name };
1000:                    method = genericGetMethod;
1001:                }
1002:
1003:                //----------------------------------------------------------------------
1004:                // special cases
1005:                //----------------------------------------------------------------------
1006:                if (method == null) {
1007:                    /** todo these special cases should be special MetaClasses maybe */
1008:                    if (theClass != Class.class && object instanceof  Class) {
1009:                        MetaClass mc = registry.getMetaClass(Class.class);
1010:                        return mc.getProperty(Class.class, object, name,
1011:                                useSuper, false);
1012:                    } else if (object instanceof  Collection) {
1013:                        return DefaultGroovyMethods.getAt((Collection) object,
1014:                                name);
1015:                    } else if (object instanceof  Object[]) {
1016:                        return DefaultGroovyMethods.getAt(Arrays
1017:                                .asList((Object[]) object), name);
1018:                    } else {
1019:                        MetaMethod addListenerMethod = (MetaMethod) listeners
1020:                                .get(name);
1021:                        if (addListenerMethod != null) {
1022:                            //TODO: one day we could try return the previously registered Closure listener for easy removal
1023:                            return null;
1024:                        }
1025:                    }
1026:                } else {
1027:
1028:                    //----------------------------------------------------------------------
1029:                    // executing the getter method 
1030:                    //----------------------------------------------------------------------
1031:                    return MetaClassHelper.doMethodInvoke(object, method,
1032:                            arguments);
1033:                }
1034:
1035:                //----------------------------------------------------------------------
1036:                // error due to missing method/field
1037:                //----------------------------------------------------------------------
1038:                throw new MissingPropertyException(name, theClass);
1039:            }
1040:
1041:            private MetaMethod getCategoryMethodGetter(Class sender,
1042:                    String name, boolean useLongVersion) {
1043:                List possibleGenericMethods = GroovyCategorySupport
1044:                        .getCategoryMethods(sender, name);
1045:                if (possibleGenericMethods != null) {
1046:                    for (Iterator iter = possibleGenericMethods.iterator(); iter
1047:                            .hasNext();) {
1048:                        MetaMethod mmethod = (MetaMethod) iter.next();
1049:                        Class[] paramTypes = mmethod.getParameterTypes();
1050:                        if (useLongVersion) {
1051:                            if (paramTypes.length == 1
1052:                                    && paramTypes[0] == String.class) {
1053:                                return mmethod;
1054:                            }
1055:                        } else {
1056:                            if (paramTypes.length == 0)
1057:                                return mmethod;
1058:                        }
1059:                    }
1060:                }
1061:                return null;
1062:            }
1063:
1064:            private MetaMethod getCategoryMethodSetter(Class sender,
1065:                    String name, boolean useLongVersion) {
1066:                List possibleGenericMethods = GroovyCategorySupport
1067:                        .getCategoryMethods(sender, name);
1068:                if (possibleGenericMethods != null) {
1069:                    for (Iterator iter = possibleGenericMethods.iterator(); iter
1070:                            .hasNext();) {
1071:                        MetaMethod mmethod = (MetaMethod) iter.next();
1072:                        Class[] paramTypes = mmethod.getParameterTypes();
1073:                        if (useLongVersion) {
1074:                            if (paramTypes.length == 2
1075:                                    && paramTypes[0] == String.class) {
1076:                                return mmethod;
1077:                            }
1078:                        } else {
1079:                            if (paramTypes.length == 1)
1080:                                return mmethod;
1081:                        }
1082:                    }
1083:                }
1084:                return null;
1085:            }
1086:
1087:            /**
1088:             * Get all the properties defined for this type
1089:             * @return a list of MetaProperty objects
1090:             */
1091:            public List getProperties() {
1092:                checkInitalised();
1093:                Map propertyMap = (Map) classPropertyIndex.get(theClass);
1094:                // simply return the values of the metaproperty map as a List
1095:                List ret = new ArrayList(propertyMap.size());
1096:                for (Iterator iter = propertyMap.values().iterator(); iter
1097:                        .hasNext();) {
1098:                    MetaProperty element = (MetaProperty) iter.next();
1099:                    if (element instanceof  MetaFieldProperty)
1100:                        continue;
1101:                    // filter out DGM beans
1102:                    if (element instanceof  MetaBeanProperty) {
1103:                        MetaBeanProperty mp = (MetaBeanProperty) element;
1104:                        boolean setter = true;
1105:                        boolean getter = true;
1106:                        if (mp.getGetter() == null
1107:                                || mp.getGetter() instanceof  NewInstanceMetaMethod) {
1108:                            getter = false;
1109:                        }
1110:                        if (mp.getSetter() == null
1111:                                || mp.getSetter() instanceof  NewInstanceMetaMethod) {
1112:                            setter = false;
1113:                        }
1114:                        if (!setter && !getter)
1115:                            continue;
1116:                        if (!setter && mp.getSetter() != null) {
1117:                            element = new MetaBeanProperty(mp.getName(), mp
1118:                                    .getType(), mp.getGetter(), null);
1119:                        }
1120:                        if (!getter && mp.getGetter() != null) {
1121:                            element = new MetaBeanProperty(mp.getName(), mp
1122:                                    .getType(), null, mp.getSetter());
1123:                        }
1124:                    }
1125:                    ret.add(element);
1126:                }
1127:                return ret;
1128:            }
1129:
1130:            private MetaMethod findPropertyMethod(List methods, boolean isGetter) {
1131:                LinkedList ret = new LinkedList();
1132:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1133:                    MetaMethod element = (MetaMethod) iter.next();
1134:                    if (!isGetter &&
1135:                    //(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) && 
1136:                            element.getParameterTypes().length == 1) {
1137:                        ret.add(element);
1138:                    }
1139:                    if (isGetter
1140:                            && !(element.getReturnType() == Void.class || element
1141:                                    .getReturnType() == Void.TYPE)
1142:                            && element.getParameterTypes().length == 0) {
1143:                        ret.add(element);
1144:                    }
1145:                }
1146:                if (ret.size() == 0)
1147:                    return null;
1148:                if (ret.size() == 1)
1149:                    return (MetaMethod) ret.getFirst();
1150:
1151:                // we found multiple matching methods
1152:                // this is a problem, because we can use only one
1153:                // if it is a getter, then use the most general return 
1154:                // type to decide which method to use. If it is a setter 
1155:                // we use the type of the first parameter 
1156:                MetaMethod method = null;
1157:                int distance = -1;
1158:                for (Iterator iter = ret.iterator(); iter.hasNext();) {
1159:                    MetaMethod element = (MetaMethod) iter.next();
1160:                    Class c;
1161:                    if (isGetter) {
1162:                        c = element.getReturnType();
1163:                    } else {
1164:                        c = element.getParameterTypes()[0];
1165:                    }
1166:                    int localDistance = distanceToObject(c);
1167:                    //TODO: maybe implement the case localDistance==distance
1168:                    if (distance == -1 || distance > localDistance) {
1169:                        distance = localDistance;
1170:                        method = element;
1171:                    }
1172:                }
1173:                return method;
1174:            }
1175:
1176:            private static int distanceToObject(Class c) {
1177:                int count;
1178:                for (count = 0; c != null; count++) {
1179:                    c = c.getSuperclass();
1180:                }
1181:                return count;
1182:            }
1183:
1184:            /**
1185:             * This will build up the property map (Map of MetaProperty objects, keyed on
1186:             * property name).
1187:             */
1188:            private void setupProperties(
1189:                    PropertyDescriptor[] propertyDescriptors) {
1190:                LinkedList super Classes = getSuperClasses();
1191:                Set interfaces = new HashSet();
1192:                makeInterfaceSet(theClass, interfaces);
1193:
1194:                // if this an Array, then add the special read-only "length" property
1195:                if (theClass.isArray()) {
1196:                    Map map = new HashMap();
1197:                    map.put("length", arrayLengthProperty);
1198:                    classPropertyIndex.put(theClass, map);
1199:                }
1200:
1201:                inheritStaticInterfaceFields(super Classes, interfaces);
1202:                inheritFields(super Classes);
1203:                applyPropertyDescriptors(propertyDescriptors);
1204:
1205:                applyStrayPropertyMethods(super Classes, classMethodIndex,
1206:                        classPropertyIndex);
1207:                applyStrayPropertyMethods(super Classes,
1208:                        classMethodIndexForSuper, classPropertyIndexForSuper);
1209:
1210:                copyClassPropertyIndexForSuper();
1211:                makeStaticPropertyIndex();
1212:            }
1213:
1214:            private void makeStaticPropertyIndex() {
1215:                Map propertyMap = (Map) classPropertyIndex.get(theClass);
1216:                for (Iterator iter = propertyMap.entrySet().iterator(); iter
1217:                        .hasNext();) {
1218:                    Map.Entry entry = (Map.Entry) iter.next();
1219:                    MetaProperty mp = (MetaProperty) entry.getValue();
1220:                    if (mp instanceof  MetaFieldProperty) {
1221:                        MetaFieldProperty mfp = (MetaFieldProperty) mp;
1222:                        if (!mfp.isStatic())
1223:                            continue;
1224:                    } else if (mp instanceof  MetaBeanProperty) {
1225:                        MetaBeanProperty mbp = (MetaBeanProperty) mp;
1226:                        boolean getter = mbp.getGetter() == null
1227:                                || mbp.getGetter().isStatic();
1228:                        boolean setter = mbp.getSetter() == null
1229:                                || mbp.getSetter().isStatic();
1230:                        boolean field = mbp.getField() == null
1231:                                || mbp.getField().isStatic();
1232:
1233:                        if (!getter && !setter && !field) {
1234:                            continue;
1235:                        } else if (setter && getter) {
1236:                            if (field) {
1237:                                mp = mbp; // nothing to do
1238:                            } else {
1239:                                mp = new MetaBeanProperty(mbp.getName(), mbp
1240:                                        .getType(), mbp.getGetter(), mbp
1241:                                        .getSetter());
1242:                            }
1243:                        } else if (getter && !setter) {
1244:                            if (mbp.getGetter() == null) {
1245:                                mp = mbp.getField();
1246:                            } else {
1247:                                MetaBeanProperty newmp = new MetaBeanProperty(
1248:                                        mbp.getName(), mbp.getType(), mbp
1249:                                                .getGetter(), null);
1250:                                if (field)
1251:                                    newmp.setField(mbp.getField());
1252:                                mp = newmp;
1253:                            }
1254:                        } else if (setter && !getter) {
1255:                            if (mbp.getSetter() == null) {
1256:                                mp = mbp.getField();
1257:                            } else {
1258:                                MetaBeanProperty newmp = new MetaBeanProperty(
1259:                                        mbp.getName(), mbp.getType(), null, mbp
1260:                                                .getSetter());
1261:                                if (field)
1262:                                    newmp.setField(mbp.getField());
1263:                                mp = newmp;
1264:                            }
1265:                        } else if (field) {
1266:                            mp = mbp.getField();
1267:                        }
1268:                    } else {
1269:                        continue; // ignore all other types
1270:                    }
1271:                    if (mp == null)
1272:                        continue;
1273:                    staticPropertyIndex.put(entry.getKey(), mp);
1274:                }
1275:
1276:            }
1277:
1278:            private void copyClassPropertyIndexForSuper() {
1279:                for (Iterator iter = classPropertyIndex.entrySet().iterator(); iter
1280:                        .hasNext();) {
1281:                    Map.Entry entry = (Map.Entry) iter.next();
1282:                    HashMap newVal = new HashMap((Map) entry.getValue());
1283:                    classPropertyIndexForSuper.put(entry.getKey(), newVal);
1284:                }
1285:            }
1286:
1287:            private Map getMap2MapNotNull(Map m, Object key) {
1288:                Map ret = (Map) m.get(key);
1289:                if (ret == null) {
1290:                    ret = new HashMap();
1291:                    m.put(key, ret);
1292:                }
1293:                return ret;
1294:            }
1295:
1296:            private void inheritStaticInterfaceFields(LinkedList super Classes,
1297:                    Set interfaces) {
1298:                for (Iterator interfaceIter = interfaces.iterator(); interfaceIter
1299:                        .hasNext();) {
1300:                    Class iclass = (Class) interfaceIter.next();
1301:                    Map iPropertyIndex = getMap2MapNotNull(classPropertyIndex,
1302:                            iclass);
1303:                    addFields(iclass, iPropertyIndex);
1304:                    for (Iterator classIter = super Classes.iterator(); classIter
1305:                            .hasNext();) {
1306:                        Class sclass = (Class) classIter.next();
1307:                        if (!iclass.isAssignableFrom(sclass))
1308:                            continue;
1309:                        Map sPropertyIndex = getMap2MapNotNull(
1310:                                classPropertyIndex, sclass);
1311:                        copyNonPrivateFields(iPropertyIndex, sPropertyIndex);
1312:                    }
1313:                }
1314:            }
1315:
1316:            private void inheritFields(LinkedList super Classes) {
1317:                Map last = null;
1318:                for (Iterator iter = super Classes.iterator(); iter.hasNext();) {
1319:                    Class klass = (Class) iter.next();
1320:                    Map propertyIndex = getMap2MapNotNull(classPropertyIndex,
1321:                            klass);
1322:                    if (last != null) {
1323:                        copyNonPrivateFields(last, propertyIndex);
1324:                    }
1325:                    last = propertyIndex;
1326:                    addFields(klass, propertyIndex);
1327:                }
1328:            }
1329:
1330:            private void addFields(final Class klass, Map propertyIndex) {
1331:                Field[] fields = (Field[]) AccessController
1332:                        .doPrivileged(new PrivilegedAction() {
1333:                            public Object run() {
1334:                                return klass.getDeclaredFields();
1335:                            }
1336:                        });
1337:                for (int i = 0; i < fields.length; i++) {
1338:                    MetaFieldProperty mfp = new MetaFieldProperty(fields[i]);
1339:                    propertyIndex.put(fields[i].getName(), mfp);
1340:                }
1341:            }
1342:
1343:            private void copyNonPrivateFields(Map from, Map to) {
1344:                for (Iterator iter = from.entrySet().iterator(); iter.hasNext();) {
1345:                    Map.Entry entry = (Map.Entry) iter.next();
1346:                    MetaFieldProperty mfp = (MetaFieldProperty) entry
1347:                            .getValue();
1348:                    if (!Modifier.isPublic(mfp.getModifiers())
1349:                            && !Modifier.isProtected(mfp.getModifiers()))
1350:                        continue;
1351:                    to.put(entry.getKey(), mfp);
1352:                }
1353:            }
1354:
1355:            private void applyStrayPropertyMethods(LinkedList super Classes,
1356:                    Map classMethodIndex, Map classPropertyIndex) {
1357:                // now look for any stray getters that may be used to define a property
1358:                for (Iterator iter = super Classes.iterator(); iter.hasNext();) {
1359:                    Class klass = (Class) iter.next();
1360:                    Map methodIndex = (Map) classMethodIndex.get(klass);
1361:                    Map propertyIndex = getMap2MapNotNull(classPropertyIndex,
1362:                            klass);
1363:                    for (Iterator nameMethodIterator = methodIndex.entrySet()
1364:                            .iterator(); nameMethodIterator.hasNext();) {
1365:                        Map.Entry entry = (Map.Entry) nameMethodIterator.next();
1366:                        String methodName = (String) entry.getKey();
1367:                        // name too sort?
1368:                        if (methodName.length() < 4)
1369:                            continue;
1370:                        //possible getter/setter
1371:                        boolean isGetter = methodName.startsWith("get");
1372:                        boolean isSetter = methodName.startsWith("set");
1373:                        if (!isGetter && !isSetter)
1374:                            continue;
1375:
1376:                        // get the name of the property
1377:                        String propName = methodName.substring(3, 4)
1378:                                .toLowerCase()
1379:                                + methodName.substring(4);
1380:                        MetaMethod propertyMethod = findPropertyMethod(
1381:                                (List) entry.getValue(), isGetter);
1382:                        if (propertyMethod == null)
1383:                            continue;
1384:
1385:                        createMetaBeanProperty(propertyIndex, propName,
1386:                                isGetter, propertyMethod);
1387:                    }
1388:                }
1389:            }
1390:
1391:            private void createMetaBeanProperty(Map propertyIndex,
1392:                    String propName, boolean isGetter, MetaMethod propertyMethod) {
1393:                // is this property already accounted for?
1394:                MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
1395:                if (mp == null) {
1396:                    if (isGetter) {
1397:                        mp = new MetaBeanProperty(propName, propertyMethod
1398:                                .getReturnType(), propertyMethod, null);
1399:                    } else {
1400:                        //isSetter
1401:                        mp = new MetaBeanProperty(propName, propertyMethod
1402:                                .getParameterTypes()[0], null, propertyMethod);
1403:                    }
1404:                } else {
1405:                    MetaBeanProperty mbp;
1406:                    MetaFieldProperty mfp;
1407:                    if (mp instanceof  MetaBeanProperty) {
1408:                        mbp = (MetaBeanProperty) mp;
1409:                        mfp = mbp.getField();
1410:                    } else if (mp instanceof  MetaFieldProperty) {
1411:                        mfp = (MetaFieldProperty) mp;
1412:                        mbp = new MetaBeanProperty(propName, mfp.getType(),
1413:                                null, null);
1414:                    } else {
1415:                        throw new GroovyBugError(
1416:                                "unknown MetaProperty class used. Class is "
1417:                                        + mp.getClass());
1418:                    }
1419:                    // we may have already found one for this name
1420:                    if (isGetter && mbp.getGetter() == null) {
1421:                        mbp.setGetter(propertyMethod);
1422:                    } else if (!isGetter && mbp.getSetter() == null) {
1423:                        mbp.setSetter(propertyMethod);
1424:                    }
1425:                    mbp.setField(mfp);
1426:                    mp = mbp;
1427:                }
1428:                propertyIndex.put(propName, mp);
1429:            }
1430:
1431:            private void applyPropertyDescriptors(
1432:                    PropertyDescriptor[] propertyDescriptors) {
1433:                Map propertyMap = (Map) classPropertyIndex.get(theClass);
1434:                // now iterate over the map of property descriptors and generate
1435:                // MetaBeanProperty objects
1436:                for (int i = 0; i < propertyDescriptors.length; i++) {
1437:                    PropertyDescriptor pd = propertyDescriptors[i];
1438:
1439:                    // skip if the property type is unknown (this seems to be the case if the
1440:                    // property descriptor is based on a setX() method that has two parameters,
1441:                    // which is not a valid property)
1442:                    if (pd.getPropertyType() == null)
1443:                        continue;
1444:
1445:                    // get the getter method
1446:                    Method method = pd.getReadMethod();
1447:                    MetaMethod getter;
1448:                    if (method != null)
1449:                        getter = findMethod(method);
1450:                    else
1451:                        getter = null;
1452:
1453:                    // get the setter method
1454:                    MetaMethod setter;
1455:                    method = pd.getWriteMethod();
1456:                    if (method != null)
1457:                        setter = findMethod(method);
1458:                    else
1459:                        setter = null;
1460:
1461:                    // now create the MetaProperty object
1462:                    MetaBeanProperty mp = new MetaBeanProperty(pd.getName(), pd
1463:                            .getPropertyType(), getter, setter);
1464:
1465:                    //keep field
1466:                    MetaFieldProperty field = null;
1467:                    MetaProperty old = (MetaProperty) propertyMap.get(pd
1468:                            .getName());
1469:                    if (old != null) {
1470:                        if (old instanceof  MetaBeanProperty) {
1471:                            field = ((MetaBeanProperty) old).getField();
1472:                        } else {
1473:                            field = (MetaFieldProperty) old;
1474:                        }
1475:                        mp.setField(field);
1476:                    }
1477:
1478:                    // put it in the list
1479:                    // this will overwrite a possible field property
1480:                    propertyMap.put(pd.getName(), mp);
1481:                }
1482:            }
1483:
1484:            /**
1485:             * Sets the property value on an object
1486:             */
1487:            public void setProperty(Class sender, Object object, String name,
1488:                    Object newValue, boolean useSuper, boolean fromInsideClass) {
1489:                checkInitalised();
1490:
1491:                //----------------------------------------------------------------------
1492:                // handling of static
1493:                //----------------------------------------------------------------------
1494:                boolean isStatic = theClass != Class.class
1495:                        && object instanceof  Class;
1496:                if (isStatic && object != theClass) {
1497:                    MetaClass mc = registry.getMetaClass((Class) object);
1498:                    mc.getProperty(sender, object, name, useSuper,
1499:                            fromInsideClass);
1500:                    return;
1501:                }
1502:
1503:                //----------------------------------------------------------------------
1504:                // Unwrap wrapped values fo now - the new MOP will handle them properly
1505:                //----------------------------------------------------------------------
1506:                if (newValue instanceof  Wrapper)
1507:                    newValue = ((Wrapper) newValue).unwrap();
1508:
1509:                MetaMethod method = null;
1510:                Object[] arguments = null;
1511:
1512:                //----------------------------------------------------------------------
1513:                // setter
1514:                //----------------------------------------------------------------------
1515:                MetaProperty mp = getMetaProperty(sender, name, useSuper,
1516:                        isStatic);
1517:                MetaProperty field = null;
1518:                if (mp != null) {
1519:                    if (mp instanceof  MetaBeanProperty) {
1520:                        MetaBeanProperty mbp = (MetaBeanProperty) mp;
1521:                        method = mbp.getSetter();
1522:                        if (method != null)
1523:                            arguments = new Object[] { newValue };
1524:                        field = mbp.getField();
1525:                    } else {
1526:                        field = mp;
1527:                    }
1528:                }
1529:
1530:                // check for a category method named like a setter 
1531:                if (!useSuper && !isStatic
1532:                        && GroovyCategorySupport.hasCategoryInAnyThread()) {
1533:                    String getterName = "set"
1534:                            + MetaClassHelper.capitalize(name);
1535:                    method = getCategoryMethodSetter(sender, getterName, false);
1536:                    if (method != null)
1537:                        arguments = new Object[] { newValue };
1538:                }
1539:
1540:                //----------------------------------------------------------------------
1541:                // listener method
1542:                //----------------------------------------------------------------------
1543:                boolean ambigousListener = false;
1544:                boolean usesProxy = false;
1545:                if (method == null) {
1546:                    method = (MetaMethod) listeners.get(name);
1547:                    ambigousListener = method == AMBIGOUS_LISTENER_METHOD;
1548:                    if (method != null && !ambigousListener
1549:                            && newValue instanceof  Closure) {
1550:                        // lets create a dynamic proxy
1551:                        Object proxy = MetaClassHelper.createListenerProxy(
1552:                                method.getParameterTypes()[0], name,
1553:                                (Closure) newValue);
1554:                        arguments = new Object[] { proxy };
1555:                        newValue = proxy;
1556:                        usesProxy = true;
1557:                    } else {
1558:                        method = null;
1559:                    }
1560:                }
1561:
1562:                //----------------------------------------------------------------------
1563:                // field
1564:                //----------------------------------------------------------------------
1565:                if (method == null && field != null) {
1566:                    field.setProperty(object, newValue);
1567:                    return;
1568:                }
1569:
1570:                //----------------------------------------------------------------------
1571:                // generic set method
1572:                //----------------------------------------------------------------------       
1573:                // check for a generic get method provided through a category
1574:                if (method == null && !useSuper && !isStatic
1575:                        && GroovyCategorySupport.hasCategoryInAnyThread()) {
1576:                    method = getCategoryMethodSetter(sender, "set", true);
1577:                    if (method != null)
1578:                        arguments = new Object[] { name, newValue };
1579:                }
1580:
1581:                // the generic method is valid, if available (!=null), if static or
1582:                // if it is not static and we do no static access
1583:                if (method == null && genericSetMethod != null
1584:                        && !(!genericSetMethod.isStatic() && isStatic)) {
1585:                    arguments = new Object[] { name, newValue };
1586:                    method = genericSetMethod;
1587:                }
1588:
1589:                //----------------------------------------------------------------------
1590:                // executing the getter method 
1591:                //----------------------------------------------------------------------
1592:                if (method != null) {
1593:                    if (arguments.length == 1) {
1594:                        newValue = DefaultTypeTransformation.castToType(
1595:                                newValue, method.getParameterTypes()[0]);
1596:                        arguments[0] = newValue;
1597:                    } else {
1598:                        newValue = DefaultTypeTransformation.castToType(
1599:                                newValue, method.getParameterTypes()[1]);
1600:                        arguments[1] = newValue;
1601:                    }
1602:                    MetaClassHelper.doMethodInvoke(object, method, arguments);
1603:                    return;
1604:                }
1605:
1606:                //----------------------------------------------------------------------
1607:                // error due to missing method/field
1608:                //----------------------------------------------------------------------
1609:                if (ambigousListener) {
1610:                    throw new GroovyRuntimeException(
1611:                            "There are multiple listeners for the property "
1612:                                    + name
1613:                                    + ". Please do not use the bean short form to access this listener.");
1614:                }
1615:                throw new MissingPropertyException(name, theClass);
1616:            }
1617:
1618:            private MetaProperty getMetaProperty(Class clazz, String name,
1619:                    boolean useSuper, boolean useStatic) {
1620:                Map propertyMap;
1621:                if (useStatic) {
1622:                    propertyMap = staticPropertyIndex;
1623:                } else if (useSuper) {
1624:                    propertyMap = (Map) classPropertyIndexForSuper.get(clazz);
1625:                } else {
1626:                    propertyMap = (Map) classPropertyIndex.get(clazz);
1627:                }
1628:                if (propertyMap == null) {
1629:                    if (clazz != theClass) {
1630:                        return getMetaProperty(theClass, name, useSuper,
1631:                                useStatic);
1632:                    } else {
1633:                        return null;
1634:                    }
1635:                }
1636:                return (MetaProperty) propertyMap.get(name);
1637:            }
1638:
1639:            /**
1640:             * Looks up the given attribute (field) on the given object
1641:             */
1642:            public Object getAttribute(Class sender, Object object,
1643:                    String attribute, boolean useSuper, boolean fromInsideClass) {
1644:                checkInitalised();
1645:
1646:                boolean isStatic = theClass != Class.class
1647:                        && object instanceof  Class;
1648:                if (isStatic && object != theClass) {
1649:                    MetaClass mc = registry.getMetaClass((Class) object);
1650:                    return mc.getAttribute(sender, object, attribute, useSuper);
1651:                }
1652:
1653:                MetaProperty mp = getMetaProperty(sender, attribute, useSuper,
1654:                        isStatic);
1655:
1656:                if (mp != null) {
1657:                    if (mp instanceof  MetaBeanProperty) {
1658:                        MetaBeanProperty mbp = (MetaBeanProperty) mp;
1659:                        mp = mbp.getField();
1660:                    }
1661:                    try {
1662:                        // delegate the get operation to the metaproperty
1663:                        if (mp != null)
1664:                            return mp.getProperty(object);
1665:                    } catch (Exception e) {
1666:                        throw new GroovyRuntimeException("Cannot read field: "
1667:                                + attribute, e);
1668:                    }
1669:                }
1670:
1671:                throw new MissingFieldException(attribute, theClass);
1672:            }
1673:
1674:            /**
1675:             * Sets the given attribute (field) on the given object
1676:             */
1677:            public void setAttribute(Class sender, Object object,
1678:                    String attribute, Object newValue, boolean useSuper,
1679:                    boolean fromInsideClass) {
1680:                checkInitalised();
1681:
1682:                boolean isStatic = theClass != Class.class
1683:                        && object instanceof  Class;
1684:                if (isStatic && object != theClass) {
1685:                    MetaClass mc = registry.getMetaClass((Class) object);
1686:                    mc.setAttribute(sender, object, attribute, newValue,
1687:                            useSuper, fromInsideClass);
1688:                    return;
1689:                }
1690:
1691:                MetaProperty mp = getMetaProperty(sender, attribute, useSuper,
1692:                        isStatic);
1693:
1694:                if (mp != null) {
1695:                    if (mp instanceof  MetaBeanProperty) {
1696:                        MetaBeanProperty mbp = (MetaBeanProperty) mp;
1697:                        mp = mbp.getField();
1698:                    }
1699:                    if (mp != null) {
1700:                        mp.setProperty(object, newValue);
1701:                        return;
1702:                    }
1703:                }
1704:
1705:                throw new MissingFieldException(attribute, theClass);
1706:            }
1707:
1708:            public ClassNode getClassNode() {
1709:                if (classNode == null
1710:                        && GroovyObject.class.isAssignableFrom(theClass)) {
1711:                    // lets try load it from the classpath
1712:                    String className = theClass.getName();
1713:                    String groovyFile = className;
1714:                    int idx = groovyFile.indexOf('$');
1715:                    if (idx > 0) {
1716:                        groovyFile = groovyFile.substring(0, idx);
1717:                    }
1718:                    groovyFile = groovyFile.replace('.', '/') + ".groovy";
1719:
1720:                    //System.out.println("Attempting to load: " + groovyFile);
1721:                    URL url = theClass.getClassLoader().getResource(groovyFile);
1722:                    if (url == null) {
1723:                        url = Thread.currentThread().getContextClassLoader()
1724:                                .getResource(groovyFile);
1725:                    }
1726:                    if (url != null) {
1727:                        try {
1728:
1729:                            /**
1730:                             * todo there is no CompileUnit in scope so class name
1731:                             * checking won't work but that mostly affects the bytecode
1732:                             * generation rather than viewing the AST
1733:                             */
1734:                            CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
1735:                                public void call(ClassVisitor writer,
1736:                                        ClassNode node) {
1737:                                    if (node.getName().equals(
1738:                                            theClass.getName())) {
1739:                                        MetaClassImpl.this .classNode = node;
1740:                                    }
1741:                                }
1742:                            };
1743:
1744:                            final ClassLoader parent = theClass
1745:                                    .getClassLoader();
1746:                            GroovyClassLoader gcl = (GroovyClassLoader) AccessController
1747:                                    .doPrivileged(new PrivilegedAction() {
1748:                                        public Object run() {
1749:                                            return new GroovyClassLoader(parent);
1750:                                        }
1751:                                    });
1752:                            CompilationUnit unit = new CompilationUnit();
1753:                            unit.setClassgenCallback(search);
1754:                            unit.addSource(url);
1755:                            unit.compile(Phases.CLASS_GENERATION);
1756:                        } catch (Exception e) {
1757:                            throw new GroovyRuntimeException(
1758:                                    "Exception thrown parsing: " + groovyFile
1759:                                            + ". Reason: " + e, e);
1760:                        }
1761:                    }
1762:
1763:                }
1764:                return classNode;
1765:            }
1766:
1767:            public String toString() {
1768:                return super .toString() + "[" + theClass + "]";
1769:            }
1770:
1771:            // Implementation methods
1772:            //-------------------------------------------------------------------------
1773:
1774:            /**
1775:             * Adds all the methods declared in the given class to the metaclass
1776:             * ignoring any matching methods already defined by a derived class
1777:             *
1778:             * @param theClass
1779:             */
1780:            private void addMethods(final Class theClass) {
1781:                Map methodIndex = (Map) classMethodIndex.get(theClass);
1782:                if (methodIndex == null) {
1783:                    methodIndex = new HashMap();
1784:                    classMethodIndex.put(theClass, methodIndex);
1785:                }
1786:                // add methods directly declared in the class
1787:                Method[] methodArray = (Method[]) AccessController
1788:                        .doPrivileged(new PrivilegedAction() {
1789:                            public Object run() {
1790:                                return theClass.getDeclaredMethods();
1791:                            }
1792:                        });
1793:                for (int i = 0; i < methodArray.length; i++) {
1794:                    Method reflectionMethod = methodArray[i];
1795:                    if (reflectionMethod.getName().indexOf('+') >= 0) {
1796:                        // Skip Synthetic methods inserted by JDK 1.5 compilers and later
1797:                        continue;
1798:                    } else if (Modifier.isAbstract(reflectionMethod
1799:                            .getModifiers())) {
1800:                        continue;
1801:                    }
1802:                    MetaMethod method = createMetaMethod(reflectionMethod);
1803:                    addMetaMethod(method);
1804:                }
1805:                // add methods declared by DGM
1806:                List methods = registry.getInstanceMethods();
1807:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1808:                    Method element = (Method) iter.next();
1809:                    if (element.getParameterTypes()[0] != theClass)
1810:                        continue;
1811:                    addNewInstanceMethod(element);
1812:                }
1813:                // add static methods declared by DGM
1814:                methods = registry.getStaticMethods();
1815:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1816:                    Method element = (Method) iter.next();
1817:                    if (element.getParameterTypes()[0] != theClass)
1818:                        continue;
1819:                    addNewStaticMethod(element);
1820:                }
1821:            }
1822:
1823:            private void addToClassMethodIndex(MetaMethod method,
1824:                    Map classMethodIndex) {
1825:                Map methodIndex = (Map) classMethodIndex.get(method
1826:                        .getDeclaringClass());
1827:                if (methodIndex == null) {
1828:                    methodIndex = new HashMap();
1829:                    classMethodIndex.put(method.getDeclaringClass(),
1830:                            methodIndex);
1831:                }
1832:                String name = method.getName();
1833:                List list = (List) methodIndex.get(name);
1834:                if (list == null) {
1835:                    list = new ArrayList();
1836:                    methodIndex.put(name, list);
1837:                    list.add(method);
1838:                } else {
1839:                    addMethodToList(list, method);
1840:                }
1841:            }
1842:
1843:            /**
1844:             * adds a MetaMethod to this class. WARNING: this method will not
1845:             * do the neccessary steps for multimethod logic and using this
1846:             * method doesn't mean, that a method added here is replacing another
1847:             * method from a parent class completely. These steps are usually done
1848:             * by initalize, which means if you need these steps, you have to add
1849:             * the method before running initialize the first time.
1850:             * @see #initialize() 
1851:             * @param method the MetaMethod
1852:             */
1853:            protected void addMetaMethod(MetaMethod method) {
1854:                if (isInitialized()) {
1855:                    throw new RuntimeException(
1856:                            "Already initialized, cannot add new method: "
1857:                                    + method);
1858:                }
1859:                if (isGenericGetMethod(method) && genericGetMethod == null) {
1860:                    genericGetMethod = method;
1861:                } else if (MetaClassHelper.isGenericSetMethod(method)
1862:                        && genericSetMethod == null) {
1863:                    genericSetMethod = method;
1864:                }
1865:                if (method.isStatic()) {
1866:                    addToClassMethodIndex(method, classStaticMethodIndex);
1867:                }
1868:                addToClassMethodIndex(method, classMethodIndex);
1869:            }
1870:
1871:            protected boolean isInitialized() {
1872:                return initialized;
1873:            }
1874:
1875:            private void addMethodToList(List list, MetaMethod method) {
1876:                MetaMethod match = removeMatchingMethod(list, method);
1877:                if (match == null) {
1878:                    list.add(method);
1879:                } else if (match.isPrivate()) {
1880:                    // do not overwrite private methods
1881:                    // Note: private methods from parent classes are not shown here,
1882:                    // but when doing the multimethod connection step, we overwrite
1883:                    // methods of the parent class with methods of a subclass and
1884:                    // in that case we want to keep the private methods
1885:                    list.add(match);
1886:                } else {
1887:                    Class methodC = method.getDeclaringClass();
1888:                    Class matchC = match.getDeclaringClass();
1889:                    if (methodC == matchC) {
1890:                        if (method instanceof  NewInstanceMetaMethod) {
1891:                            // let DGM replace existing methods
1892:                            list.add(method);
1893:                        } else {
1894:                            list.add(match);
1895:                        }
1896:                    } else if (MetaClassHelper
1897:                            .isAssignableFrom(methodC, matchC)) {
1898:                        list.add(match);
1899:                    } else {
1900:                        list.add(method);
1901:                    }
1902:                }
1903:            }
1904:
1905:            /**
1906:             * remove a method of the same matching prototype was found in the list
1907:             */
1908:            private MetaMethod removeMatchingMethod(List list, MetaMethod method) {
1909:                for (Iterator iter = list.iterator(); iter.hasNext();) {
1910:                    MetaMethod aMethod = (MetaMethod) iter.next();
1911:                    Class[] params1 = aMethod.getParameterTypes();
1912:                    Class[] params2 = method.getParameterTypes();
1913:                    if (params1.length == params2.length) {
1914:                        boolean matches = true;
1915:                        for (int i = 0; i < params1.length; i++) {
1916:                            if (params1[i] != params2[i]) {
1917:                                matches = false;
1918:                                break;
1919:                            }
1920:                        }
1921:                        if (matches) {
1922:                            iter.remove();
1923:                            return (MetaMethod) aMethod;
1924:                        }
1925:                    }
1926:                }
1927:                return null;
1928:            }
1929:
1930:            /**
1931:             * @return the matching method which should be found
1932:             */
1933:            private MetaMethod findMethod(Method aMethod) {
1934:                List methods = getMethods(theClass, aMethod.getName(), false);
1935:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1936:                    MetaMethod method = (MetaMethod) iter.next();
1937:                    if (method.isMethod(aMethod)) {
1938:                        return method;
1939:                    }
1940:                }
1941:                //log.warning("Creating reflection based dispatcher for: " + aMethod);
1942:                return new ReflectionMetaMethod(aMethod);
1943:            }
1944:
1945:            /**
1946:             * @return the getter method for the given object
1947:             */
1948:            private MetaMethod findGetter(Object object, String name) {
1949:                List methods = getMethods(theClass, name, false);
1950:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1951:                    MetaMethod method = (MetaMethod) iter.next();
1952:                    if (method.getParameterTypes().length == 0) {
1953:                        return method;
1954:                    }
1955:                }
1956:                return null;
1957:            }
1958:
1959:            /**
1960:             * @return the Method of the given name with no parameters or null
1961:             */
1962:            private MetaMethod findStaticGetter(Class type, String name) {
1963:                List methods = getStaticMethods(type, name);
1964:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
1965:                    MetaMethod method = (MetaMethod) iter.next();
1966:                    if (method.getParameterTypes().length == 0) {
1967:                        return method;
1968:                    }
1969:                }
1970:
1971:                /** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
1972:                try {
1973:                    Method method = type.getMethod(name,
1974:                            MetaClassHelper.EMPTY_TYPE_ARRAY);
1975:                    if ((method.getModifiers() & Modifier.STATIC) != 0) {
1976:                        return findMethod(method);
1977:                    } else {
1978:                        return null;
1979:                    }
1980:                } catch (Exception e) {
1981:                    return null;
1982:                }
1983:            }
1984:
1985:            private static Object doConstructorInvoke(final Class at,
1986:                    Constructor constructor, Object[] argumentArray,
1987:                    boolean setAccessible) {
1988:                if (log.isLoggable(Level.FINER)) {
1989:                    MetaClassHelper.logMethodCall(constructor
1990:                            .getDeclaringClass(), constructor.getName(),
1991:                            argumentArray);
1992:                }
1993:
1994:                if (setAccessible) {
1995:                    // To fix JIRA 435
1996:                    // Every constructor should be opened to the accessible classes.
1997:                    final boolean accessible = MetaClassHelper
1998:                            .accessibleToConstructor(at, constructor);
1999:                    final Constructor ctor = constructor;
2000:                    AccessController.doPrivileged(new PrivilegedAction() {
2001:                        public Object run() {
2002:                            ctor.setAccessible(accessible);
2003:                            return null;
2004:                        }
2005:                    });
2006:                }
2007:                return MetaClassHelper.doConstructorInvoke(constructor,
2008:                        argumentArray);
2009:            }
2010:
2011:            /**
2012:             * Chooses the correct method to use from a list of methods which match by
2013:             * name.
2014:             *
2015:             * @param methods
2016:             *            the possible methods to choose from
2017:             * @param arguments
2018:             *            the original argument to the method
2019:             */
2020:            private Object chooseMethod(String methodName, List methods,
2021:                    Class[] arguments, boolean coerce) {
2022:                int methodCount = methods.size();
2023:                if (methodCount <= 0) {
2024:                    return null;
2025:                } else if (methodCount == 1) {
2026:                    Object method = methods.get(0);
2027:                    if (MetaClassHelper
2028:                            .isValidMethod(method, arguments, coerce)) {
2029:                        return method;
2030:                    }
2031:                    return null;
2032:                }
2033:                Object answer = null;
2034:                if (arguments == null || arguments.length == 0) {
2035:                    answer = MetaClassHelper.chooseEmptyMethodParams(methods);
2036:                } else if (arguments.length == 1 && arguments[0] == null) {
2037:                    answer = MetaClassHelper
2038:                            .chooseMostGeneralMethodWith1NullParam(methods);
2039:                } else {
2040:                    List matchingMethods = new ArrayList();
2041:
2042:                    for (Iterator iter = methods.iterator(); iter.hasNext();) {
2043:                        Object method = iter.next();
2044:
2045:                        // making this false helps find matches
2046:                        if (MetaClassHelper.isValidMethod(method, arguments,
2047:                                coerce)) {
2048:                            matchingMethods.add(method);
2049:                        }
2050:                    }
2051:                    if (matchingMethods.isEmpty()) {
2052:                        return null;
2053:                    } else if (matchingMethods.size() == 1) {
2054:                        return matchingMethods.get(0);
2055:                    }
2056:                    return chooseMostSpecificParams(methodName,
2057:                            matchingMethods, arguments);
2058:
2059:                }
2060:                if (answer != null) {
2061:                    return answer;
2062:                }
2063:                throw new GroovyRuntimeException(
2064:                        "Could not find which method to invoke from this list: "
2065:                                + methods + " for arguments: "
2066:                                + InvokerHelper.toString(arguments));
2067:            }
2068:
2069:            private Object chooseMostSpecificParams(String name,
2070:                    List matchingMethods, Class[] arguments) {
2071:
2072:                long matchesDistance = -1;
2073:                LinkedList matches = new LinkedList();
2074:                for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
2075:                    Object method = iter.next();
2076:                    Class[] paramTypes = MetaClassHelper
2077:                            .getParameterTypes(method);
2078:                    if (!MetaClassHelper.parametersAreCompatible(arguments,
2079:                            paramTypes))
2080:                        continue;
2081:                    long dist = MetaClassHelper.calculateParameterDistance(
2082:                            arguments, paramTypes);
2083:                    if (dist == 0)
2084:                        return method;
2085:                    if (matches.size() == 0) {
2086:                        matches.add(method);
2087:                        matchesDistance = dist;
2088:                    } else if (dist < matchesDistance) {
2089:                        matchesDistance = dist;
2090:                        matches.clear();
2091:                        matches.add(method);
2092:                    } else if (dist == matchesDistance) {
2093:                        matches.add(method);
2094:                    }
2095:
2096:                }
2097:                if (matches.size() == 1) {
2098:                    return matches.getFirst();
2099:                }
2100:                if (matches.size() == 0) {
2101:                    return null;
2102:                }
2103:
2104:                //more than one matching method found --> ambigous!
2105:                String msg = "Ambiguous method overloading for method ";
2106:                msg += theClass.getName() + "#" + name;
2107:                msg += ".\nCannot resolve which method to invoke for ";
2108:                msg += InvokerHelper.toString(arguments);
2109:                msg += " due to overlapping prototypes between:";
2110:                for (Iterator iter = matches.iterator(); iter.hasNext();) {
2111:                    Class[] types = MetaClassHelper.getParameterTypes(iter
2112:                            .next());
2113:                    msg += "\n\t" + InvokerHelper.toString(types);
2114:                }
2115:                throw new GroovyRuntimeException(msg);
2116:            }
2117:
2118:            private boolean isGenericGetMethod(MetaMethod method) {
2119:                if (method.getName().equals("get")) {
2120:                    Class[] parameterTypes = method.getParameterTypes();
2121:                    return parameterTypes.length == 1
2122:                            && parameterTypes[0] == String.class;
2123:                }
2124:                return false;
2125:            }
2126:
2127:            /**
2128:             * Call this method when any mutation method is called, such as adding a new
2129:             * method to this MetaClass so that any caching or bytecode generation can be
2130:             * regenerated.
2131:             */
2132:            private synchronized void onMethodChange() {
2133:                reflector = null;
2134:            }
2135:
2136:            public synchronized void initialize() {
2137:                if (!isInitialized()) {
2138:                    fillMethodIndex();
2139:                    addProperties();
2140:                    initialized = true;
2141:                }
2142:                if (reflector == null) {
2143:                    generateReflector();
2144:                }
2145:            }
2146:
2147:            private void addProperties() {
2148:                BeanInfo info;
2149:                //     introspect
2150:                try {
2151:                    info = (BeanInfo) AccessController
2152:                            .doPrivileged(new PrivilegedExceptionAction() {
2153:                                public Object run()
2154:                                        throws IntrospectionException {
2155:                                    return Introspector.getBeanInfo(theClass);
2156:                                }
2157:                            });
2158:                } catch (PrivilegedActionException pae) {
2159:                    throw new GroovyRuntimeException(
2160:                            "exception while bean introspection", pae
2161:                                    .getException());
2162:                }
2163:                PropertyDescriptor[] descriptors = info
2164:                        .getPropertyDescriptors();
2165:
2166:                // build up the metaproperties based on the public fields, property descriptors,
2167:                // and the getters and setters
2168:                setupProperties(descriptors);
2169:
2170:                EventSetDescriptor[] eventDescriptors = info
2171:                        .getEventSetDescriptors();
2172:                for (int i = 0; i < eventDescriptors.length; i++) {
2173:                    EventSetDescriptor descriptor = eventDescriptors[i];
2174:                    Method[] listenerMethods = descriptor.getListenerMethods();
2175:                    for (int j = 0; j < listenerMethods.length; j++) {
2176:                        Method listenerMethod = listenerMethods[j];
2177:                        MetaMethod metaMethod = createMetaMethod(descriptor
2178:                                .getAddListenerMethod());
2179:                        String name = listenerMethod.getName();
2180:                        if (listeners.containsKey(name)) {
2181:                            listeners.put(name, AMBIGOUS_LISTENER_METHOD);
2182:                        } else {
2183:                            listeners.put(name, metaMethod);
2184:                        }
2185:                    }
2186:                }
2187:            }
2188:
2189:            private MetaMethod createMetaMethod(final Method method) {
2190:                if (registry.useAccessible()) {
2191:                    AccessController.doPrivileged(new PrivilegedAction() {
2192:                        public Object run() {
2193:                            method.setAccessible(true);
2194:                            return null;
2195:                        }
2196:                    });
2197:                }
2198:
2199:                MetaMethod answer = new MetaMethod(method);
2200:                if (isValidReflectorMethod(answer)) {
2201:                    allMethods.add(answer);
2202:                    answer.setMethodIndex(allMethods.size());
2203:                } else {
2204:                    //log.warning("Creating reflection based dispatcher for: " + method);
2205:                    answer = new ReflectionMetaMethod(method);
2206:                }
2207:
2208:                if (useReflection) {
2209:                    //log.warning("Creating reflection based dispatcher for: " + method);
2210:                    return new ReflectionMetaMethod(method);
2211:                }
2212:
2213:                return answer;
2214:            }
2215:
2216:            private boolean isValidReflectorMethod(MetaMethod method) {
2217:                // We cannot use a reflector if the method is private, protected, or package accessible only.
2218:                if (!method.isPublic()) {
2219:                    return false;
2220:                }
2221:                // lets see if this method is implemented on an interface
2222:                List interfaceMethods = getInterfaceMethods();
2223:                for (Iterator iter = interfaceMethods.iterator(); iter
2224:                        .hasNext();) {
2225:                    MetaMethod aMethod = (MetaMethod) iter.next();
2226:                    if (method.isSame(aMethod)) {
2227:                        method.setInterfaceClass(aMethod.getCallClass());
2228:                        return true;
2229:                    }
2230:                }
2231:                // it's no interface method, so try to find the highest class
2232:                // in hierarchy defining this method
2233:                Class declaringClass = method.getCallClass();
2234:                for (Class clazz = declaringClass; clazz != null; clazz = clazz
2235:                        .getSuperclass()) {
2236:                    try {
2237:                        final Class klazz = clazz;
2238:                        final String mName = method.getName();
2239:                        final Class[] parms = method.getParameterTypes();
2240:                        try {
2241:                            Method m = (Method) AccessController
2242:                                    .doPrivileged(new PrivilegedExceptionAction() {
2243:                                        public Object run()
2244:                                                throws NoSuchMethodException {
2245:                                            return klazz.getDeclaredMethod(
2246:                                                    mName, parms);
2247:                                        }
2248:                                    });
2249:                            if (!Modifier.isPublic(clazz.getModifiers()))
2250:                                continue;
2251:                            if (!Modifier.isPublic(m.getModifiers()))
2252:                                continue;
2253:                            declaringClass = clazz;
2254:                        } catch (PrivilegedActionException pae) {
2255:                            if (pae.getException() instanceof  NoSuchMethodException) {
2256:                                throw (NoSuchMethodException) pae
2257:                                        .getException();
2258:                            } else {
2259:                                throw new RuntimeException(pae.getException());
2260:                            }
2261:                        }
2262:                    } catch (SecurityException e) {
2263:                        continue;
2264:                    } catch (NoSuchMethodException e) {
2265:                        continue;
2266:                    }
2267:                }
2268:                if (!Modifier.isPublic(declaringClass.getModifiers()))
2269:                    return false;
2270:                method.setCallClass(declaringClass);
2271:
2272:                return true;
2273:            }
2274:
2275:            private void generateReflector() {
2276:                reflector = registry.loadReflector(theClass, allMethods);
2277:                if (reflector == null) {
2278:                    throw new RuntimeException("Should have a reflector for "
2279:                            + theClass.getName());
2280:                }
2281:                // lets set the reflector on all the methods
2282:                for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
2283:                    MetaMethod metaMethod = (MetaMethod) iter.next();
2284:                    metaMethod.setReflector(reflector);
2285:                }
2286:            }
2287:
2288:            public List getMethods() {
2289:                return allMethods;
2290:            }
2291:
2292:            public List getMetaMethods() {
2293:                return new ArrayList(newGroovyMethodsList);
2294:            }
2295:
2296:            private synchronized List getInterfaceMethods() {
2297:                if (interfaceMethods == null) {
2298:                    interfaceMethods = new ArrayList();
2299:                    Class type = theClass;
2300:                    while (type != null) {
2301:                        Class[] interfaces = type.getInterfaces();
2302:                        for (int i = 0; i < interfaces.length; i++) {
2303:                            Class iface = interfaces[i];
2304:                            Method[] methods = iface.getMethods();
2305:                            addInterfaceMethods(interfaceMethods, methods);
2306:                        }
2307:                        type = type.getSuperclass();
2308:                    }
2309:                }
2310:                return interfaceMethods;
2311:            }
2312:
2313:            private void addInterfaceMethods(List list, Method[] methods) {
2314:                for (int i = 0; i < methods.length; i++) {
2315:                    list.add(createMetaMethod(methods[i]));
2316:                }
2317:            }
2318:
2319:            private static class MethodIndexAction {
2320:                public void iterate(Map classMethodIndex) {
2321:                    for (Iterator iter = classMethodIndex.entrySet().iterator(); iter
2322:                            .hasNext();) {
2323:                        Map.Entry classEntry = (Map.Entry) iter.next();
2324:                        Map methodIndex = (Map) classEntry.getValue();
2325:                        Class clazz = (Class) classEntry.getKey();
2326:                        if (skipClass(clazz))
2327:                            continue;
2328:                        for (Iterator iterator = methodIndex.entrySet()
2329:                                .iterator(); iterator.hasNext();) {
2330:                            Map.Entry nameEntry = (Map.Entry) iterator.next();
2331:                            String name = (String) nameEntry.getKey();
2332:                            List oldList = (List) nameEntry.getValue();
2333:                            List newList = methodNameAction(clazz, name,
2334:                                    oldList);
2335:                            if (replaceMethodList())
2336:                                nameEntry.setValue(newList);
2337:                        }
2338:                    }
2339:                }
2340:
2341:                public List methodNameAction(Class clazz, String methodName,
2342:                        List methods) {
2343:                    List newList = new ArrayList(methods.size());
2344:                    for (Iterator methodIter = methods.iterator(); methodIter
2345:                            .hasNext();) {
2346:                        MetaMethod method = (MetaMethod) methodIter.next();
2347:                        methodListAction(clazz, methodName, method, methods,
2348:                                newList);
2349:                    }
2350:                    return newList;
2351:                }
2352:
2353:                public boolean skipClass(Class clazz) {
2354:                    return false;
2355:                }
2356:
2357:                public void methodListAction(Class clazz, String methodName,
2358:                        MetaMethod method, List oldList, List newList) {
2359:                }
2360:
2361:                public boolean replaceMethodList() {
2362:                    return true;
2363:                }
2364:            }
2365:
2366:            /**
2367:             * @deprecated
2368:             */
2369:            public Object getProperty(Object object, String property) {
2370:                return getProperty(theClass, object, property, false, false);
2371:            }
2372:
2373:            /**
2374:             * @deprecated
2375:             */
2376:            public void setProperty(Object object, String property,
2377:                    Object newValue) {
2378:                setProperty(theClass, object, property, newValue, false, false);
2379:            }
2380:
2381:            /**
2382:             * @deprecated
2383:             */
2384:            public Object getAttribute(Object object, String attribute) {
2385:                return getAttribute(theClass, object, attribute, false, false);
2386:            }
2387:
2388:            /**
2389:             * @deprecated
2390:             */
2391:            public void setAttribute(Object object, String attribute,
2392:                    Object newValue) {
2393:                setAttribute(theClass, object, attribute, newValue, false,
2394:                        false);
2395:            }
2396:
2397:            public MetaMethod pickMethod(String methodName, Class[] arguments) {
2398:                return getMethodWithoutCaching(theClass, methodName, arguments,
2399:                        false);
2400:            }
2401:
2402:            /**
2403:             * @deprecated use pickMethod instead
2404:             */
2405:            protected MetaMethod retrieveMethod(String methodName,
2406:                    Class[] arguments) {
2407:                return pickMethod(methodName, arguments);
2408:            }
2409:
2410:            /**
2411:             * remove all method call cache entries. This should be done if a 
2412:             * method is added during runtime, but not by using a category.
2413:             */
2414:            protected void clearInvocationCaches() {
2415:                staticMethodCache.clear();
2416:                methodCache.clear();
2417:            }
2418:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.