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 }