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