metaclassimpl.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,511 行 · 第 1/5 页

JAVA
1,511
字号
           return constructor;
       }
       constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
       if (constructor != null) {
           return constructor;
       }
       return null;
   }

   public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
       MethodKey methodKey = new DefaultMethodKey(theClass, methodName, arguments, false);
       MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
       if (method == null) {
           method = pickStaticMethod(theClass,methodName, arguments);
           cacheStaticMethod(methodKey, method);
       }
       return method;
   }

   public MetaMethod getMethodWithoutCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
       MetaMethod method = null;
       List methods = getMethods(sender,methodName,isCallToSuper);
       if (methods!=null && !methods.isEmpty()) {
           method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
       }
       return method;
   }

   public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
       checkInitalised();
       if (log.isLoggable(Level.FINER)){
           MetaClassHelper.logMethodCall(object, methodName, arguments);
       }
       
       Class sender = object.getClass();
       if (object instanceof Class) sender = (Class) object;
       if (sender!=theClass) {
           MetaClass mc = registry.getMetaClass(sender);
           return mc.invokeStaticMethod(sender,methodName,arguments);
       }
       if (sender==Class.class) {
           return invokeMethod(object,methodName,arguments);
       }
       
       if (arguments==null) arguments = EMPTY_ARGUMENTS;
       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
       unwrap(arguments);
       
       // lets try use the cache to find the method
       MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, false);
       MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
       if (method == null) {
           method = pickStaticMethod(sender, methodName, argClasses);
           cacheStaticMethod(methodKey.createCopy(), method);
       }

       if (method != null) {
           return MetaClassHelper.doMethodInvoke(object, method, arguments);
       }

       throw new MissingMethodException(methodName, sender, arguments, true);
   }
   
   private MetaMethod pickStaticMethod(Class sender, String methodName, Class[] arguments) {
       MetaMethod method = null;
       List methods = getStaticMethods(sender,methodName);

       if (!methods.isEmpty()) {
           method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
       }
       if (method == null && theClass != Class.class) {
           MetaClass classMetaClass = registry.getMetaClass(Class.class);
           method = classMetaClass.pickMethod(methodName, arguments);
       }
       if (method == null) {
           method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), true);
       }
       return method;
   }

   public Object invokeConstructor(Object[] arguments) {
       return invokeConstructor(theClass,arguments,false);
   }

   public int selectConstructorAndTransformArguments(int numberOfCosntructors, Object[] arguments) {
       //TODO: that is just a quick prototype, not the real thing!
       if (numberOfCosntructors != constructors.size()) {
           throw new IncompatibleClassChangeError("the number of constructors during runtime and compile time for "+
               this.theClass.getName()+" do not match. Expected "+numberOfCosntructors+" but got "+constructors.size());
       }
       
       if (arguments==null) arguments = EMPTY_ARGUMENTS;
       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
       unwrap(arguments);       
       Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
       if (constructor == null) {
           constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
       }
       if (constructor==null) {
           throw new GroovyRuntimeException(
                   "Could not find matching constructor for: "
                       + theClass.getName()
                       + "("+InvokerHelper.toTypeString(arguments)+")");
       }
       List l = new ArrayList(constructors);
       Comparator comp = new Comparator() {
           public int compare(Object arg0, Object arg1) {
               Constructor c0 = (Constructor) arg0;
               Constructor c1 = (Constructor) arg1;
               String descriptor0 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c0.getParameterTypes()); 
               String descriptor1 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c1.getParameterTypes());
               return descriptor0.compareTo(descriptor1);
           }            
       };
       Collections.sort(l,comp);
       int found = -1;
       for (int i=0; i<l.size(); i++) {
           if (l.get(i)!=constructor) continue;
           found = i;
           break;
       }
       // NOTE: must be changed to "1 |" if constructor was vargs
       int ret = 0 | (found << 8);
       return ret;
   }
   
   /**
    * checks if the initialisation of the class id complete.
    * This method should be called as a form of assert, it is no
    * way to test if there is still initialisation work to be done. 
    * Such logic must be implemented in a different way.
    * @throws IllegalStateException if the initialisation is incomplete yet
    */
   protected void checkInitalised() {
       if (!isInitialized())
           throw new IllegalStateException(
                   "initialize must be called for meta " +
                   "class of "+ theClass + 
                   "("+this.getClass() + ") " +
                   "to complete initialisation process " +
                   "before any invocation or field/property " +
                   "access can be done");
   }
   
   private Object invokeConstructor(Class at, Object[] arguments, boolean setAccessible) {
       checkInitalised();
       if (arguments==null) arguments = EMPTY_ARGUMENTS;
       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
       unwrap(arguments);       
       Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
       if (constructor != null) {
           return doConstructorInvoke(at, constructor, arguments, true);
       }
       constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
       if (constructor != null) {
           return doConstructorInvoke(at, constructor, arguments, true);
       }

       if (arguments.length == 1) {
           Object firstArgument = arguments[0];
           if (firstArgument instanceof Map) {
               constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
               if (constructor != null) {
                   Object bean = doConstructorInvoke(at, constructor, MetaClassHelper.EMPTY_ARRAY, true);
                   setProperties(bean, ((Map) firstArgument));
                   return bean;
               }
           }
       }
       throw new GroovyRuntimeException(
                   "Could not find matching constructor for: "
                       + theClass.getName()
                       + "("+InvokerHelper.toTypeString(arguments)+")");
   }

   /**
    * Sets a number of bean properties from the given Map where the keys are
    * the String names of properties and the values are the values of the
    * properties to set
    */
   public void setProperties(Object bean, Map map) {
       checkInitalised();
       for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
           Map.Entry entry = (Map.Entry) iter.next();
           String key = entry.getKey().toString();

           Object value = entry.getValue();
           setProperty(bean, key, value);
       }
   }
   
   /**
    * @return the given property's value on the object
    */
   public Object getProperty(Class sender, Object object, String name, boolean useSuper, boolean fromInsideClass) {
       checkInitalised();
       
       //----------------------------------------------------------------------
       // handling of static
       //----------------------------------------------------------------------
       boolean isStatic = theClass != Class.class && object instanceof Class;
       if (isStatic && object != theClass) {
           MetaClass mc = registry.getMetaClass((Class) object);
           return mc.getProperty(sender,object,name,useSuper,false);
       }
    
       MetaMethod method = null;
       Object[] arguments = EMPTY_ARGUMENTS;

       //----------------------------------------------------------------------
       // getter
       //----------------------------------------------------------------------
       MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
       if (mp != null) {
           if (mp instanceof MetaBeanProperty) {
               MetaBeanProperty mbp = (MetaBeanProperty) mp;
               method = mbp.getGetter();
               mp = mbp.getField();
           } 
       }

       // check for a category method named like a getter 
       if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
           String getterName = "get"+MetaClassHelper.capitalize(name);
           method = getCategoryMethodGetter(sender,getterName,false);
       }

       //----------------------------------------------------------------------
       // field
       //----------------------------------------------------------------------
       if (method==null && mp!=null) {
           return mp.getProperty(object);
       }
       

       //----------------------------------------------------------------------
       // generic get method
       //----------------------------------------------------------------------       
       // check for a generic get method provided through a category
       if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
           method = getCategoryMethodGetter(sender,"get",true);
           if (method!=null) arguments = new Object[]{name};
       }

       // the generic method is valid, if available (!=null), if static or
       // if it is not static and we do no static access
       if (method==null && genericGetMethod != null && !(!genericGetMethod.isStatic() && isStatic)) {
           arguments = new Object[]{ name };
           method = genericGetMethod;
       } 
       
       //----------------------------------------------------------------------
       // special cases
       //----------------------------------------------------------------------
       if (method==null) {
           /** todo these special cases should be special MetaClasses maybe */
           if (theClass != Class.class && object instanceof Class) {
               MetaClass mc = registry.getMetaClass(Class.class);
               return mc.getProperty(Class.class,object,name,useSuper,false);
           } else if (object instanceof Collection) {
               return DefaultGroovyMethods.getAt((Collection) object, name);
           } else if (object instanceof Object[]) {
               return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), name);
           } else {
               MetaMethod addListenerMethod = (MetaMethod) listeners.get(name);
               if (addListenerMethod != null) {
                   //TODO: one day we could try return the previously registered Closure listener for easy removal
                   return null;
               }
           }
       } else {
           
           //----------------------------------------------------------------------
           // executing the getter method 
           //----------------------------------------------------------------------
           return MetaClassHelper.doMethodInvoke(object,method,arguments);
       }
       
       //----------------------------------------------------------------------
       // error due to missing method/field
       //----------------------------------------------------------------------
       throw new MissingPropertyException(name, theClass);   
   }

   private MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
       List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
       if (possibleGenericMethods != null) {
           for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
               MetaMethod mmethod = (MetaMethod) iter.next();
               Class[] paramTypes = mmethod.getParameterTypes();
               if (useLongVersion) {
                   if (paramTypes.length==1 && paramTypes[0] == String.class) {
                       return mmethod;
                   }
               } else {
                   if (paramTypes.length==0) return mmethod;
               }
           }
       }
       return null;
   }
   
   private MetaMethod getCategoryMethodSetter(Class sender, String name, boolean useLongVersion) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?