Save This Page
Home » groovy-src-1.6.5 » groovy » lang » [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 groovy.lang;
   18   
   19   import org.codehaus.groovy.classgen.BytecodeHelper;
   20   import org.codehaus.groovy.reflection.CachedClass;
   21   import org.codehaus.groovy.reflection.GeneratedMetaMethod;
   22   import org.codehaus.groovy.reflection.ParameterTypes;
   23   import org.codehaus.groovy.runtime.InvokerHelper;
   24   import org.codehaus.groovy.runtime.MetaClassHelper;
   25   
   26   import java.lang.reflect.Modifier;
   27   
   28   /**
   29    * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
   30    * except without using reflection to invoke the method
   31    *
   32    * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
   33    * @author Alex Tkachman
   34    * @version $Revision: 15212 $
   35    */
   36   public abstract class MetaMethod extends ParameterTypes implements Cloneable {
   37       private String signature;
   38       private String mopName;
   39   
   40       public MetaMethod() {
   41       }
   42   
   43       public MetaMethod(Class [] pt) {
   44           super (pt);
   45       }
   46   
   47       public abstract int getModifiers();
   48   
   49       public abstract String getName();
   50   
   51       public abstract Class getReturnType();
   52   
   53       public abstract CachedClass getDeclaringClass();
   54   
   55       public abstract Object invoke(Object object, Object[] arguments);
   56   
   57       /**
   58        * Checks that the given parameters are valid to call this method
   59        *
   60        * @param arguments the arguments to check
   61        * @throws IllegalArgumentException if the parameters are not valid
   62        */
   63       public void checkParameters(Class[] arguments) {
   64           // lets check that the argument types are valid
   65           if (!isValidMethod(arguments)) {
   66               throw new IllegalArgumentException(
   67                       "Parameters to method: "
   68                       + getName()
   69                       + " do not match types: "
   70                       + InvokerHelper.toString(getParameterTypes())
   71                       + " for arguments: "
   72                       + InvokerHelper.toString(arguments));
   73           }
   74       }
   75   
   76       public boolean isMethod(MetaMethod method) {
   77           return getName().equals(method.getName())
   78               && getModifiers() == method.getModifiers()
   79               && getReturnType().equals(method.getReturnType())
   80               && equal(getParameterTypes(), method.getParameterTypes());
   81       }
   82   
   83       protected static boolean equal(CachedClass[] a, Class[] b) {
   84           if (a.length == b.length) {
   85               for (int i = 0, size = a.length; i < size; i++) {
   86                   if (!a[i].getTheClass().equals(b[i])) {
   87                       return false;
   88                   }
   89               }
   90               return true;
   91           }
   92           return false;
   93       }
   94   
   95       protected static boolean equal(CachedClass[] a, CachedClass[] b) {
   96           if (a.length == b.length) {
   97               for (int i = 0, size = a.length; i < size; i++) {
   98                   if (a[i] != b[i]) {
   99                       return false;
  100                   }
  101               }
  102               return true;
  103           }
  104           return false;
  105       }
  106   
  107       public String toString() {
  108           return super.toString()
  109               + "[name: "
  110               + getName()
  111               + " params: "
  112               + InvokerHelper.toString(getParameterTypes())
  113               + " returns: "
  114               + getReturnType()
  115               + " owner: "
  116               + getDeclaringClass()
  117               + "]";
  118       }
  119   
  120       public Object clone() {
  121           try {
  122               return super.clone();
  123           }
  124           catch (CloneNotSupportedException e) {
  125               throw new GroovyRuntimeException("This should never happen", e);
  126           }
  127       }
  128   
  129       public boolean isStatic() {
  130           return (getModifiers() & Modifier.STATIC) != 0;
  131       }
  132   
  133       public boolean isAbstract() {
  134           return (getModifiers() & Modifier.ABSTRACT) != 0;
  135       }
  136   
  137       public final boolean isPrivate() {
  138           return (getModifiers() & Modifier.PRIVATE) != 0;
  139       }
  140   
  141       public final boolean isProtected() {
  142           return (getModifiers() & Modifier.PROTECTED) != 0;
  143       }
  144   
  145       public final boolean isPublic() {
  146           return (getModifiers() & Modifier.PUBLIC) != 0;
  147       }
  148   
  149       /**
  150        * @param method the method to compare against
  151        * @return true if the given method has the same name, parameters, return type
  152        * and modifiers but may be defined on another type
  153        */
  154       public final boolean isSame(MetaMethod method) {
  155           return getName().equals(method.getName())
  156               && compatibleModifiers(getModifiers(), method.getModifiers())
  157               && getReturnType().equals(method.getReturnType())
  158               && equal(getParameterTypes(), method.getParameterTypes());
  159       }
  160   
  161       private static boolean compatibleModifiers(int modifiersA, int modifiersB) {
  162           int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
  163           return (modifiersA & mask) == (modifiersB & mask);
  164       }
  165   
  166       public boolean isCacheable() {
  167           return true;
  168       }
  169   
  170       public String getDescriptor() {
  171           return BytecodeHelper.getMethodDescriptor(getReturnType(), getNativeParameterTypes());
  172       }
  173   
  174       public synchronized String getSignature() {
  175           if (signature == null) {
  176               CachedClass [] parameters = getParameterTypes();
  177               final String name = getName();
  178               StringBuffer buf = new StringBuffer(name.length()+parameters.length*10);
  179               buf.append(getReturnType().getName());
  180               //
  181               buf.append(' ');
  182               buf.append(name);
  183               buf.append('(');
  184               for (int i = 0; i < parameters.length; i++) {
  185                   if (i > 0) {
  186                       buf.append(", ");
  187                   }
  188                   buf.append(parameters[i].getName());
  189               }
  190               buf.append(')');
  191               signature = buf.toString();
  192           }
  193           return signature;
  194       }
  195   
  196       public String getMopName() {
  197           if (mopName == null) {
  198             String name = getName();
  199             CachedClass declaringClass = getDeclaringClass();
  200             if ((getModifiers() & (Modifier.PUBLIC| Modifier.PROTECTED)) == 0)
  201               mopName = new StringBuffer().append("this$").append(declaringClass.getSuperClassDistance()).append("$").append(name).toString();
  202             else
  203               mopName = new StringBuffer().append("super$").append(declaringClass.getSuperClassDistance()).append("$").append(name).toString();
  204           }
  205           return mopName;
  206       }
  207   
  208       public final RuntimeException processDoMethodInvokeException (Exception e, Object object, Object [] argumentArray) {
  209           if (e instanceof IllegalArgumentException) {
  210               //TODO: test if this is OK with new MOP, should be changed!
  211               // we don't want the exception being unwrapped if it is a IllegalArgumentException
  212               // but in the case it is for example a IllegalThreadStateException, we want the unwrapping
  213               // from the runtime
  214               //Note: the reason we want unwrapping sometimes and sometimes not is that the method
  215               // invocation tries to invoke the method with and then reacts with type transformation
  216               // if the invocation failed here. This is OK for IllegalArgumentException, but it is
  217               // possible that a Reflector will be used to execute the call and then an Exception from inside
  218               // the method is not wrapped in a InvocationTargetException and we will end here.
  219               boolean setReason = e.getClass() != IllegalArgumentException.class || this instanceof GeneratedMetaMethod;
  220               return MetaClassHelper.createExceptionText("failed to invoke method: ", this, object, argumentArray, e, setReason);
  221           }
  222   
  223           if (e instanceof RuntimeException)
  224             return (RuntimeException) e;
  225   
  226           return MetaClassHelper.createExceptionText("failed to invoke method: ", this, object, argumentArray, e, true);
  227       }
  228   
  229       // This method is not final but it should be overloaded very carefully and only by generated methods
  230       // there is no guarantee that it will be called
  231       public Object doMethodInvoke(Object object, Object[] argumentArray) {
  232           argumentArray = coerceArgumentsToClasses(argumentArray);
  233           try {
  234               return invoke(object, argumentArray);
  235           } catch (Exception e) {
  236               throw processDoMethodInvokeException(e, object, argumentArray);
  237           }
  238       }
  239   }

Save This Page
Home » groovy-src-1.6.5 » groovy » lang » [javadoc | source]