View Javadoc

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