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; 55 56 import net.sf.cglib.core.*; 57 import java.lang.reflect.Method; 58 import java.util.*; 59 import org.objectweb.asm.ClassVisitor; 60 61 /*** 62 * Generates dynamic subclasses to enable method interception. This 63 * class started as a substitute for the standard Dynamic Proxy support 64 * included with JDK 1.3, but one that allowed the proxies to extend a 65 * concrete base class, in addition to implementing interfaces. The dynamically 66 * generated subclasses override the non-final methods of the superclass and 67 * have hooks which callback to user-defined interceptor 68 * implementations. 69 * <p> 70 * The original and most general callback type is the {@link MethodInterceptor}, which 71 * in AOP terms enables "around advice"--that is, you can invoke custom code both before 72 * and after the invocation of the "super" method. In addition you can modify the 73 * arguments before calling the super method, or not call it at all. 74 * <p> 75 * Although <code>MethodInterceptor</code> is generic enough to meet any 76 * interception need, it is often overkill. For simplicity and performance, additional 77 * specialized callback types, such as {@link LazyLoader} are also available. 78 * Often a single callback type will be used per enhanced class, but you can control 79 * which callback is used on a per-method basis with a {@link CallbackFilter}. 80 * <p> 81 * The most common uses of this class are embodied in the static helper methods. For 82 * advanced needs, such as customizing the <code>ClassLoader</code> to use, you should create 83 * a new instance of <code>Enhancer</code>. Other classes within CGLIB follow a similar pattern. 84 * <p> 85 * For an almost drop-in replacement for 86 * <code>java.lang.reflect.Proxy</code>, see the {@link Proxy} class. 87 */ 88 public class Enhancer extends AbstractClassGenerator 89 { 90 private static final Source SOURCE = new Source(Enhancer.class.getName()); 91 private static final EnhancerKey KEY_FACTORY = 92 (EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.CLASS_BY_NAME); 93 94 interface EnhancerKey { 95 public Object newInstance(Class type, Class[] interfaces, CallbackFilter filter, boolean classOnly); 96 } 97 98 private Class[] interfaces; 99 private CallbackFilter filter; 100 private Callbacks callbacks; 101 private boolean classOnly; 102 private Class superclass; 103 private Class[] argumentTypes; 104 private Object[] arguments; 105 106 /*** 107 * Create a new <code>Enhancer</code>. A new <code>Enhancer</code> 108 * object should be used for each generated object, and should not 109 * be shared across threads. To create additional instances of a 110 * generated class, use the <code>Factory</code> interface. 111 * @see Factory 112 */ 113 public Enhancer() { 114 super(SOURCE); 115 } 116 117 /*** 118 * Set the class which the generated class will extend. As a convenience, 119 * if the supplied superclass is actually an interface, <code>setInterfaces</code> 120 * will be called with the appropriate argument instead. 121 * Non-interfaces arguments must not be declared as final, and must have an 122 * accessible constructor. 123 * @param superclass class to extend or interface to implement 124 * @see #setInterfaces(Class[]) 125 */ 126 public void setSuperclass(Class superclass) { 127 if (superclass != null && superclass.isInterface()) { 128 setInterfaces(new Class[]{ superclass }); 129 } else { 130 this.superclass = superclass; 131 } 132 } 133 134 /*** 135 * Set the interfaces to implement. The <code>Factory</code> interface will 136 * always be implemented regardless of what is specified here. 137 * @param interfaces array of interfaces to implement, or null 138 * @see Factory 139 */ 140 public void setInterfaces(Class[] interfaces) { 141 this.interfaces = interfaces; 142 } 143 144 /*** 145 * Set the <code>CallbackFilter</code> used to map the generated class' methods 146 * to a particular callback type. See the <code>Callbacks</code> interface for a 147 * description of the various callback types. 148 * New object instances will always use the same mapping, but may use different 149 * actual callback objects. 150 * @param filter the callback filter to use when generating a new class 151 * @see Callbacks 152 */ 153 public void setCallbackFilter(CallbackFilter filter) { 154 this.filter = filter; 155 } 156 157 /*** 158 * Set the single <code>Callback</code> to use. This will override any 159 * <code>CallbackFilter</code> that has been specified previously, and 160 * ensure that every applicable method is mapped to the given callback 161 * object. 162 * Ignored if you use <code>createClass</code>. 163 * @param callback the callback to use for all methods 164 * @see #setCallbackFilter 165 * @see #setCallbacks 166 * @see #createClass 167 */ 168 public void setCallback(final Callback callback) { 169 setCallbacks(new Callbacks() { 170 public Callback get(int type) { 171 return callback; 172 } 173 }); 174 setCallbackFilter(new SimpleFilter(CallbackUtils.determineType(callback))); 175 } 176 177 /*** 178 * Register the callbacks to use when creating the new object 179 * instance. For each callback type (see {@link Callbacks}) 180 * returned by the registered <code>CallbackFilter</code>, the 181 * <code>Callbacks</code> argument should return a non-null 182 * <code>Callback</code> implementation (where applicable--for 183 * instance the {@link Callbacks#NO_OP} type does not have an 184 * associated implementation). 185 * Ignored if you use <code>createClass</code>. 186 * @param callbacks callback implementations to use for the enhanced object 187 * @see SimpleCallbacks 188 * @see #setCallbackFilter 189 * @see #createClass 190 */ 191 public void setCallbacks(Callbacks callbacks) { 192 this.callbacks = callbacks; 193 } 194 195 /*** 196 * Generate a new class if necessary and uses the specified 197 * callbacks (if any) to create a new object instance. 198 * Uses the no-arg constructor of the superclass. 199 * @return a new instance 200 */ 201 public Factory create() { 202 classOnly = false; 203 argumentTypes = null; 204 return (Factory)createHelper(); 205 } 206 207 /*** 208 * Generate a new class if necessary and uses the specified 209 * callbacks (if any) to create a new object instance. 210 * Uses the constructor of the superclass matching the <code>argumentTypes</code> 211 * parameter, with the given arguments. 212 * @param argumentTypes constructor signature 213 * @param arguments compatible wrapped arguments to pass to constructor 214 * @return a new instance 215 */ 216 public Factory create(Class[] argumentTypes, Object[] arguments) { 217 classOnly = false; 218 if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) { 219 throw new IllegalArgumentException("Arguments must be non-null and of equal length"); 220 } 221 this.argumentTypes = argumentTypes; 222 this.arguments = arguments; 223 return (Factory)createHelper(); 224 } 225 226 /*** 227 * Generate a new class if necessary and return it without creating a new instance. 228 * This ignores any callbacks that have been set. 229 * To create a new instance you will have to use reflection, and methods 230 * called during the constructor will not be intercepted. To avoid this problem, 231 * use the multi-arg <code>create</code> method. 232 * @see #create(Class[], Object[]) 233 */ 234 public Class createClass() { 235 classOnly = true; 236 return (Class)createHelper(); 237 } 238 239 private Object createHelper() { 240 if (superclass != null) { 241 setNamePrefix(superclass.getName()); 242 } else if (interfaces != null) { 243 setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); 244 } 245 Object key = KEY_FACTORY.newInstance(superclass, interfaces, filter, classOnly); 246 return super.create(key); 247 } 248 249 protected ClassLoader getDefaultClassLoader() { 250 if (superclass != null) { 251 return superclass.getClassLoader(); 252 } else if (interfaces != null) { 253 return interfaces[0].getClassLoader(); 254 } else { 255 return null; 256 } 257 } 258 259 public void generateClass(ClassVisitor v) throws Exception { 260 new EnhancerEmitter(v, getClassName(), superclass, interfaces, filter); 261 } 262 263 protected Object firstInstance(Class type) throws Exception { 264 if (classOnly) { 265 return type; 266 } 267 268 ////// this is a hack ////// 269 Method setter = type.getDeclaredMethod("CGLIB$SET_THREAD_CALLBACKS", new Class[]{ Callbacks.class }); 270 setter.invoke(null, new Object[]{ callbacks }); 271 //////////////////////////// 272 273 Factory instance; 274 if (argumentTypes != null) { 275 instance = (Factory)ReflectUtils.newInstance(type, argumentTypes, arguments); 276 } else { 277 instance = (Factory)ReflectUtils.newInstance(type); 278 } 279 instance.setCallbacks(callbacks); 280 return instance; 281 } 282 283 protected Object nextInstance(Object instance) { 284 return classOnly ? instance : ((Factory)instance).newInstance(callbacks); 285 } 286 287 /*** 288 * Helper method to create an intercepted object. 289 * For finer control over the generated instance, use a new instance of Enhancer 290 * instead of this static method. 291 * @param type class to extend or interface to implement 292 * @param callback the callback to use for all methods 293 */ 294 public static Factory create(Class type, Callback callback) { 295 Enhancer e = new Enhancer(); 296 e.setSuperclass(type); 297 e.setCallback(callback); 298 return e.create(); 299 } 300 301 /*** 302 * Helper method to create an intercepted object. 303 * For finer control over the generated instance, use a new instance of Enhancer 304 * instead of this static method. 305 * @param type class to extend or interface to implement 306 * @param interfaces array of interfaces to implement, or null 307 * @param callback the callback to use for all methods 308 */ 309 public static Factory create(Class superclass, Class interfaces[], Callback callback) { 310 Enhancer e = new Enhancer(); 311 e.setSuperclass(superclass); 312 e.setInterfaces(interfaces); 313 e.setCallback(callback); 314 return e.create(); 315 } 316 317 /*** 318 * Helper method to create an intercepted object. 319 * For finer control over the generated instance, use a new instance of Enhancer 320 * instead of this static method. 321 * @param type class to extend or interface to implement 322 * @param interfaces array of interfaces to implement, or null 323 * @param filter the callback filter to use when generating a new class 324 * @param callbacks callback implementations to use for the enhanced object 325 */ 326 public static Factory create(Class superclass, Class[] interfaces, CallbackFilter filter, Callbacks callbacks) { 327 Enhancer e = new Enhancer(); 328 e.setSuperclass(superclass); 329 e.setInterfaces(interfaces); 330 e.setCallbackFilter(filter); 331 e.setCallbacks(callbacks); 332 return e.create(); 333 } 334 }

This page was automatically generated by Maven