1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/*
2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2002,2003,2004 The Apache Software Foundation
3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Licensed under the Apache License, Version 2.0 (the "License");
5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License.
6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at
7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *      http://www.apache.org/licenses/LICENSE-2.0
9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Unless required by applicable law or agreed to in writing, software
11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS,
12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and
14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License.
15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.proxy;
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.InvocationTargetException;
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.Method;
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*;
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor;
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Label;
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type;
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*;
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/**
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Generates dynamic subclasses to enable method interception. This
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * class started as a substitute for the standard Dynamic Proxy support
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * included with JDK 1.3, but one that allowed the proxies to extend a
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * concrete base class, in addition to implementing interfaces. The dynamically
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * generated subclasses override the non-final methods of the superclass and
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * have hooks which callback to user-defined interceptor
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * implementations.
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <p>
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * The original and most general callback type is the {@link MethodInterceptor}, which
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * in AOP terms enables "around advice"--that is, you can invoke custom code both before
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * and after the invocation of the "super" method. In addition you can modify the
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * arguments before calling the super method, or not call it at all.
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <p>
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Although <code>MethodInterceptor</code> is generic enough to meet any
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * interception need, it is often overkill. For simplicity and performance, additional
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * specialized callback types, such as {@link LazyLoader} are also available.
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Often a single callback will be used per enhanced class, but you can control
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * which callback is used on a per-method basis with a {@link CallbackFilter}.
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <p>
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * The most common uses of this class are embodied in the static helper methods. For
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * advanced needs, such as customizing the <code>ClassLoader</code> to use, you should create
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * a new instance of <code>Enhancer</code>. Other classes within CGLIB follow a similar pattern.
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <p>
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * All enhanced objects implement the {@link Factory} interface, unless {@link #setUseFactory} is
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * used to explicitly disable this feature. The <code>Factory</code> interface provides an API
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * to change the callbacks of an existing object, as well as a faster and easier way to create
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * new instances of the same type.
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <p>
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * For an almost drop-in replacement for
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <code>java.lang.reflect.Proxy</code>, see the {@link Proxy} class.
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpublic class Enhancer extends AbstractClassGenerator
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen{
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final CallbackFilter ALL_ZERO = new CallbackFilter(){
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public int accept(Method method, List<Method> allMethods) {
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return 0;
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    };
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Source SOURCE = new Source(Enhancer.class.getName());
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final EnhancerKey KEY_FACTORY =
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      (EnhancerKey)KeyFactory.create(EnhancerKey.class);
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String BOUND_FIELD = "CGLIB$BOUND";
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String THREAD_CALLBACKS_FIELD = "CGLIB$THREAD_CALLBACKS";
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String STATIC_CALLBACKS_FIELD = "CGLIB$STATIC_CALLBACKS";
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS";
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String SET_STATIC_CALLBACKS_NAME = "CGLIB$SET_STATIC_CALLBACKS";
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED";
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type FACTORY =
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("org.mockito.cglib.proxy.Factory");
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type ILLEGAL_STATE_EXCEPTION =
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("IllegalStateException");
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("IllegalArgumentException");
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type THREAD_LOCAL =
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("ThreadLocal");
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type CALLBACK =
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("org.mockito.cglib.proxy.Callback");
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type CALLBACK_ARRAY =
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      Type.getType(Callback[].class);
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature CSTRUCT_NULL =
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseConstructor("");
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SET_THREAD_CALLBACKS =
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature(SET_THREAD_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SET_STATIC_CALLBACKS =
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature(SET_STATIC_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature NEW_INSTANCE =
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK_ARRAY });
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature MULTIARG_NEW_INSTANCE =
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen          Constants.TYPE_CLASS_ARRAY,
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen          Constants.TYPE_OBJECT_ARRAY,
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen          CALLBACK_ARRAY,
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      });
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SINGLE_NEW_INSTANCE =
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK });
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SET_CALLBACK =
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("setCallback", Type.VOID_TYPE, new Type[]{ Type.INT_TYPE, CALLBACK });
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature GET_CALLBACK =
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("getCallback", CALLBACK, new Type[]{ Type.INT_TYPE });
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SET_CALLBACKS =
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("setCallbacks", Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY });
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature GET_CALLBACKS =
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("getCallbacks", CALLBACK_ARRAY, new Type[0]);
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature THREAD_LOCAL_GET =
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("Object get()");
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature THREAD_LOCAL_SET =
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("void set(Object)");
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature BIND_CALLBACKS =
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("void CGLIB$BIND_CALLBACKS(Object)");
120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /** Internal interface, only public due to ClassLoader issues. */
122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public interface EnhancerKey {
123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Object newInstance(String type,
124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  String[] interfaces,
125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  CallbackFilter filter,
126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  Type[] callbackTypes,
127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  boolean useFactory,
128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  boolean interceptDuringConstruction,
129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                  Long serialVersionUID);
130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Class[] interfaces;
133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private CallbackFilter filter;
134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Callback[] callbacks;
135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Type[] callbackTypes;
136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private boolean classOnly;
137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Class superclass;
138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Class[] argumentTypes;
139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Object[] arguments;
140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private boolean useFactory = true;
141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Long serialVersionUID;
142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private boolean interceptDuringConstruction = true;
143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Create a new <code>Enhancer</code>. A new <code>Enhancer</code>
146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * object should be used for each generated object, and should not
147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * be shared across threads. To create additional instances of a
148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * generated class, use the <code>Factory</code> interface.
149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see Factory
150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Enhancer() {
152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        super(SOURCE);
153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the class which the generated class will extend. As a convenience,
157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * if the supplied superclass is actually an interface, <code>setInterfaces</code>
158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * will be called with the appropriate argument instead.
159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * A non-interface argument must not be declared as final, and must have an
160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * accessible constructor.
161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param superclass class to extend or interface to implement
162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setInterfaces(Class[])
163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setSuperclass(Class superclass) {
165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (superclass != null && superclass.isInterface()) {
166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setInterfaces(new Class[]{ superclass });
167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (superclass != null && superclass.equals(Object.class)) {
168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // affects choice of ClassLoader
169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.superclass = null;
170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.superclass = superclass;
172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the interfaces to implement. The <code>Factory</code> interface will
177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * always be implemented regardless of what is specified here.
178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interfaces array of interfaces to implement, or null
179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see Factory
180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setInterfaces(Class[] interfaces) {
182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.interfaces = interfaces;
183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the {@link CallbackFilter} used to map the generated class' methods
187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * to a particular callback index.
188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * New object instances will always use the same mapping, but may use different
189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * actual callback objects.
190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param filter the callback filter to use when generating a new class
191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setCallbacks
192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setCallbackFilter(CallbackFilter filter) {
194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.filter = filter;
195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the single {@link Callback} to use.
200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Ignored if you use {@link #createClass}.
201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callback the callback to use for all methods
202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setCallbacks
203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setCallback(final Callback callback) {
205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setCallbacks(new Callback[]{ callback });
206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the array of callbacks to use.
210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Ignored if you use {@link #createClass}.
211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * You must use a {@link CallbackFilter} to specify the index into this
212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * array for each method in the proxied class.
213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbacks the callback array
214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setCallbackFilter
215674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setCallback
216674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
217674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setCallbacks(Callback[] callbacks) {
218674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (callbacks != null && callbacks.length == 0) {
219674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("Array cannot be empty");
220674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
221674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.callbacks = callbacks;
222674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
223674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
224674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
225674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set whether the enhanced object instances should implement
226674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * the {@link Factory} interface.
227674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * This was added for tools that need for proxies to be more
228674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * indistinguishable from their targets. Also, in some cases it may
229674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * be necessary to disable the <code>Factory</code> interface to
230674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * prevent code from changing the underlying callbacks.
231674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param useFactory whether to implement <code>Factory</code>; default is <code>true</code>
232674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
233674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setUseFactory(boolean useFactory) {
234674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.useFactory = useFactory;
235674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
236674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
237674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
238674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set whether methods called from within the proxy's constructer
239674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * will be intercepted. The default value is true. Unintercepted methods
240674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * will call the method of the proxy's base class, if it exists.
241674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interceptDuringConstruction whether to intercept methods called from the constructor
242674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
243674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setInterceptDuringConstruction(boolean interceptDuringConstruction) {
244674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.interceptDuringConstruction = interceptDuringConstruction;
245674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
246674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
247674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
248674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the single type of {@link Callback} to use.
249674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * This may be used instead of {@link #setCallback} when calling
250674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * {@link #createClass}, since it may not be possible to have
251674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * an array of actual callback instances.
252674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbackType the type of callback to use for all methods
253674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setCallbackTypes
254674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
255674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setCallbackType(Class callbackType) {
256674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setCallbackTypes(new Class[]{ callbackType });
257674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
258674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
259674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
260674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Set the array of callback types to use.
261674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * This may be used instead of {@link #setCallbacks} when calling
262674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * {@link #createClass}, since it may not be possible to have
263674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * an array of actual callback instances.
264674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * You must use a {@link CallbackFilter} to specify the index into this
265674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * array for each method in the proxied class.
266674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbackTypes the array of callback types
267674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
268674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setCallbackTypes(Class[] callbackTypes) {
269674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (callbackTypes != null && callbackTypes.length == 0) {
270674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("Array cannot be empty");
271674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
272674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.callbackTypes = CallbackInfo.determineTypes(callbackTypes);
273674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
274674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
275674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
276674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Generate a new class if necessary and uses the specified
277674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * callbacks (if any) to create a new object instance.
278674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Uses the no-arg constructor of the superclass.
279674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return a new instance
280674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
281674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Object create() {
282674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        classOnly = false;
283674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        argumentTypes = null;
284674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return createHelper();
285674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
286674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
287674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
288674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Generate a new class if necessary and uses the specified
289674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * callbacks (if any) to create a new object instance.
290674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Uses the constructor of the superclass matching the <code>argumentTypes</code>
291674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * parameter, with the given arguments.
292674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param argumentTypes constructor signature
293674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param arguments compatible wrapped arguments to pass to constructor
294674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return a new instance
295674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
296674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Object create(Class[] argumentTypes, Object[] arguments) {
297674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        classOnly = false;
298674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) {
299674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("Arguments must be non-null and of equal length");
300674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
301674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.argumentTypes = argumentTypes;
302674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.arguments = arguments;
303674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return createHelper();
304674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
305674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
306674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
307674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Generate a new class if necessary and return it without creating a new instance.
308674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * This ignores any callbacks that have been set.
309674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * To create a new instance you will have to use reflection, and methods
310674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * called during the constructor will not be intercepted. To avoid this problem,
311674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * use the multi-arg <code>create</code> method.
312674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #create(Class[], Object[])
313674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
314674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public Class createClass() {
315674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        classOnly = true;
316674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return (Class)createHelper();
317674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
318674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
319674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
320674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Insert a static serialVersionUID field into the generated class.
321674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param sUID the field value, or null to avoid generating field.
322674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
323674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void setSerialVersionUID(Long sUID) {
324674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        serialVersionUID = sUID;
325674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
326674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
327674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void validate() {
328674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (classOnly ^ (callbacks == null)) {
329674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (classOnly) {
330674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalStateException("createClass does not accept callbacks");
331674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
332674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalStateException("Callbacks are required");
333674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
334674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
335674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (classOnly && (callbackTypes == null)) {
336674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalStateException("Callback types are required");
337674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
338674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (callbacks != null && callbackTypes != null) {
339674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (callbacks.length != callbackTypes.length) {
340674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalStateException("Lengths of callback and callback types array must be the same");
341674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
342674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Type[] check = CallbackInfo.determineTypes(callbacks);
343674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < check.length; i++) {
344674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (!check[i].equals(callbackTypes[i])) {
345674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    throw new IllegalStateException("Callback " + check[i] + " is not assignable to " + callbackTypes[i]);
346674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
347674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
348674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (callbacks != null) {
349674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            callbackTypes = CallbackInfo.determineTypes(callbacks);
350674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
351674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (filter == null) {
352674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (callbackTypes.length > 1) {
353674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalStateException("Multiple callback types possible but no filter specified");
354674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
355674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            filter = ALL_ZERO;
356674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
357674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (interfaces != null) {
358674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < interfaces.length; i++) {
359674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (interfaces[i] == null) {
360674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    throw new IllegalStateException("Interfaces cannot be null");
361674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
362674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (!interfaces[i].isInterface()) {
363674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    throw new IllegalStateException(interfaces[i] + " is not an interface");
364674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
365674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
366674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
367674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
368674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
369674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Object createHelper() {
370674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        validate();
371674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (superclass != null) {
372674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setNamePrefix(superclass.getName());
373674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (interfaces != null) {
374674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
375674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
376674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
377674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    ReflectUtils.getNames(interfaces),
378674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    filter,
379674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    callbackTypes,
380674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    useFactory,
381674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    interceptDuringConstruction,
382674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                                    serialVersionUID));
383674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
384674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
385674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected ClassLoader getDefaultClassLoader() {
386674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (superclass != null) {
387674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return superclass.getClassLoader();
388674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (interfaces != null) {
389674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return interfaces[0].getClassLoader();
390674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
391674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return null;
392674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
393674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
394674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
395674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Signature rename(Signature sig, int index) {
396674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Signature("CGLIB$" + sig.getName() + "$" + index,
397674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                             sig.getDescriptor());
398674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
399674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
400674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
401674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Finds all of the methods that will be extended by an
402674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Enhancer-generated class using the specified superclass and
403674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * interfaces. This can be useful in building a list of Callback
404674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * objects. The methods are added to the end of the given list.  Due
405674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * to the subclassing nature of the classes generated by Enhancer,
406674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * the methods are guaranteed to be non-static, non-final, and
407674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * non-private. Each method signature will only occur once, even if
408674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * it occurs in multiple classes.
409674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param superclass the class that will be extended, or null
410674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interfaces the list of interfaces that will be implemented, or null
411674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param methods the list into which to copy the applicable methods
412674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
413674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void getMethods(Class superclass, Class[] interfaces, List methods)
414674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
415674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        getMethods(superclass, interfaces, methods, null, null);
416674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
417674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
418674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic)
419674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
420674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        ReflectUtils.addAllMethods(superclass, methods);
421674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List target = (interfaceMethods != null) ? interfaceMethods : methods;
422674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (interfaces != null) {
423674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < interfaces.length; i++) {
424674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (interfaces[i] != Factory.class) {
425674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    ReflectUtils.addAllMethods(interfaces[i], target);
426674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
427674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
428674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
429674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (interfaceMethods != null) {
430674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (forcePublic != null) {
431674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
432674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
433674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            methods.addAll(interfaceMethods);
434674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
435674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_STATIC));
436674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
437674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CollectionUtils.filter(methods, new DuplicatesPredicate());
438674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_FINAL));
439674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
440674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
441674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void generateClass(ClassVisitor v) throws Exception {
442674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Class sc = (superclass == null) ? Object.class : superclass;
443674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
444674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (TypeUtils.isFinal(sc.getModifiers()))
445674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("Cannot subclass final class " + sc);
446674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
447674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        filterConstructors(sc, constructors);
448674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
449674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // Order is very important: must add superclass, then
450674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // its superclass chain, then each interface and
451674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // its superinterfaces.
452674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List actualMethods = new ArrayList();
453674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List interfaceMethods = new ArrayList();
454674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Set forcePublic = new HashSet();
455674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);
456674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
457674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List methods = CollectionUtils.transform(actualMethods, new Transformer() {
458674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Object transform(Object value) {
459674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Method method = (Method)value;
460674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                int modifiers = Constants.ACC_FINAL
461674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    | (method.getModifiers()
462674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                       & ~Constants.ACC_ABSTRACT
463674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                       & ~Constants.ACC_NATIVE
464674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                       & ~Constants.ACC_SYNCHRONIZED);
465674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (forcePublic.contains(MethodWrapper.create(method))) {
466674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
467674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
468674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return ReflectUtils.getMethodInfo(method, modifiers);
469674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
470674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
471674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
472674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        ClassEmitter e = new ClassEmitter(v);
473674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.begin_class(Constants.V1_2,
474674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                      Constants.ACC_PUBLIC,
475674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                      getClassName(),
476674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                      Type.getType(sc),
477674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                      (useFactory ?
478674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                       TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
479674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                       TypeUtils.getTypes(interfaces)),
480674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                      Constants.SOURCE_FILE);
481674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
482674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
483674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
484674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!interceptDuringConstruction) {
485674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
486674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
487674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
488674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
489674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (serialVersionUID != null) {
490674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
491674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
492674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
493674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < callbackTypes.length; i++) {
494674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
495674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
496674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
497674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitMethods(e, methods, actualMethods);
498674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitConstructors(e, constructorInfo);
499674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitSetThreadCallbacks(e);
500674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitSetStaticCallbacks(e);
501674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitBindCallbacks(e);
502674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
503674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (useFactory) {
504674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int[] keys = getCallbackKeys();
505674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitNewInstanceCallbacks(e);
506674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitNewInstanceCallback(e);
507674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitNewInstanceMultiarg(e, constructorInfo);
508674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitGetCallback(e, keys);
509674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitSetCallback(e, keys);
510674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitGetCallbacks(e);
511674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            emitSetCallbacks(e);
512674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
513674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
514674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_class();
515674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
516674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
517674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
518674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Filter the list of constructors from the superclass. The
519674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * constructors which remain will be included in the generated
520674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * class. The default implementation is to filter out all private
521674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * constructors, but subclasses may extend Enhancer to override this
522674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * behavior.
523674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param sc the superclass
524674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param constructors the list of all declared constructors from the superclass
525674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @throws IllegalArgumentException if there are no non-private constructors
526674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
527674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected void filterConstructors(Class sc, List constructors) {
528674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CollectionUtils.filter(constructors, new VisibilityPredicate(sc, true));
529674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (constructors.size() == 0)
530674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("No visible constructors in " + sc);
531674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
532674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
533674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected Object firstInstance(Class type) throws Exception {
534674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (classOnly) {
535674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return type;
536674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
537674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return createUsingReflection(type);
538674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
539674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
540674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
541674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected Object nextInstance(Object instance) {
542674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
543674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (classOnly) {
544674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return protoclass;
545674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (instance instanceof Factory) {
546674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (argumentTypes != null) {
547674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return ((Factory)instance).newInstance(argumentTypes, arguments, callbacks);
548674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
549674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return ((Factory)instance).newInstance(callbacks);
550674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
551674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
552674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return createUsingReflection(protoclass);
553674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
554674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
555674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
556674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
557674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Call this method to register the {@link Callback} array to use before
558674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * creating a new instance of the generated class via reflection. If you are using
559674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * an instance of <code>Enhancer</code> or the {@link Factory} interface to create
560674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * new instances, this method is unnecessary. Its primary use is for when you want to
561674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * cache and reuse a generated class yourself, and the generated class does
562674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * <i>not</i> implement the {@link Factory} interface.
563674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * <p>
564674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Note that this method only registers the callbacks on the current thread.
565674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * If you want to register callbacks for instances created by multiple threads,
566674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * use {@link #registerStaticCallbacks}.
567674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * <p>
568674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * The registered callbacks are overwritten and subsequently cleared
569674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * when calling any of the <code>create</code> methods (such as
570674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * {@link #create}), or any {@link Factory} <code>newInstance</code> method.
571674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Otherwise they are <i>not</i> cleared, and you should be careful to set them
572674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * back to <code>null</code> after creating new instances via reflection if
573674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * memory leakage is a concern.
574674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param generatedClass a class previously created by {@link Enhancer}
575674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbacks the array of callbacks to use when instances of the generated
576674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * class are created
577674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @see #setUseFactory
578674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
579674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void registerCallbacks(Class generatedClass, Callback[] callbacks) {
580674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setThreadCallbacks(generatedClass, callbacks);
581674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
582674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
583674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
584674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Similar to {@link #registerCallbacks}, but suitable for use
585674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * when multiple threads will be creating instances of the generated class.
586674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * The thread-level callbacks will always override the static callbacks.
587674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Static callbacks are never cleared.
588674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param generatedClass a class previously created by {@link Enhancer}
589674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbacks the array of callbacks to use when instances of the generated
590674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * class are created
591674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
592674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) {
593674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setCallbacksHelper(generatedClass, callbacks, SET_STATIC_CALLBACKS_NAME);
594674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
595674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
596674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
597674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Determine if a class was generated using <code>Enhancer</code>.
598674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type any class
599674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @return whether the class was generated  using <code>Enhancer</code>
600674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
601674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static boolean isEnhanced(Class type) {
602674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        try {
603674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            getCallbacksSetter(type, SET_THREAD_CALLBACKS_NAME);
604674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return true;
605674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (NoSuchMethodException e) {
606674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return false;
607674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
608674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
609674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
610674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void setThreadCallbacks(Class type, Callback[] callbacks) {
611674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME);
612674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
613674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
614674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
615674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // TODO: optimize
616674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        try {
617674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Method setter = getCallbacksSetter(type, methodName);
618674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setter.invoke(null, new Object[]{ callbacks });
619674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (NoSuchMethodException e) {
620674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException(type + " is not an enhanced class");
621674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (IllegalAccessException e) {
622674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new CodeGenerationException(e);
623674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (InvocationTargetException e) {
624674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new CodeGenerationException(e);
625674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
626674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
627674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
628674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
629674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return type.getDeclaredMethod(methodName, new Class[]{ Callback[].class });
630674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
631674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
632674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private Object createUsingReflection(Class type) {
633674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        setThreadCallbacks(type, callbacks);
634674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        try{
635674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
636674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (argumentTypes != null) {
637674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
638674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen             return ReflectUtils.newInstance(type, argumentTypes, arguments);
639674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
640674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
641674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
642674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return ReflectUtils.newInstance(type);
643674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
644674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
645674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }finally{
646674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         // clear thread callbacks to allow them to be gc'd
647674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         setThreadCallbacks(type, null);
648674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
649674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
650674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
651674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
652674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create an intercepted object.
653674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
654674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
655674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type class to extend or interface to implement
656674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callback the callback to use for all methods
657674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
658674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Object create(Class type, Callback callback) {
659674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Enhancer e = new Enhancer();
660674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setSuperclass(type);
661674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setCallback(callback);
662674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return e.create();
663674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
664674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
665674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
666674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create an intercepted object.
667674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
668674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
669674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type class to extend or interface to implement
670674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interfaces array of interfaces to implement, or null
671674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callback the callback to use for all methods
672674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
673674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Object create(Class superclass, Class interfaces[], Callback callback) {
674674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Enhancer e = new Enhancer();
675674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setSuperclass(superclass);
676674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setInterfaces(interfaces);
677674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setCallback(callback);
678674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return e.create();
679674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
680674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
681674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
682674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create an intercepted object.
683674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
684674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
685674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type class to extend or interface to implement
686674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param interfaces array of interfaces to implement, or null
687674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param filter the callback filter to use when generating a new class
688674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callbacks callback implementations to use for the enhanced object
689674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
690674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
691674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Enhancer e = new Enhancer();
692674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setSuperclass(superclass);
693674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setInterfaces(interfaces);
694674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setCallbackFilter(filter);
695674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.setCallbacks(callbacks);
696674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return e.create();
697674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
698674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
699674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitConstructors(ClassEmitter ce, List constructors) {
700674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        boolean seenNull = false;
701674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (Iterator it = constructors.iterator(); it.hasNext();) {
702674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            MethodInfo constructor = (MethodInfo)it.next();
703674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC);
704674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_this();
705674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
706674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_args();
707674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Signature sig = constructor.getSignature();
708674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            seenNull = seenNull || sig.getDescriptor().equals("()V");
709674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.super_invoke_constructor(sig);
710674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_static_this(BIND_CALLBACKS);
711674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (!interceptDuringConstruction) {
712674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.load_this();
713674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(1);
714674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.putfield(CONSTRUCTED_FIELD);
715674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
716674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.return_value();
717674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.end_method();
718674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
719674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!classOnly && !seenNull && arguments == null)
720674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new IllegalArgumentException("Superclass has no null constructors but no arguments were given");
721674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
722674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
723674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private int[] getCallbackKeys() {
724674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        int[] keys = new int[callbackTypes.length];
725674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < callbackTypes.length; i++) {
726674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            keys[i] = i;
727674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
728674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return keys;
729674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
730674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
731674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitGetCallback(ClassEmitter ce, int[] keys) {
732674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null);
733674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
734674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(BIND_CALLBACKS);
735674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
736674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
737674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(keys, new ProcessSwitchCallback() {
738674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processCase(int key, Label end) {
739674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.getfield(getCallbackField(key));
740674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(end);
741674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
742674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processDefault() {
743674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.pop(); // stack height
744674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.aconst_null();
745674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
746674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
747674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
748674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
749674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
750674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
751674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitSetCallback(ClassEmitter ce, int[] keys) {
752674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null);
753674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
754674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(keys, new ProcessSwitchCallback() {
755674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processCase(int key, Label end) {
756674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.load_this();
757674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.load_arg(1);
758674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.checkcast(callbackTypes[key]);
759674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.putfield(getCallbackField(key));
760674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(end);
761674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
762674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processDefault() {
763674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                // TODO: error?
764674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
765674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
766674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
767674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
768674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
769674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
770674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitSetCallbacks(ClassEmitter ce) {
771674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null);
772674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
773674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
774674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < callbackTypes.length; i++) {
775674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup2();
776674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aaload(i);
777674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.checkcast(callbackTypes[i]);
778674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.putfield(getCallbackField(i));
779674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
780674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
781674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
782674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
783674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
784674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitGetCallbacks(ClassEmitter ce) {
785674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACKS, null);
786674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
787674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(BIND_CALLBACKS);
788674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
789674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(callbackTypes.length);
790674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.newarray(CALLBACK);
791674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < callbackTypes.length; i++) {
792674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
793674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(i);
794674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_this();
795674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.getfield(getCallbackField(i));
796674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aastore();
797674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
798674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
799674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
800674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
801674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
802674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitNewInstanceCallbacks(ClassEmitter ce) {
803674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
804674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
805674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(SET_THREAD_CALLBACKS);
806674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitCommonNewInstance(e);
807674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
808674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
809674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitCommonNewInstance(CodeEmitter e) {
810674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance_this();
811674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
812674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_constructor_this();
813674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.aconst_null();
814674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(SET_THREAD_CALLBACKS);
815674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
816674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
817674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
818674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
819674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitNewInstanceCallback(ClassEmitter ce) {
820674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null);
821674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        switch (callbackTypes.length) {
822674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case 0:
823674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // TODO: make sure Callback is null
824674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            break;
825674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case 1:
826674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // for now just make a new array; TODO: optimize
827674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(1);
828674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.newarray(CALLBACK);
829674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
830674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(0);
831674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_arg(0);
832674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aastore();
833674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_static_this(SET_THREAD_CALLBACKS);
834674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            break;
835674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        default:
836674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required");
837674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
838674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        emitCommonNewInstance(e);
839674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
840674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
841674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitNewInstanceMultiarg(ClassEmitter ce, List constructors) {
842674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null);
843674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(2);
844674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(SET_THREAD_CALLBACKS);
845674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance_this();
846674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
847674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
848674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        EmitUtils.constructor_switch(e, constructors, new ObjectSwitchCallback() {
849674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processCase(Object key, Label end) {
850674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                MethodInfo constructor = (MethodInfo)key;
851674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Type types[] = constructor.getSignature().getArgumentTypes();
852674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                for (int i = 0; i < types.length; i++) {
853674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.load_arg(1);
854674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.push(i);
855674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.aaload();
856674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.unbox(types[i]);
857674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
858674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_constructor_this(constructor.getSignature());
859674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(end);
860674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
861674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processDefault() {
862674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found");
863674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
864674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
865674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.aconst_null();
866674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(SET_THREAD_CALLBACKS);
867674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
868674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
869674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
870674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
871674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) {
872674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes);
873674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
874674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Map groups = new HashMap();
875674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map indexes = new HashMap();
876674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map originalModifiers = new HashMap();
877674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map positions = CollectionUtils.getIndexMap(methods);
878674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
879674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Iterator it1 = methods.iterator();
880674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Iterator it2 = (actualMethods != null) ? actualMethods.iterator() : null;
881674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
882674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        while (it1.hasNext()) {
883674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            MethodInfo method = (MethodInfo)it1.next();
884674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Method actualMethod = (it2 != null) ? (Method)it2.next() : null;
885674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int index = filter.accept(actualMethod, actualMethods);
886674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (index >= callbackTypes.length) {
887674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
888674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
889674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            originalModifiers.put(method, new Integer((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers()));
890674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            indexes.put(method, new Integer(index));
891674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            List group = (List)groups.get(generators[index]);
892674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (group == null) {
893674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                groups.put(generators[index], group = new ArrayList(methods.size()));
894674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
895674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            group.add(method);
896674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
897674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
898674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Set seenGen = new HashSet();
899674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter se = ce.getStaticHook();
900674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.new_instance(THREAD_LOCAL);
901674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.dup();
902674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL);
903674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.putfield(THREAD_CALLBACKS_FIELD);
904674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
905674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Object[] state = new Object[1];
906674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CallbackGenerator.Context context = new CallbackGenerator.Context() {
907674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public ClassLoader getClassLoader() {
908674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return Enhancer.this.getClassLoader();
909674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
910674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public int getOriginalModifiers(MethodInfo method) {
911674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return ((Integer)originalModifiers.get(method)).intValue();
912674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
913674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public int getIndex(MethodInfo method) {
914674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return ((Integer)indexes.get(method)).intValue();
915674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
916674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void emitCallback(CodeEmitter e, int index) {
917674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                emitCurrentCallback(e, index);
918674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
919674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Signature getImplSignature(MethodInfo method) {
920674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return rename(method.getSignature(), ((Integer)positions.get(method)).intValue());
921674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
922674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method) {
923674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                CodeEmitter e = EmitUtils.begin_method(ce, method);
924674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (!interceptDuringConstruction &&
925674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    !TypeUtils.isAbstract(method.getModifiers())) {
926674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    Label constructed = e.make_label();
927674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.load_this();
928674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.getfield(CONSTRUCTED_FIELD);
929674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.if_jump(e.NE, constructed);
930674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.load_this();
931674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.load_args();
932674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.super_invoke();
933674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.return_value();
934674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.mark(constructed);
935674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
936674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return e;
937674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
938674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        };
939674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < callbackTypes.length; i++) {
940674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            CallbackGenerator gen = generators[i];
941674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (!seenGen.contains(gen)) {
942674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                seenGen.add(gen);
943674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                final List fmethods = (List)groups.get(gen);
944674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (fmethods != null) {
945674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    try {
946674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        gen.generate(ce, context, fmethods);
947674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        gen.generateStatic(se, context, fmethods);
948674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } catch (RuntimeException x) {
949674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        throw x;
950674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } catch (Exception x) {
951674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        throw new CodeGenerationException(x);
952674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
953674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
954674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
955674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
956674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.return_value();
957674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        se.end_method();
958674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
959674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
960674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitSetThreadCallbacks(ClassEmitter ce) {
961674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
962674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        SET_THREAD_CALLBACKS,
963674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        null);
964674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(THREAD_CALLBACKS_FIELD);
965674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
966674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET);
967674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
968674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
969674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
970674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
971674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitSetStaticCallbacks(ClassEmitter ce) {
972674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
973674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        SET_STATIC_CALLBACKS,
974674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        null);
975674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
976674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.putfield(STATIC_CALLBACKS_FIELD);
977674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
978674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
979674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
980674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
981674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitCurrentCallback(CodeEmitter e, int index) {
982674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
983674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(getCallbackField(index));
984674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
985674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
986674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(end);
987674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop(); // stack height
988674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
989674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_static_this(BIND_CALLBACKS);
990674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
991674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(getCallbackField(index));
992674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
993674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
994674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
995674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void emitBindCallbacks(ClassEmitter ce) {
996674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.PRIVATE_FINAL_STATIC,
997674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        BIND_CALLBACKS,
998674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                        null);
999674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local me = e.make_local();
1000674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
1001674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.checkcast_this();
1002674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(me);
1003674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1004674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
1005674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(me);
1006674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(BOUND_FIELD);
1007674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.if_jump(e.NE, end);
1008674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(me);
1009674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(1);
1010674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.putfield(BOUND_FIELD);
1011674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1012674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(THREAD_CALLBACKS_FIELD);
1013674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET);
1014674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
1015674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label found_callback = e.make_label();
1016674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(found_callback);
1017674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
1018674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1019674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(STATIC_CALLBACKS_FIELD);
1020674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
1021674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(found_callback);
1022674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
1023674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(end);
1024674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1025674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(found_callback);
1026674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.checkcast(CALLBACK_ARRAY);
1027674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(me);
1028674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.swap();
1029674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = callbackTypes.length - 1; i >= 0; i--) {
1030674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (i != 0) {
1031674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.dup2();
1032674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
1033674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aaload(i);
1034674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.checkcast(callbackTypes[i]);
1035674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.putfield(getCallbackField(i));
1036674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
1037674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1038674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
1039674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
1040674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
1041674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
1042674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
1043674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static String getCallbackField(int index) {
1044674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return "CGLIB$CALLBACK_" + index;
1045674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
1046674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
1047