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 }