001 /*
002 * $Id: MetaMethod.java,v 1.14 2004/07/10 03:31:36 bran Exp $
003 *
004 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005 *
006 * Redistribution and use of this software and associated documentation
007 * ("Software"), with or without modification, are permitted provided that the
008 * following conditions are met:
009 * 1. Redistributions of source code must retain copyright statements and
010 * notices. Redistributions must also contain a copy of this document.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 * notice, this list of conditions and the following disclaimer in the
013 * documentation and/or other materials provided with the distribution.
014 * 3. The name "groovy" must not be used to endorse or promote products
015 * derived from this Software without prior written permission of The Codehaus.
016 * For written permission, please contact info@codehaus.org.
017 * 4. Products derived from this Software may not be called "groovy" nor may
018 * "groovy" appear in their names without prior written permission of The
019 * Codehaus. "groovy" is a registered trademark of The Codehaus.
020 * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
021 *
022 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
023 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
024 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
025 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
026 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
027 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
028 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
031 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
032 * DAMAGE.
033 *
034 */
035 package groovy.lang;
036
037 import java.lang.reflect.Method;
038 import java.lang.reflect.Modifier;
039 import java.security.AccessController;
040 import java.security.PrivilegedAction;
041 import java.util.logging.Logger;
042
043 import org.codehaus.groovy.runtime.InvokerHelper;
044 import org.codehaus.groovy.runtime.Reflector;
045
046 /**
047 * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
048 * except without using reflection to invoke the method
049 *
050 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
051 * @version $Revision: 1.14 $
052 */
053 public class MetaMethod implements Cloneable {
054
055 private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
056
057 private String name;
058 private Class declaringClass;
059 private Class interfaceClass;
060 private Class[] parameterTypes;
061 private Class returnType;
062 private int modifiers;
063 private Reflector reflector;
064 private int methodIndex;
065 private Method method;
066
067 public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
068 this.name = name;
069 this.declaringClass = declaringClass;
070 this.parameterTypes = parameterTypes;
071 this.returnType = returnType;
072 this.modifiers = modifiers;
073 }
074
075 public MetaMethod(Method method) {
076 this(
077 method.getName(),
078 method.getDeclaringClass(),
079 method.getParameterTypes(),
080 method.getReturnType(),
081 method.getModifiers());
082 this.method = method;
083 }
084
085 public MetaMethod(MetaMethod metaMethod) {
086 this(metaMethod.method);
087 }
088
089 /**
090 * Checks that the given parameters are valid to call this method
091 *
092 * @param arguments
093 * @throws IllegalArgumentException if the parameters are not valid
094 */
095 public void checkParameters(Class[] arguments) {
096 // lets check that the argument types are valid
097 if (!MetaClass.isValidMethod(getParameterTypes(), arguments, false)) {
098 throw new IllegalArgumentException(
099 "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 }