View Javadoc

    1   /*
    2    * $Id: MetaMethod.java,v 1.14 2004/07/10 03:31:36 bran 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.Reflector;
    45
    46  /***
    47   * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
    48   * except without using reflection to invoke the method
    49   *
    50   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    51   * @version $Revision: 1.14 $
    52   */
    53  public class MetaMethod implements Cloneable {
    54
    55      private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
    56
    57      private String name;
    58      private Class declaringClass;
    59      private Class interfaceClass;
    60      private Class[] parameterTypes;
    61      private Class returnType;
    62      private int modifiers;
    63      private Reflector reflector;
    64      private int methodIndex;
    65      private Method method;
    66
    67      public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
    68          this.name = name;
    69          this.declaringClass = declaringClass;
    70          this.parameterTypes = parameterTypes;
    71          this.returnType = returnType;
    72          this.modifiers = modifiers;
    73      }
    74
    75      public MetaMethod(Method method) {
    76          this(
    77              method.getName(),
    78              method.getDeclaringClass(),
    79              method.getParameterTypes(),
    80              method.getReturnType(),
    81              method.getModifiers());
    82          this.method = method;
    83      }
    84
    85      public MetaMethod(MetaMethod metaMethod) {
    86          this(metaMethod.method);
    87      }
    88
    89      /***
    90       * Checks that the given parameters are valid to call this method
    91       *
    92       * @param arguments
    93       * @throws IllegalArgumentException if the parameters are not valid
    94       */
    95      public void checkParameters(Class[] arguments) {
    96          // lets check that the argument types are valid
    97          if (!MetaClass.isValidMethod(getParameterTypes(), arguments, false)) {
    98              throw new IllegalArgumentException(
    99                      "Parameters to method: "
    100                     + getName()
    101                     + " do not match types: "
    102                     + InvokerHelper.toString(getParameterTypes())
    103                     + " for arguments: "
    104                     + InvokerHelper.toString(arguments));
    105         }
    106     }
    107
    108     public Object invoke(Object object, Object[] arguments) throws Exception {
    109         if (reflector != null) {
    110             return reflector.invoke(this, object, arguments);
    111         }
    112         else {
    113             AccessController.doPrivileged(new PrivilegedAction() {
    114 	    			public Object run() {
    115 	    			    method.setAccessible(true);
    116 	    			    return null;
    117 	    			}
    118 	    		});
    119             return method.invoke(object, arguments);
    120         }
    121     }
    122
    123     public Class getDeclaringClass() {
    124         return declaringClass;
    125     }
    126
    127     public int getMethodIndex() {
    128         return methodIndex;
    129     }
    130
    131     public void setMethodIndex(int methodIndex) {
    132         this.methodIndex = methodIndex;
    133     }
    134
    135     public int getModifiers() {
    136         return modifiers;
    137     }
    138
    139     public String getName() {
    140         return name;
    141     }
    142
    143     public Class[] getParameterTypes() {
    144         return parameterTypes;
    145     }
    146
    147     public Class getReturnType() {
    148         return returnType;
    149     }
    150
    151     public Reflector getReflector() {
    152         return reflector;
    153     }
    154
    155     public void setReflector(Reflector reflector) {
    156         this.reflector = reflector;
    157     }
    158
    159     public boolean isMethod(Method method) {
    160         return name.equals(method.getName())
    161             && modifiers == method.getModifiers()
    162             && returnType.equals(method.getReturnType())
    163             && equal(parameterTypes, method.getParameterTypes());
    164     }
    165
    166     protected boolean equal(Class[] a, Class[] b) {
    167         if (a.length == b.length) {
    168             for (int i = 0, size = a.length; i < size; i++) {
    169                 if (!a[i].equals(b[i])) {
    170                     return false;
    171                 }
    172             }
    173             return true;
    174         }
    175         return false;
    176     }
    177
    178     public String toString() {
    179         return super.toString()
    180             + "[name: "
    181             + name
    182             + " params: "
    183             + InvokerHelper.toString(parameterTypes)
    184             + " returns: "
    185             + returnType
    186             + " owner: "
    187             + declaringClass
    188             + "]";
    189     }
    190
    191     public Object clone() {
    192         try {
    193             return super.clone();
    194         }
    195         catch (CloneNotSupportedException e) {
    196             throw new GroovyRuntimeException("This should never happen", e);
    197         }
    198     }
    199
    200     public boolean isStatic() {
    201         return (modifiers & Modifier.STATIC) != 0;
    202     }
    203
    204     public boolean isPrivate() {
    205         return (modifiers & Modifier.PRIVATE) != 0;
    206     }
    207
    208     public boolean isProtected() {
    209         return (modifiers & Modifier.PROTECTED) != 0;
    210     }
    211
    212     public boolean isPublic() {
    213         return (modifiers & Modifier.PUBLIC) != 0;
    214     }
    215
    216     /***
    217      * @return true if the given method has the same name, parameters, return type
    218      * and modifiers but may be defined on another type
    219      */
    220     public boolean isSame(MetaMethod method) {
    221         return name.equals(method.getName())
    222             && compatibleModifiers(modifiers, method.getModifiers())
    223             && returnType.equals(method.getReturnType())
    224             && equal(parameterTypes, method.getParameterTypes());
    225     }
    226
    227     protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
    228         int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
    229         return (modifiersA & mask) == (modifiersB & mask);
    230     }
    231
    232     public Class getInterfaceClass() {
    233         return interfaceClass;
    234     }
    235
    236     public void setInterfaceClass(Class interfaceClass) {
    237         this.interfaceClass = interfaceClass;
    238     }
    239
    240     public boolean isCacheable() {
    241         return true;
    242     }
    243
    244 }