001 /* 002 * $Id: MetaMethod.java,v 1.18 2005/10/17 08:36:21 tug 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.MetaClassHelper; 045 import org.codehaus.groovy.runtime.Reflector; 046 047 /** 048 * Represents a Method on a Java object a little like {@link java.lang.reflect.Method} 049 * except without using reflection to invoke the method 050 * 051 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> 052 * @version $Revision: 1.18 $ 053 */ 054 public class MetaMethod implements Cloneable { 055 056 private static final Logger log = Logger.getLogger(MetaMethod.class.getName()); 057 058 private String name; 059 private Class declaringClass; 060 private Class interfaceClass; 061 private Class[] parameterTypes; 062 private Class returnType; 063 private int modifiers; 064 private Reflector reflector; 065 private int methodIndex; 066 private Method method; 067 068 public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) { 069 this.name = name; 070 this.declaringClass = declaringClass; 071 this.parameterTypes = parameterTypes; 072 this.returnType = returnType; 073 this.modifiers = modifiers; 074 } 075 076 public MetaMethod(Method method) { 077 this( 078 method.getName(), 079 method.getDeclaringClass(), 080 method.getParameterTypes(), 081 method.getReturnType(), 082 method.getModifiers()); 083 this.method = method; 084 } 085 086 public MetaMethod(MetaMethod metaMethod) { 087 this(metaMethod.method); 088 } 089 090 /** 091 * Checks that the given parameters are valid to call this method 092 * 093 * @param arguments 094 * @throws IllegalArgumentException if the parameters are not valid 095 */ 096 public void checkParameters(Class[] arguments) { 097 // lets check that the argument types are valid 098 if (!MetaClassHelper.isValidMethod(getParameterTypes(), arguments, false)) { 099 throw new IllegalArgumentException( 100 "Parameters to method: " 101 + getName() 102 + " do not match types: " 103 + InvokerHelper.toString(getParameterTypes()) 104 + " for arguments: " 105 + InvokerHelper.toString(arguments)); 106 } 107 } 108 109 public Object invoke(Object object, Object[] arguments) throws Exception { 110 if (reflector != null) { 111 return reflector.invoke(this, object, arguments); 112 } 113 else { 114 AccessController.doPrivileged(new PrivilegedAction() { 115 public Object run() { 116 method.setAccessible(true); 117 return null; 118 } 119 }); 120 return method.invoke(object, arguments); 121 } 122 } 123 124 public Class getDeclaringClass() { 125 return declaringClass; 126 } 127 128 public void setDeclaringClass(Class c) { 129 declaringClass=c; 130 } 131 132 public int getMethodIndex() { 133 return methodIndex; 134 } 135 136 public void setMethodIndex(int methodIndex) { 137 this.methodIndex = methodIndex; 138 } 139 140 public int getModifiers() { 141 return modifiers; 142 } 143 144 public String getName() { 145 return name; 146 } 147 148 public Class[] getParameterTypes() { 149 return parameterTypes; 150 } 151 152 public Class getReturnType() { 153 return returnType; 154 } 155 156 public Reflector getReflector() { 157 return reflector; 158 } 159 160 public void setReflector(Reflector reflector) { 161 this.reflector = reflector; 162 } 163 164 public boolean isMethod(Method method) { 165 return name.equals(method.getName()) 166 && modifiers == method.getModifiers() 167 && returnType.equals(method.getReturnType()) 168 && equal(parameterTypes, method.getParameterTypes()); 169 } 170 171 protected boolean equal(Class[] a, Class[] b) { 172 if (a.length == b.length) { 173 for (int i = 0, size = a.length; i < size; i++) { 174 if (!a[i].equals(b[i])) { 175 return false; 176 } 177 } 178 return true; 179 } 180 return false; 181 } 182 183 public String toString() { 184 return super.toString() 185 + "[name: " 186 + name 187 + " params: " 188 + InvokerHelper.toString(parameterTypes) 189 + " returns: " 190 + returnType 191 + " owner: " 192 + declaringClass 193 + "]"; 194 } 195 196 public Object clone() { 197 try { 198 return super.clone(); 199 } 200 catch (CloneNotSupportedException e) { 201 throw new GroovyRuntimeException("This should never happen", e); 202 } 203 } 204 205 public boolean isStatic() { 206 return (modifiers & Modifier.STATIC) != 0; 207 } 208 209 public boolean isPrivate() { 210 return (modifiers & Modifier.PRIVATE) != 0; 211 } 212 213 public boolean isProtected() { 214 return (modifiers & Modifier.PROTECTED) != 0; 215 } 216 217 public boolean isPublic() { 218 return (modifiers & Modifier.PUBLIC) != 0; 219 } 220 221 /** 222 * @return true if the given method has the same name, parameters, return type 223 * and modifiers but may be defined on another type 224 */ 225 public boolean isSame(MetaMethod method) { 226 return name.equals(method.getName()) 227 && compatibleModifiers(modifiers, method.getModifiers()) 228 && returnType.equals(method.getReturnType()) 229 && equal(parameterTypes, method.getParameterTypes()); 230 } 231 232 protected boolean compatibleModifiers(int modifiersA, int modifiersB) { 233 int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC; 234 return (modifiersA & mask) == (modifiersB & mask); 235 } 236 237 public Class getInterfaceClass() { 238 return interfaceClass; 239 } 240 241 public void setInterfaceClass(Class interfaceClass) { 242 this.interfaceClass = interfaceClass; 243 } 244 245 public boolean isCacheable() { 246 return true; 247 } 248 249 }