001 /* 002 * $Id: MetaMethod.java 4254 2006-11-23 20:38:19Z blackdrag $ 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.InvokerInvocationException; 045 import org.codehaus.groovy.runtime.MetaClassHelper; 046 import org.codehaus.groovy.runtime.Reflector; 047 048 /** 049 * Represents a Method on a Java object a little like {@link java.lang.reflect.Method} 050 * except without using reflection to invoke the method 051 * 052 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> 053 * @version $Revision: 4254 $ 054 */ 055 public class MetaMethod implements Cloneable { 056 057 private static final Logger log = Logger.getLogger(MetaMethod.class.getName()); 058 059 private String name; 060 private Class callClass; 061 private Class declaringClass; 062 private Class interfaceClass; 063 private Class[] parameterTypes; 064 private Class returnType; 065 private int modifiers; 066 private Reflector reflector; 067 private int methodIndex; 068 private Method method; 069 070 public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) { 071 this.name = name; 072 this.callClass = declaringClass; 073 this.declaringClass = declaringClass; 074 this.parameterTypes = parameterTypes; 075 this.returnType = returnType; 076 this.modifiers = modifiers; 077 } 078 079 public MetaMethod(Method method) { 080 this( 081 method.getName(), 082 method.getDeclaringClass(), 083 method.getParameterTypes(), 084 method.getReturnType(), 085 method.getModifiers()); 086 this.method = method; 087 } 088 089 public MetaMethod(MetaMethod metaMethod) { 090 this(metaMethod.method); 091 } 092 093 /** 094 * Checks that the given parameters are valid to call this method 095 * 096 * @param arguments 097 * @throws IllegalArgumentException if the parameters are not valid 098 */ 099 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 }