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 }