View Javadoc
1 /* 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" must 27 * not be used to endorse or promote products derived from this 28 * software without prior written permission. For written 29 * permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * nor may "Apache" appear in their name, without prior written 33 * permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>;. 53 */ 54 package net.sf.cglib.reflect; 55 56 import java.lang.reflect.*; 57 import net.sf.cglib.*; 58 import net.sf.cglib.core.*; 59 import org.objectweb.asm.ClassVisitor; 60 import org.objectweb.asm.Type; 61 62 // TODO: don't require exact match for return type 63 64 /*** 65 * <b>DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS</b> 66 * 67 * <p> 68 * Delegates are a typesafe pointer to another method. Since Java does not 69 * have language support for such a construct, this utility will construct 70 * a proxy that forwards method calls to any method with the same signature. 71 * This utility is inspired in part by the C# delegate mechanism. We 72 * implemented it in a Java-centric manner. 73 * </p> 74 * 75 * <h2>Delegate</h2> 76 * <p> 77 * Any interface with one method can become the interface for a delegate. 78 * Consider the example below: 79 * </p> 80 * 81 * <pre> 82 * public interface MainDelegate { 83 * int main(String[] args); 84 * } 85 * </pre> 86 * 87 * <p> 88 * The interface above is an example of an interface that can become a 89 * delegate. It has only one method, and the interface is public. In 90 * order to create a delegate for that method, all we have to do is 91 * call <code>MethodDelegate.create(this, "alternateMain", MainDelegate.class)</code>. 92 * The following program will show how to use it: 93 * </p> 94 * 95 * <pre> 96 * public class Main { 97 * public static int main( String[] args ) { 98 * Main newMain = new Main(); 99 * MainDelegate start = (MainDelegate) 100 * MethodDelegate.create(newMain, "alternateMain", MainDelegate.class); 101 * return start.main( args ); 102 * } 103 * 104 * public int alternateMain( String[] args ) { 105 * for (int i = 0; i < args.length; i++) { 106 * System.out.println( args[i] ); 107 * } 108 * return args.length; 109 * } 110 * } 111 * </pre> 112 * 113 * <p> 114 * By themselves, delegates don't do much. Their true power lies in the fact that 115 * they can be treated like objects, and passed to other methods. In fact that is 116 * one of the key building blocks of building Intelligent Agents which in tern are 117 * the foundation of artificial intelligence. In the above program, we could have 118 * easily created the delegate to match the static <code>main</code> method by 119 * substituting the delegate creation call with this: 120 * <code>MethodDelegate.createStatic(getClass(), "main", MainDelegate.class)</code>. 121 * </p> 122 * <p> 123 * Another key use for Delegates is to register event listeners. It is much easier 124 * to have all the code for your events separated out into methods instead of individual 125 * classes. One of the ways Java gets around that is to create anonymous classes. 126 * They are particularly troublesome because many Debuggers do not know what to do 127 * with them. Anonymous classes tend to duplicate alot of code as well. We can 128 * use any interface with one declared method to forward events to any method that 129 * matches the signature (although the method name can be different). 130 * </p> 131 * 132 * <h3>Equality</h3> 133 * The criteria that we use to test if two delegates are equal are: 134 * <ul> 135 * <li> 136 * They both refer to the same instance. That is, the <code>instance</code> 137 * parameter passed to the newDelegate method was the same for both. The 138 * instances are compared with the identity equality operator, <code>==</code>. 139 * </li> 140 * <li>They refer to the same method as resolved by <code>Method.equals</code>.</li> 141 * </ul> 142 * 143 * @version $Id: MethodDelegate.java,v 1.20 2003/11/06 05:10:52 herbyderby Exp $ 144 */ 145 abstract public class MethodDelegate { 146 private static final MethodDelegateKey KEY_FACTORY = 147 (MethodDelegateKey)KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME); 148 149 protected Object target; 150 protected String eqMethod; 151 152 interface MethodDelegateKey { 153 Object newInstance(Class delegateClass, String methodName, Class iface); 154 } 155 156 public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) { 157 Generator gen = new Generator(); 158 gen.setTargetClass(targetClass); 159 gen.setMethodName(methodName); 160 gen.setInterface(iface); 161 return gen.create(); 162 } 163 164 public static MethodDelegate create(Object target, String methodName, Class iface) { 165 Generator gen = new Generator(); 166 gen.setTarget(target); 167 gen.setMethodName(methodName); 168 gen.setInterface(iface); 169 return gen.create(); 170 } 171 172 public boolean equals(Object obj) { 173 MethodDelegate other = (MethodDelegate)obj; 174 return target == other.target && eqMethod.equals(other.eqMethod); 175 } 176 177 public int hashCode() { 178 return target.hashCode() ^ eqMethod.hashCode(); 179 } 180 181 public Object getTarget() { 182 return target; 183 } 184 185 abstract public MethodDelegate newInstance(Object target); 186 187 public static class Generator extends AbstractClassGenerator { 188 private static final Source SOURCE = new Source(MethodDelegate.class.getName()); 189 private static final Signature NEW_INSTANCE = 190 TypeUtils.parseSignature("net.sf.cglib.reflect.MethodDelegate newInstance(Object)"); 191 private static final Type METHOD_DELEGATE = 192 TypeUtils.parseType("net.sf.cglib.reflect.MethodDelegate"); 193 194 private Object target; 195 private Class targetClass; 196 private String methodName; 197 private Class iface; 198 199 public Generator() { 200 super(SOURCE); 201 } 202 203 public void setTarget(Object target) { 204 this.target = target; 205 this.targetClass = target.getClass(); 206 } 207 208 public void setTargetClass(Class targetClass) { 209 this.targetClass = targetClass; 210 } 211 212 public void setMethodName(String methodName) { 213 this.methodName = methodName; 214 } 215 216 public void setInterface(Class iface) { 217 this.iface = iface; 218 } 219 220 protected ClassLoader getDefaultClassLoader() { 221 return targetClass.getClassLoader(); 222 } 223 224 public MethodDelegate create() { 225 setNamePrefix(targetClass.getName()); 226 Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface); 227 return (MethodDelegate)super.create(key); 228 } 229 230 protected Object firstInstance(Class type) { 231 return ((MethodDelegate)ReflectUtils.newInstance(type)).newInstance(target); 232 } 233 234 protected Object nextInstance(Object instance) { 235 return ((MethodDelegate)instance).newInstance(target); 236 } 237 238 public void generateClass(ClassVisitor v) throws NoSuchMethodException { 239 Method proxy = ReflectUtils.findInterfaceMethod(iface); 240 final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes()); 241 if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) { 242 throw new IllegalArgumentException("incompatible return types"); 243 } 244 245 boolean isStatic = Modifier.isStatic(method.getModifiers()); 246 if ((target == null) ^ isStatic) { 247 throw new IllegalArgumentException("Static method " + (isStatic ? "not " : "") + "expected"); 248 } 249 250 ClassEmitter ce = new ClassEmitter(v); 251 CodeEmitter e; 252 ce.begin_class(Constants.ACC_PUBLIC, 253 getClassName(), 254 METHOD_DELEGATE, 255 new Type[]{ Type.getType(iface) }, 256 Constants.SOURCE_FILE); 257 ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null, null); 258 EmitUtils.null_constructor(ce); 259 260 // generate proxied method 261 Method proxied = iface.getDeclaredMethods()[0]; 262 e = ce.begin_method(Constants.ACC_PUBLIC, 263 ReflectUtils.getSignature(proxied), 264 ReflectUtils.getExceptionTypes(proxied), 265 null); 266 e.load_this(); 267 e.super_getfield("target", Constants.TYPE_OBJECT); 268 e.checkcast(Type.getType(method.getDeclaringClass())); 269 e.load_args(); 270 e.invoke(method); 271 e.return_value(); 272 e.end_method(); 273 274 // newInstance 275 e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null, null); 276 e.new_instance_this(); 277 e.dup(); 278 e.dup2(); 279 e.invoke_constructor_this(); 280 e.getfield("eqMethod"); 281 e.super_putfield("eqMethod", Constants.TYPE_STRING); 282 e.load_arg(0); 283 e.super_putfield("target", Constants.TYPE_OBJECT); 284 e.return_value(); 285 e.end_method(); 286 287 // static initializer 288 e = ce.begin_static(); 289 Signature sig = ReflectUtils.getSignature(method); 290 e.push(sig.getName() + sig.getDescriptor()); 291 e.putfield("eqMethod"); 292 e.return_value(); 293 e.end_method(); 294 295 ce.end_class(); 296 } 297 } 298 }

This page was automatically generated by Maven