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.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
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 }