001 /* 002 * $Id: MetaMethod.java,v 1.15 2005/06/30 16:12:05 blackdrag 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.15 $ 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 void setDeclaringClass(Class c) { 128 declaringClass=c; 129 } 130 131 public int getMethodIndex() { 132 return methodIndex; 133 } 134 135 public void setMethodIndex(int methodIndex) { 136 this.methodIndex = methodIndex; 137 } 138 139 public int getModifiers() { 140 return modifiers; 141 } 142 143 public String getName() { 144 return name; 145 } 146 147 public Class[] getParameterTypes() { 148 return parameterTypes; 149 } 150 151 public Class getReturnType() { 152 return returnType; 153 } 154 155 public Reflector getReflector() { 156 return reflector; 157 } 158 159 public void setReflector(Reflector reflector) { 160 this.reflector = reflector; 161 } 162 163 public boolean isMethod(Method method) { 164 return name.equals(method.getName()) 165 && modifiers == method.getModifiers() 166 && returnType.equals(method.getReturnType()) 167 && equal(parameterTypes, method.getParameterTypes()); 168 } 169 170 protected boolean equal(Class[] a, Class[] b) { 171 if (a.length == b.length) { 172 for (int i = 0, size = a.length; i < size; i++) { 173 if (!a[i].equals(b[i])) { 174 return false; 175 } 176 } 177 return true; 178 } 179 return false; 180 } 181 182 public String toString() { 183 return super.toString() 184 + "[name: " 185 + name 186 + " params: " 187 + InvokerHelper.toString(parameterTypes) 188 + " returns: " 189 + returnType 190 + " owner: " 191 + declaringClass 192 + "]"; 193 } 194 195 public Object clone() { 196 try { 197 return super.clone(); 198 } 199 catch (CloneNotSupportedException e) { 200 throw new GroovyRuntimeException("This should never happen", e); 201 } 202 } 203 204 public boolean isStatic() { 205 return (modifiers & Modifier.STATIC) != 0; 206 } 207 208 public boolean isPrivate() { 209 return (modifiers & Modifier.PRIVATE) != 0; 210 } 211 212 public boolean isProtected() { 213 return (modifiers & Modifier.PROTECTED) != 0; 214 } 215 216 public boolean isPublic() { 217 return (modifiers & Modifier.PUBLIC) != 0; 218 } 219 220 /** 221 * @return true if the given method has the same name, parameters, return type 222 * and modifiers but may be defined on another type 223 */ 224 public boolean isSame(MetaMethod method) { 225 return name.equals(method.getName()) 226 && compatibleModifiers(modifiers, method.getModifiers()) 227 && returnType.equals(method.getReturnType()) 228 && equal(parameterTypes, method.getParameterTypes()); 229 } 230 231 protected boolean compatibleModifiers(int modifiersA, int modifiersB) { 232 int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC; 233 return (modifiersA & mask) == (modifiersB & mask); 234 } 235 236 public Class getInterfaceClass() { 237 return interfaceClass; 238 } 239 240 public void setInterfaceClass(Class interfaceClass) { 241 this.interfaceClass = interfaceClass; 242 } 243 244 public boolean isCacheable() { 245 return true; 246 } 247 248 }