View Javadoc

    1   /*
    2    * $Id: MetaMethod.java,v 1.18 2005/10/17 08:36:21 tug Exp $
    3    *
    4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
    5    *
    6    * Redistribution and use of this software and associated documentation
    7    * ("Software"), with or without modification, are permitted provided that the
    8    * following conditions are met:
    9    *  1. Redistributions of source code must retain copyright statements and
    10   * notices. Redistributions must also contain a copy of this document.
    11   *  2. Redistributions in binary form must reproduce the above copyright
    12   * notice, this list of conditions and the following disclaimer in the
    13   * documentation and/or other materials provided with the distribution.
    14   *  3. The name "groovy" must not be used to endorse or promote products
    15   * derived from this Software without prior written permission of The Codehaus.
    16   * For written permission, please contact info@codehaus.org.
    17   *  4. Products derived from this Software may not be called "groovy" nor may
    18   * "groovy" appear in their names without prior written permission of The
    19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
    20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
    21   *
    22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
    23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
    26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    32   * DAMAGE.
    33   *
    34   */
    35  package groovy.lang;
    36
    37  import java.lang.reflect.Method;
    38  import java.lang.reflect.Modifier;
    39  import java.security.AccessController;
    40  import java.security.PrivilegedAction;
    41  import java.util.logging.Logger;
    42
    43  import org.codehaus.groovy.runtime.InvokerHelper;
    44  import org.codehaus.groovy.runtime.MetaClassHelper;
    45  import org.codehaus.groovy.runtime.Reflector;
    46
    47  /***
    48   * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
    49   * except without using reflection to invoke the method
    50   *
    51   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    52   * @version $Revision: 1.18 $
    53   */
    54  public class MetaMethod implements Cloneable {
    55
    56      private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
    57
    58      private String name;
    59      private Class declaringClass;
    60      private Class interfaceClass;
    61      private Class[] parameterTypes;
    62      private Class returnType;
    63      private int modifiers;
    64      private Reflector reflector;
    65      private int methodIndex;
    66      private Method method;
    67
    68      public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
    69          this.name = name;
    70          this.declaringClass = declaringClass;
    71          this.parameterTypes = parameterTypes;
    72          this.returnType = returnType;
    73          this.modifiers = modifiers;
    74      }
    75
    76      public MetaMethod(Method method) {
    77          this(
    78              method.getName(),
    79              method.getDeclaringClass(),
    80              method.getParameterTypes(),
    81              method.getReturnType(),
    82              method.getModifiers());
    83          this.method = method;
    84      }
    85
    86      public MetaMethod(MetaMethod metaMethod) {
    87          this(metaMethod.method);
    88      }
    89
    90      /***
    91       * Checks that the given parameters are valid to call this method
    92       *
    93       * @param arguments
    94       * @throws IllegalArgumentException if the parameters are not valid
    95       */
    96      public void checkParameters(Class[] arguments) {
    97          // lets check that the argument types are valid
    98          if (!MetaClassHelper.isValidMethod(getParameterTypes(), arguments, false)) {
    99              throw new IllegalArgumentException(
    100                     "Parameters to method: "
    101                     + getName()
    102                     + " do not match types: "
    103                     + InvokerHelper.toString(getParameterTypes())
    104                     + " for arguments: "
    105                     + InvokerHelper.toString(arguments));
    106         }
    107     }
    108
    109     public Object invoke(Object object, Object[] arguments) throws Exception {
    110         if (reflector != null) {
    111             return reflector.invoke(this, object, arguments);
    112         }
    113         else {
    114             AccessController.doPrivileged(new PrivilegedAction() {
    115 	    			public Object run() {
    116 	    			    method.setAccessible(true);
    117 	    			    return null;
    118 	    			}
    119 	    		});
    120             return method.invoke(object, arguments);
    121         }
    122     }
    123
    124     public Class getDeclaringClass() {
    125         return declaringClass;
    126     }
    127
    128     public void setDeclaringClass(Class c) {
    129         declaringClass=c;
    130     }
    131
    132     public int getMethodIndex() {
    133         return methodIndex;
    134     }
    135
    136     public void setMethodIndex(int methodIndex) {
    137         this.methodIndex = methodIndex;
    138     }
    139
    140     public int getModifiers() {
    141         return modifiers;
    142     }
    143
    144     public String getName() {
    145         return name;
    146     }
    147
    148     public Class[] getParameterTypes() {
    149         return parameterTypes;
    150     }
    151
    152     public Class getReturnType() {
    153         return returnType;
    154     }
    155
    156     public Reflector getReflector() {
    157         return reflector;
    158     }
    159
    160     public void setReflector(Reflector reflector) {
    161         this.reflector = reflector;
    162     }
    163
    164     public boolean isMethod(Method method) {
    165         return name.equals(method.getName())
    166             && modifiers == method.getModifiers()
    167             && returnType.equals(method.getReturnType())
    168             && equal(parameterTypes, method.getParameterTypes());
    169     }
    170
    171     protected boolean equal(Class[] a, Class[] b) {
    172         if (a.length == b.length) {
    173             for (int i = 0, size = a.length; i < size; i++) {
    174                 if (!a[i].equals(b[i])) {
    175                     return false;
    176                 }
    177             }
    178             return true;
    179         }
    180         return false;
    181     }
    182
    183     public String toString() {
    184         return super.toString()
    185             + "[name: "
    186             + name
    187             + " params: "
    188             + InvokerHelper.toString(parameterTypes)
    189             + " returns: "
    190             + returnType
    191             + " owner: "
    192             + declaringClass
    193             + "]";
    194     }
    195
    196     public Object clone() {
    197         try {
    198             return super.clone();
    199         }
    200         catch (CloneNotSupportedException e) {
    201             throw new GroovyRuntimeException("This should never happen", e);
    202         }
    203     }
    204
    205     public boolean isStatic() {
    206         return (modifiers & Modifier.STATIC) != 0;
    207     }
    208
    209     public boolean isPrivate() {
    210         return (modifiers & Modifier.PRIVATE) != 0;
    211     }
    212
    213     public boolean isProtected() {
    214         return (modifiers & Modifier.PROTECTED) != 0;
    215     }
    216
    217     public boolean isPublic() {
    218         return (modifiers & Modifier.PUBLIC) != 0;
    219     }
    220
    221     /***
    222      * @return true if the given method has the same name, parameters, return type
    223      * and modifiers but may be defined on another type
    224      */
    225     public boolean isSame(MetaMethod method) {
    226         return name.equals(method.getName())
    227             && compatibleModifiers(modifiers, method.getModifiers())
    228             && returnType.equals(method.getReturnType())
    229             && equal(parameterTypes, method.getParameterTypes());
    230     }
    231
    232     protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
    233         int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
    234         return (modifiersA & mask) == (modifiersB & mask);
    235     }
    236
    237     public Class getInterfaceClass() {
    238         return interfaceClass;
    239     }
    240
    241     public void setInterfaceClass(Class interfaceClass) {
    242         this.interfaceClass = interfaceClass;
    243     }
    244
    245     public boolean isCacheable() {
    246         return true;
    247     }
    248
    249 }