Save This Page
Home » Groovy-1.7.0 » org.codehaus » groovy » runtime » metaclass » [javadoc | source]
    1   /*
    2    * Copyright 2003-2007 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.codehaus.groovy.runtime.metaclass;
   18   
   19   import groovy.lang;
   20   
   21   import org.codehaus.groovy.reflection;
   22   import org.codehaus.groovy.runtime.InvokerHelper;
   23   import org.codehaus.groovy.runtime.MetaClassHelper;
   24   import org.codehaus.groovy.runtime.callsite.CallSite;
   25   import org.codehaus.groovy.runtime.callsite.PogoMetaClassSite;
   26   import org.codehaus.groovy.runtime.wrappers.Wrapper;
   27   import org.codehaus.groovy.util.FastArray;
   28   
   29   import java.lang.reflect.Constructor;
   30   import java.lang.reflect.Method;
   31   import java.util;
   32   
   33   /**
   34    * A meta class for closures generated by the Groovy compiler. These classes
   35    * have special characteristics this MetaClass uses. One of these is that a
   36    * generated Closure has only additional doCall methods, all other methods
   37    * are in the Closure class as well. To use this fact this MetaClass uses
   38    * a MetaClass for Closure as static field And delegates calls to this
   39    * MetaClass if needed. This allows a lean implementation for this MetaClass.
   40    * Multiple generated closures will then use the same MetaClass for Closure.
   41    * For static dispatching this class uses the MetaClass of Class, again
   42    * all instances of this class will share that MetaClass. The Class MetaClass
   43    * is initialized lazy, because most operations do not need this MetaClass.
   44    * <p/>
   45    * The Closure and Class MetaClasses are not replaceable.
   46    * <p/>
   47    * This MetaClass is for internal usage only!
   48    *
   49    * @author Jochen Theodorou
   50    * @since 1.5
   51    */
   52   public final class ClosureMetaClass extends MetaClassImpl {
   53       private boolean initialized;
   54       private final FastArray closureMethods = new FastArray(3);
   55       private Map attributes = new HashMap();
   56       private MethodChooser chooser;
   57       private volatile boolean attributeInitDone = false;
   58   
   59       private static final MetaClassImpl CLOSURE_METACLASS;
   60       private static MetaClassImpl classMetaClass;
   61       private static final Object[] EMPTY_ARGUMENTS = {};
   62       private static final String CLOSURE_CALL_METHOD = "call";
   63       private static final String CLOSURE_DO_CALL_METHOD = "doCall";
   64       private static final String CLOSURE_CURRY_METHOD = "curry";
   65   
   66       static {
   67           CLOSURE_METACLASS = new MetaClassImpl(Closure.class);
   68           CLOSURE_METACLASS.initialize();
   69       }
   70   
   71       private static synchronized MetaClass getStaticMetaClass() {
   72           if (classMetaClass == null) {
   73               classMetaClass = new MetaClassImpl(Class.class);
   74               classMetaClass.initialize();
   75           }
   76           return classMetaClass;
   77       }
   78   
   79       private interface MethodChooser {
   80           Object chooseMethod(Class[] arguments, boolean coerce);
   81       }
   82   
   83       private static class StandardClosureChooser implements MethodChooser {
   84           private final MetaMethod doCall0;
   85           private final MetaMethod doCall1;
   86   
   87           StandardClosureChooser(MetaMethod m0, MetaMethod m1) {
   88               doCall0 = m0;
   89               doCall1 = m1;
   90           }
   91   
   92           public Object chooseMethod(Class[] arguments, boolean coerce) {
   93               if (arguments.length == 0) return doCall0;
   94               if (arguments.length == 1) return doCall1;
   95               return null;
   96           }
   97       }
   98   
   99       private static class NormalMethodChooser implements MethodChooser {
  100           private final FastArray methods;
  101           final Class theClass;
  102   
  103           NormalMethodChooser(Class theClass, FastArray methods) {
  104               this.theClass = theClass;
  105               this.methods = methods;
  106           }
  107   
  108           public Object chooseMethod(Class[] arguments, boolean coerce) {
  109               if (arguments.length == 0) {
  110                   return MetaClassHelper.chooseEmptyMethodParams(methods);
  111               } else if (arguments.length == 1 && arguments[0] == null) {
  112                   return MetaClassHelper.chooseMostGeneralMethodWith1NullParam(methods);
  113               } else {
  114                   List matchingMethods = new ArrayList();
  115   
  116                   final int len = methods.size();
  117                   final Object[] data = methods.getArray();
  118                   for (int i = 0; i != len; ++i) {
  119                       Object method = data[i];
  120   
  121                       // making this false helps find matches
  122                       if (((ParameterTypes) method).isValidMethod(arguments)) {
  123                           matchingMethods.add(method);
  124                       }
  125                   }
  126                   if (matchingMethods.isEmpty()) {
  127                       return null;
  128                   } else if (matchingMethods.size() == 1) {
  129                       return matchingMethods.get(0);
  130                   }
  131                   return chooseMostSpecificParams(CLOSURE_DO_CALL_METHOD, matchingMethods, arguments);
  132               }
  133           }
  134   
  135           private Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
  136               long matchesDistance = -1;
  137               LinkedList matches = new LinkedList();
  138               for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
  139                   Object method = iter.next();
  140                   final ParameterTypes parameterTypes = (ParameterTypes) method;
  141                   Class[] paramTypes = parameterTypes.getNativeParameterTypes();
  142                   if (!MetaClassHelper.parametersAreCompatible(arguments, paramTypes)) continue;
  143                   long dist = MetaClassHelper.calculateParameterDistance(arguments, parameterTypes);
  144                   if (dist == 0) return method;
  145                   if (matches.isEmpty()) {
  146                       matches.add(method);
  147                       matchesDistance = dist;
  148                   } else if (dist < matchesDistance) {
  149                       matchesDistance = dist;
  150                       matches.clear();
  151                       matches.add(method);
  152                   } else if (dist == matchesDistance) {
  153                       matches.add(method);
  154                   }
  155   
  156               }
  157               if (matches.size() == 1) {
  158                   return matches.getFirst();
  159               }
  160               if (matches.isEmpty()) {
  161                   return null;
  162               }
  163   
  164               //more than one matching method found --> ambigous!
  165               String msg = "Ambiguous method overloading for method ";
  166               msg += theClass.getName() + "#" + name;
  167               msg += ".\nCannot resolve which method to invoke for ";
  168               msg += InvokerHelper.toString(arguments);
  169               msg += " due to overlapping prototypes between:";
  170               for (Iterator iter = matches.iterator(); iter.hasNext();) {
  171                   CachedClass[] types = ((ParameterTypes) iter.next()).getParameterTypes();
  172                   msg += "\n\t" + InvokerHelper.toString(types);
  173               }
  174               throw new GroovyRuntimeException(msg);
  175           }
  176       }
  177   
  178   
  179       public ClosureMetaClass(MetaClassRegistry registry, Class theClass) {
  180           super(registry, theClass);
  181       }
  182   
  183       public MetaProperty getMetaProperty(String name) {
  184           return CLOSURE_METACLASS.getMetaProperty(name);
  185       }
  186   
  187       private void unwrap(Object[] arguments) {
  188           for (int i = 0; i != arguments.length; i++) {
  189               if (arguments[i] instanceof Wrapper) {
  190                   arguments[i] = ((Wrapper) arguments[i]).unwrap();
  191               }
  192           }
  193       }
  194   
  195       private MetaMethod pickClosureMethod(Class[] argClasses) {
  196           Object answer = chooser.chooseMethod(argClasses, false);
  197           return (MetaMethod) answer;
  198       }
  199   
  200       private MetaMethod getDelegateMethod(Closure closure, Object delegate, String methodName, Class[] argClasses) {
  201           if (delegate == closure || delegate == null) return null;
  202           MetaClass delegateMetaClass;
  203           if (delegate instanceof Class) {
  204               delegateMetaClass = registry.getMetaClass((Class)delegate);
  205               return delegateMetaClass.getStaticMetaMethod(methodName, argClasses);
  206           }
  207           else {
  208               delegateMetaClass = lookupObjectMetaClass(delegate);
  209               MetaMethod method = delegateMetaClass.pickMethod(methodName, argClasses);
  210               if (method != null) {
  211                 return method;
  212               }
  213   
  214               if (delegateMetaClass instanceof ExpandoMetaClass) {
  215                  method = ((ExpandoMetaClass)delegateMetaClass).findMixinMethod(methodName, argClasses);
  216   
  217                  if (method != null) {
  218                     onMixinMethodFound(method);
  219                     return method;
  220                  }
  221               }
  222   
  223               if (delegateMetaClass instanceof MetaClassImpl) {
  224                   method = MetaClassImpl.findMethodInClassHierarchy(getTheClass(), methodName, argClasses, this);
  225                   if(method != null) {
  226                       onSuperMethodFoundInHierarchy(method);
  227                       return method;
  228                   }
  229               }
  230   
  231               return method;
  232           }
  233       }
  234   
  235       public Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
  236           checkInitalised();
  237           if (object == null) {
  238               throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
  239           }
  240   
  241           final Object[] arguments = makeArguments(originalArguments, methodName); 
  242           final Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
  243           unwrap(arguments);
  244   
  245           MetaMethod method;
  246           final Closure closure = (Closure) object;
  247   
  248           if (CLOSURE_DO_CALL_METHOD.equals(methodName) || CLOSURE_CALL_METHOD.equals(methodName)) {
  249               method = pickClosureMethod(argClasses);
  250               if (method==null && arguments.length==1 && arguments[0] instanceof List) {
  251                   Object[] newArguments = ((List) arguments[0]).toArray();
  252                   Class[] newArgClasses = MetaClassHelper.convertToTypeArray(newArguments);
  253                   method = pickClosureMethod(newArgClasses);
  254                   if (method!=null) {
  255                       method = new TransformMetaMethod(method) {
  256                           public Object invoke(Object object, Object[] arguments) {
  257                               Object firstArgument = arguments[0];
  258                               List list = (List) firstArgument;
  259                               arguments = list.toArray();
  260                               return super.invoke(object, arguments);
  261                           }
  262                       };
  263                   }
  264               }
  265               if (method==null) throw new MissingMethodException(methodName, theClass, arguments, false);
  266           } else if (CLOSURE_CURRY_METHOD.equals(methodName)) {
  267               return closure.curry(arguments);
  268           } else {
  269               method = CLOSURE_METACLASS.pickMethod(methodName, argClasses);
  270           }
  271    
  272           if (method != null) return method.doMethodInvoke(object, arguments);
  273   
  274           MissingMethodException last = null;
  275           Object callObject = object;
  276           if (method == null) {
  277               final Object owner = closure.getOwner();
  278               final Object delegate = closure.getDelegate();
  279               final Object thisObject = closure.getThisObject();
  280               final int resolveStrategy = closure.getResolveStrategy();
  281               boolean invokeOnDelegate = false;
  282               boolean invokeOnOwner = false;
  283               boolean ownerFirst = true;
  284   
  285               switch (resolveStrategy) {
  286                   case Closure.TO_SELF:
  287                       break;
  288                   case Closure.DELEGATE_ONLY:
  289                       method = getDelegateMethod(closure, delegate, methodName, argClasses);
  290                       callObject = delegate;
  291                       if (method == null) {
  292                           invokeOnDelegate = delegate != closure && (delegate instanceof GroovyObject);
  293                       }
  294                       break;
  295                   case Closure.OWNER_ONLY:
  296                       method = getDelegateMethod(closure, owner, methodName, argClasses);
  297                       callObject = owner;
  298                       if (method == null) {
  299                           invokeOnOwner = owner != closure && (owner instanceof GroovyObject);
  300                       }
  301   
  302                       break;
  303                   case Closure.DELEGATE_FIRST:
  304                       method = getDelegateMethod(closure, delegate, methodName, argClasses);
  305                       callObject = delegate;
  306                       if (method == null) {
  307                           method = getDelegateMethod(closure, owner, methodName, argClasses);
  308                           callObject = owner;
  309                       }
  310                       if (method == null) {
  311                           invokeOnDelegate = delegate != closure && (delegate instanceof GroovyObject);
  312                           invokeOnOwner = owner != closure && (owner instanceof GroovyObject);
  313                           ownerFirst = false;
  314                       }
  315                       break;
  316                   default: // owner first
  317                       // owner first means we start with the outer most owner that is not a generated closure
  318                       // this owner is equal to the this object, so we check that one first.                    
  319                       method = getDelegateMethod(closure, thisObject, methodName, argClasses);
  320                       callObject = thisObject;
  321                       if (method == null) {
  322                           //try finding a delegate that has that method... we start from 
  323                           // outside building a stack and try each delegate
  324                           LinkedList list = new LinkedList();
  325                           for (Object current = closure; current!=thisObject; ) {
  326                               Closure currentClosure = (Closure) current; 
  327                               if (currentClosure.getDelegate()!=null) list.add(current);
  328                               current=currentClosure.getOwner();
  329                           }
  330   
  331                           while (!list.isEmpty() && method==null) {
  332                               Closure closureWithDelegate = (Closure) list.removeLast();
  333                               Object currentDelegate = closureWithDelegate.getDelegate();
  334                               method = getDelegateMethod(closureWithDelegate,currentDelegate,methodName,argClasses);
  335                               callObject = currentDelegate;
  336                           }
  337                       }
  338                       if (method == null) {
  339                           invokeOnDelegate = delegate != closure && (delegate instanceof GroovyObject);
  340                           invokeOnOwner = owner != closure && (owner instanceof GroovyObject);
  341                       }
  342               }
  343               if (method == null && (invokeOnOwner || invokeOnDelegate)) {
  344                   try {
  345                       if (ownerFirst) {
  346                           return invokeOnDelegationObjects(invokeOnOwner, owner, invokeOnDelegate, delegate, methodName, arguments);
  347                       } else {
  348                           return invokeOnDelegationObjects(invokeOnDelegate, delegate, invokeOnOwner, owner, methodName, arguments);
  349                       }
  350                   } catch (MissingMethodException mme) {
  351                       last = mme;
  352                   }
  353               }
  354           }
  355   
  356           if (method != null) {
  357           	MetaClass metaClass = registry.getMetaClass(callObject.getClass());
  358           	if(metaClass instanceof ProxyMetaClass) {
  359           		return metaClass.invokeMethod(callObject, methodName, arguments);
  360           	} else {
  361           		return method.doMethodInvoke(callObject, arguments);
  362           	}
  363           } else {
  364               // if no method was found, try to find a closure defined as a field of the class and run it
  365               Object value = null;
  366               try {
  367                   value = this.getProperty(object, methodName);
  368               } catch (MissingPropertyException mpe) {
  369                   // ignore
  370               }
  371               if (value instanceof Closure) {  // This test ensures that value != this If you ever change this ensure that value != this
  372                   Closure cl = (Closure) value;
  373                   MetaClass delegateMetaClass = cl.getMetaClass();
  374                   return delegateMetaClass.invokeMethod(cl.getClass(), closure, CLOSURE_DO_CALL_METHOD, originalArguments, false, fromInsideClass);
  375               }
  376           }
  377   
  378           if (last != null) throw last;
  379           throw new MissingMethodException(methodName, theClass, arguments, false);
  380       }
  381   
  382       private Object[] makeArguments(Object[] arguments, String methodName) {
  383           if (arguments == null) return EMPTY_ARGUMENTS;
  384           return arguments;
  385       }
  386       
  387       private static Throwable unwrap(GroovyRuntimeException gre) {
  388           Throwable th = gre;
  389           if (th.getCause() != null && th.getCause() != gre) th = th.getCause();
  390           if (th != gre && (th instanceof GroovyRuntimeException)) return unwrap((GroovyRuntimeException) th);
  391           return th;
  392       }
  393   
  394       private Object invokeOnDelegationObjects(
  395               boolean invoke1, Object o1,
  396               boolean invoke2, Object o2,
  397               String methodName, Object[] args) {
  398           MissingMethodException first = null;
  399           if (invoke1) {
  400               GroovyObject go = (GroovyObject) o1;
  401               try {
  402                   return go.invokeMethod(methodName, args);
  403               } catch (MissingMethodException mme) {
  404                   first = mme;
  405               } catch (GroovyRuntimeException gre) {
  406                   Throwable th = unwrap(gre);
  407                   if ((th instanceof MissingMethodException)
  408                       && (methodName.equals(((MissingMethodException)th).getMethod())))
  409                   {
  410                       first = (MissingMethodException) th;
  411                   } else {
  412                       throw gre;
  413                   }
  414               }
  415           }
  416           if (invoke2 && (!invoke1 || o1 != o2)) {
  417               GroovyObject go = (GroovyObject) o2;
  418               try {
  419                   return go.invokeMethod(methodName, args);
  420               } catch (MissingMethodException mme) {
  421                   // patch needed here too, but we need a test case to trip it first
  422                   if (first == null) first = mme;
  423               } catch (GroovyRuntimeException gre) {
  424                   Throwable th = unwrap(gre);
  425                   if (th instanceof MissingMethodException) {
  426                       first = (MissingMethodException) th;
  427                   } else {
  428                       throw gre;
  429                   }
  430               }
  431           }
  432           throw first;
  433       }
  434   
  435       private synchronized void initAttributes() {
  436           if (!attributes.isEmpty()) return;
  437           attributes.put("!", null); // just a dummy for later
  438           CachedField[] fieldArray = theCachedClass.getFields();
  439           for (int i = 0; i < fieldArray.length; i++) {
  440               attributes.put(fieldArray[i].getName(), fieldArray[i]);
  441           }
  442           attributeInitDone = !attributes.isEmpty();
  443       }
  444   
  445       public synchronized void initialize() {
  446           if (!isInitialized()) {
  447               CachedMethod[] methodArray = theCachedClass.getMethods();
  448               synchronized (theCachedClass) {
  449                   for (int i = 0; i < methodArray.length; i++) {
  450                       final CachedMethod cachedMethod = methodArray[i];
  451                       if (!cachedMethod.getName().equals(CLOSURE_DO_CALL_METHOD)) continue;
  452                       MetaMethod method = cachedMethod;
  453                       closureMethods.add(method);
  454                   }
  455               }
  456               assignMethodChooser();
  457   
  458               initialized = true;
  459           }
  460       }
  461   
  462       private void assignMethodChooser() {
  463           if (closureMethods.size() == 1) {
  464               final MetaMethod doCall = (MetaMethod) closureMethods.get(0);
  465               final CachedClass[] c = doCall.getParameterTypes();
  466               int length = c.length;
  467               if (length == 0) {
  468                   // no arg method
  469                   chooser = new MethodChooser() {
  470                       public Object chooseMethod(Class[] arguments, boolean coerce) {
  471                           if (arguments.length == 0) return doCall;
  472                           return null;
  473                       }
  474                   };
  475               } else {
  476                   if (length == 1 && c[0].getTheClass() == Object.class) {
  477                       // Object fits all, so simple dispatch rule here
  478                       chooser = new MethodChooser() {
  479                           public Object chooseMethod(Class[] arguments, boolean coerce) {
  480                               // <2, because foo() is same as foo(null)
  481                               if (arguments.length < 2) return doCall;
  482                               return null;
  483                           }
  484                       };
  485                   } else {
  486                       boolean allObject = true;
  487                       for (int i = 0; i < c.length - 1; i++) {
  488                           if (c[i].getTheClass() != Object.class) {
  489                               allObject = false;
  490                               break;
  491                           }
  492                       }
  493                       if (allObject && c[c.length - 1].getTheClass() == Object.class) {
  494                           // all arguments are object, so test only if argument number is correct
  495                           chooser = new MethodChooser() {
  496                               public Object chooseMethod(Class[] arguments, boolean coerce) {
  497                                   if (arguments.length == c.length) return doCall;
  498                                   return null;
  499                               }
  500                           };
  501                       } else {
  502                           if (allObject && c[c.length - 1].getTheClass() == Object[].class) {
  503                               // all arguments are Object but last, which is a vargs argument, that
  504                               // will fit all, so jsut test if the number of argument is equal or
  505                               // more than the parameters we have.
  506                               final int minimumLength = c.length - 2;
  507                               chooser = new MethodChooser() {
  508                                   public Object chooseMethod(Class[] arguments, boolean coerce) {
  509                                       if (arguments.length > minimumLength) return doCall;
  510                                       return null;
  511                                   }
  512                               };
  513                           } else {
  514                               // general case for single method
  515                               chooser = new MethodChooser() {
  516                                   public Object chooseMethod(Class[] arguments, boolean coerce) {
  517                                       if (doCall.isValidMethod(arguments)) {
  518                                           return doCall;
  519                                       }
  520                                       return null;
  521                                   }
  522                               };
  523                           }
  524                       }
  525                   }
  526               }
  527           } else if (closureMethods.size() == 2) {
  528               MetaMethod m0 = null, m1 = null;
  529               for (int i = 0; i != closureMethods.size(); ++i) {
  530                   MetaMethod m = (MetaMethod) closureMethods.get(i);
  531                   CachedClass[] c = m.getParameterTypes();
  532                   if (c.length == 0) {
  533                       m0 = m;
  534                   } else {
  535                       if (c.length == 1 && c[0].getTheClass() == Object.class) {
  536                           m1 = m;
  537                       }
  538                   }
  539               }
  540               if (m0 != null && m1 != null) {
  541                   // standard closure (2 methods because "it" is with default null)
  542                   chooser = new StandardClosureChooser(m0, m1);
  543               }
  544           }
  545           if (chooser == null) {
  546               // standard chooser for cases if it is not a single method and if it is
  547               // not the standard closure.
  548               chooser = new NormalMethodChooser(theClass, closureMethods);
  549           }
  550       }
  551   
  552       private MetaClass lookupObjectMetaClass(Object object) {
  553           if (object instanceof GroovyObject) {
  554               GroovyObject go = (GroovyObject) object;
  555               return go.getMetaClass();
  556           }
  557           Class ownerClass = object.getClass();
  558           if (ownerClass == Class.class) {
  559               ownerClass = (Class) object;
  560               return registry.getMetaClass(ownerClass);
  561           }
  562           MetaClass metaClass = InvokerHelper.getMetaClass(object);
  563           return metaClass;
  564       }
  565   
  566       @Override
  567       public List<MetaMethod> getMethods() {
  568           List<MetaMethod> answer = CLOSURE_METACLASS.getMetaMethods();
  569           answer.addAll(closureMethods.toList());
  570           return answer;
  571       }
  572   
  573       @Override
  574       public List<MetaMethod> getMetaMethods() {
  575           return CLOSURE_METACLASS.getMetaMethods();
  576       }
  577   
  578       @Override
  579       public List<MetaProperty> getProperties() {
  580           return CLOSURE_METACLASS.getProperties();
  581       }
  582   
  583       @Override
  584       public MetaMethod pickMethod(String name, Class[] argTypes) {
  585           if (argTypes == null) argTypes = MetaClassHelper.EMPTY_CLASS_ARRAY;
  586           if (name.equals(CLOSURE_CALL_METHOD) || name.equals(CLOSURE_DO_CALL_METHOD)) {
  587               return pickClosureMethod(argTypes);
  588           }
  589           return CLOSURE_METACLASS.getMetaMethod(name, argTypes);
  590       }
  591   
  592       public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
  593           return null;
  594       }
  595   
  596       protected boolean isInitialized() {
  597           return initialized;
  598       }
  599   
  600       public MetaMethod getStaticMetaMethod(String name, Object[] args) {
  601           return CLOSURE_METACLASS.getStaticMetaMethod(name, args);
  602       }
  603   
  604       public MetaMethod getStaticMetaMethod(String name, Class[] argTypes) {
  605           return CLOSURE_METACLASS.getStaticMetaMethod(name, argTypes);
  606       }
  607   
  608       public Object getProperty(Class sender, Object object, String name, boolean useSuper, boolean fromInsideClass) {
  609           if (object instanceof Class) {
  610               return getStaticMetaClass().getProperty(sender, object, name, useSuper, fromInsideClass);
  611           } else {
  612               return CLOSURE_METACLASS.getProperty(sender, object, name, useSuper, fromInsideClass);
  613           }
  614       }
  615   
  616       @Override
  617       public Object getAttribute(Class sender, Object object, String attribute, boolean useSuper, boolean fromInsideClass) {
  618           if (object instanceof Class) {
  619               return getStaticMetaClass().getAttribute(sender, object, attribute, useSuper);
  620           } else {
  621               if (!attributeInitDone) initAttributes();
  622               CachedField mfp = (CachedField) attributes.get(attribute);
  623               if (mfp == null) {
  624                   return CLOSURE_METACLASS.getAttribute(sender, object, attribute, useSuper);
  625               } else {
  626                   return mfp.getProperty(object);
  627               }
  628           }
  629       }
  630   
  631       @Override
  632       public void setAttribute(Class sender, Object object, String attribute,
  633                                Object newValue, boolean useSuper, boolean fromInsideClass) {
  634           if (object instanceof Class) {
  635               getStaticMetaClass().setAttribute(sender, object, attribute, newValue, useSuper, fromInsideClass);
  636           } else {
  637               if (!attributeInitDone) initAttributes();
  638               CachedField mfp = (CachedField) attributes.get(attribute);
  639               if (mfp == null) {
  640                   CLOSURE_METACLASS.setAttribute(sender, object, attribute, newValue, useSuper, fromInsideClass);
  641               } else {
  642                   mfp.setProperty(object, newValue);
  643               }
  644           }
  645       }
  646   
  647       public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
  648           return getStaticMetaClass().invokeMethod(Class.class, object, methodName, arguments, false, false);
  649       }
  650   
  651       public void setProperty(Class sender, Object object, String name, Object newValue, boolean useSuper, boolean fromInsideClass) {
  652           if (object instanceof Class) {
  653               getStaticMetaClass().setProperty(sender, object, name, newValue, useSuper, fromInsideClass);
  654           } else {
  655               CLOSURE_METACLASS.setProperty(sender, object, name, newValue, useSuper, fromInsideClass);
  656           }
  657       }
  658   
  659       public MetaMethod getMethodWithoutCaching(int index, Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
  660           throw new UnsupportedOperationException();
  661       }
  662   
  663       public void setProperties(Object bean, Map map) {
  664           throw new UnsupportedOperationException();
  665       }
  666       
  667       public void addMetaBeanProperty(MetaBeanProperty mp) {
  668           throw new UnsupportedOperationException();
  669       }
  670   
  671       public void addMetaMethod(MetaMethod method) {
  672           throw new UnsupportedOperationException();
  673       }
  674   
  675       public void addNewInstanceMethod(Method method) {
  676           throw new UnsupportedOperationException();
  677       }
  678   
  679       public void addNewStaticMethod(Method method) {
  680           throw new UnsupportedOperationException();
  681       }
  682   
  683       public Constructor retrieveConstructor(Class[] arguments) {
  684           throw new UnsupportedOperationException();
  685       }
  686   
  687       public CallSite createPojoCallSite(CallSite site, Object receiver, Object[] args) {
  688           throw new UnsupportedOperationException();
  689       }
  690   
  691       public CallSite createPogoCallSite(CallSite site, Object[] args) {
  692          return new PogoMetaClassSite(site, this);
  693       }
  694   
  695       public CallSite createPogoCallCurrentSite(CallSite site, Class sender, Object[] args) {
  696           return new PogoMetaClassSite(site, this);
  697       }
  698   }

Save This Page
Home » Groovy-1.7.0 » org.codehaus » groovy » runtime » metaclass » [javadoc | source]