1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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.15 $
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
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 void setDeclaringClass(Class c) {
128 declaringClass=c;
129 }
130
131 public int getMethodIndex() {
132 return methodIndex;
133 }
134
135 public void setMethodIndex(int methodIndex) {
136 this.methodIndex = methodIndex;
137 }
138
139 public int getModifiers() {
140 return modifiers;
141 }
142
143 public String getName() {
144 return name;
145 }
146
147 public Class[] getParameterTypes() {
148 return parameterTypes;
149 }
150
151 public Class getReturnType() {
152 return returnType;
153 }
154
155 public Reflector getReflector() {
156 return reflector;
157 }
158
159 public void setReflector(Reflector reflector) {
160 this.reflector = reflector;
161 }
162
163 public boolean isMethod(Method method) {
164 return name.equals(method.getName())
165 && modifiers == method.getModifiers()
166 && returnType.equals(method.getReturnType())
167 && equal(parameterTypes, method.getParameterTypes());
168 }
169
170 protected boolean equal(Class[] a, Class[] b) {
171 if (a.length == b.length) {
172 for (int i = 0, size = a.length; i < size; i++) {
173 if (!a[i].equals(b[i])) {
174 return false;
175 }
176 }
177 return true;
178 }
179 return false;
180 }
181
182 public String toString() {
183 return super.toString()
184 + "[name: "
185 + name
186 + " params: "
187 + InvokerHelper.toString(parameterTypes)
188 + " returns: "
189 + returnType
190 + " owner: "
191 + declaringClass
192 + "]";
193 }
194
195 public Object clone() {
196 try {
197 return super.clone();
198 }
199 catch (CloneNotSupportedException e) {
200 throw new GroovyRuntimeException("This should never happen", e);
201 }
202 }
203
204 public boolean isStatic() {
205 return (modifiers & Modifier.STATIC) != 0;
206 }
207
208 public boolean isPrivate() {
209 return (modifiers & Modifier.PRIVATE) != 0;
210 }
211
212 public boolean isProtected() {
213 return (modifiers & Modifier.PROTECTED) != 0;
214 }
215
216 public boolean isPublic() {
217 return (modifiers & Modifier.PUBLIC) != 0;
218 }
219
220 /***
221 * @return true if the given method has the same name, parameters, return type
222 * and modifiers but may be defined on another type
223 */
224 public boolean isSame(MetaMethod method) {
225 return name.equals(method.getName())
226 && compatibleModifiers(modifiers, method.getModifiers())
227 && returnType.equals(method.getReturnType())
228 && equal(parameterTypes, method.getParameterTypes());
229 }
230
231 protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
232 int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
233 return (modifiersA & mask) == (modifiersB & mask);
234 }
235
236 public Class getInterfaceClass() {
237 return interfaceClass;
238 }
239
240 public void setInterfaceClass(Class interfaceClass) {
241 this.interfaceClass = interfaceClass;
242 }
243
244 public boolean isCacheable() {
245 return true;
246 }
247
248 }