169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.util.proxy;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Field;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.InvocationTargetException;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Method;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Constructor;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Member;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Modifier;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.security.ProtectionDomain;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.*;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.ref.WeakReference;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CannotCompileException;
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.*;
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This class is implemented only with the lower-level API of Javassist.
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This design decision is for maximizing performance.
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Factory of dynamic proxy classes.
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>This factory generates a class that extends the given super class and implements
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the given interfaces.  The calls of the methods inherited from the super class are
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * forwarded and then <code>invoke()</code> is called on the method handler
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * associated with instances of the generated class.  The calls of the methods from
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the interfaces are also forwarded to the method handler.
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>For example, if the following code is executed,
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * ProxyFactory f = new ProxyFactory();
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * f.setSuperclass(Foo.class);
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * f.setFilter(new MethodFilter() {
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     public boolean isHandled(Method m) {
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *         // ignore finalize()
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *         return !m.getName().equals("finalize");
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     }
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * });
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Class c = f.createClass();
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * MethodHandler mi = new MethodHandler() {
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     public Object invoke(Object self, Method m, Method proceed,
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *                          Object[] args) throws Throwable {
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *         System.out.println("Name: " + m.getName());
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *         return proceed.invoke(self, args);  // execute the original method.
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     }
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * };
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Foo foo = (Foo)c.newInstance();
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * ((ProxyObject)foo).setHandler(mi);
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Then, the following method call will be forwarded to MethodHandler
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>mi</code> and prints a message before executing the originally called method
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>bar()</code> in <code>Foo</code>.
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * foo.bar();
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The last three lines of the code shown above can be replaced with a call to
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the helper method <code>create</code>, which generates a proxy class, instantiates
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * it, and sets the method handler of the instance:
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     :
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Foo foo = (Foo)f.create(new Class[0], new Object[0], mi);
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To change the method handler during runtime,
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * execute the following code:
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * MethodHandler mi = ... ;    // alternative handler
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * ((ProxyObject)foo).setHandler(mi);
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p> If setHandler is never called for a proxy instance then it will
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * employ the default handler which proceeds by invoking the original method.
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The behaviour of the default handler is identical to the following
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * handler:
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class EmptyHandler implements MethodHandler {
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     public Object invoke(Object self, Method m,
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *                          Method proceed, Object[] args) throws Exception {
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *         return proceed.invoke(self, args);
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *     }
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * }
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>A proxy factory caches and reuses proxy classes by default. It is possible to reset
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * this default globally by setting static field {@link ProxyFactory#useCache} to false.
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Caching may also be configured for a specific factory by calling instance method
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link ProxyFactory#setUseCache(boolean)}. It is strongly recommended that new clients
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * of class ProxyFactory enable caching. Failure to do so may lead to exhaustion of
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the heap memory area used to store classes.
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Caching is automatically disabled for any given proxy factory if deprecated instance
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * method {@link ProxyFactory#setHandler(MethodHandler)} is called. This method was
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * used to specify a default handler which newly created proxy classes should install
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * when they create their instances. It is only retained to provide backward compatibility
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with previous releases of javassist. Unfortunately,this legacy behaviour makes caching
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * and reuse of proxy classes impossible. The current programming model expects javassist
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * clients to set the handler of a proxy instance explicitly by calling method
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link ProxyObject#setHandler(MethodHandler)} as shown in the sample code above. New
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * clients are strongly recommended to use this model rather than calling
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link ProxyFactory#setHandler(MethodHandler)}.
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * if its super class or any of its interfaces implement <code>java.io.Serializable</code>.
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * However, a serialized proxy object may not be compatible with future releases.
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The serialization support should be used for short-term storage or RMI.
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>For compatibility with older releases serialization of proxy objects is implemented by
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * adding a writeReplace method to the proxy class. This allows a proxy to be serialized
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * to a conventional {@link java.io.ObjectOutputStream} and deserialized from a corresponding
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link java.io.ObjectInputStream}. However this method suffers from several problems, the most
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * notable one being that it fails to serialize state inherited from the proxy's superclass.
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * An alternative method of serializing proxy objects is available which fixes these problems. It
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * requires inhibiting generation of the writeReplace method and instead using instances of
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link javassist.util.proxy.ProxyObjectOutputStream} and {@link javassist.util.proxy.ProxyObjectInputStream}
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * (which are subclasses of {@link java.io.ObjectOutputStream} and  {@link java.io.ObjectInputStream})
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * to serialize and deserialize, respectively, the proxy. These streams recognise javassist proxies and ensure
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * that they are serialized and deserialized without the need for the proxy class to implement special methods
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * such as writeReplace. Generation of the writeReplace method can be disabled globally by setting static field
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link ProxyFactory#useWriteReplace} to false. Alternatively, it may be
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * configured per factory by calling instance method {@link ProxyFactory#setUseWriteReplace(boolean)}.
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see MethodHandler
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @since 3.1
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Muga Nishizawa
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Shigeru Chiba
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Andrew Dinn
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class ProxyFactory {
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class superClass;
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class[] interfaces;
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private MethodFilter methodFilter;
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private MethodHandler handler;  // retained for legacy usage
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private List signatureMethods;
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private byte[] signature;
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String classname;
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String basename;
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String superName;
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class thisClass;
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * per factory setting initialised from current setting for useCache but able to be reset before each create call
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean factoryUseCache;
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * per factory setting initialised from current setting for useWriteReplace but able to be reset before each create call
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean factoryWriteReplace;
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the value of this variable is not null, the class file of
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the generated proxy class is written under the directory specified
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * by this variable.  For example, if the value is
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>"."</code>, then the class file is written under the current
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * directory.  This method is for debugging.
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>The default value is null.
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String writeDirectory;
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final Class OBJECT_TYPE = Object.class;
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HOLDER = "_methods_";
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String FILTER_SIGNATURE_FIELD = "_filter_signature";
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String FILTER_SIGNATURE_TYPE = "[B";
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER = "handler";
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER_TYPE
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER_SETTER = "setHandler";
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER_GETTER = "getHandler";
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HANDLER_GETTER_TYPE = "()" + HANDLER_TYPE;
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID";
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String SERIAL_VERSION_UID_TYPE = "J";
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final int SERIAL_VERSION_UID_VALUE = -1;
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If true, a generated proxy class is cached and it will be reused
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * when generating the proxy class with the same properties is requested.
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The default value is true.
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Note that this value merely specifies the initial setting employed by any newly created
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * proxy factory. The factory setting may be overwritten by calling factory instance method
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * {@link #setUseCache(boolean)}
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static volatile boolean useCache = true;
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If true, a generated proxy class will implement method writeReplace enabling
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * serialization of its proxies to a conventional ObjectOutputStream. this (default)
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * setting retains the old javassist behaviour which has the advantage that it
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * retains compatibility with older  releases and requires no extra work on the part
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * of the client performing the serialization. However, it has the disadvantage that
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * state inherited from the superclasses of the proxy is lost during serialization.
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * if false then serialization/deserialization of the proxy instances will preserve
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * all fields. However, serialization must be performed via a {@link ProxyObjectOutputStream}
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * and deserialization must be via {@link ProxyObjectInputStream}. Any attempt to serialize
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * proxies whose class was created with useWriteReplace set to false via a normal
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * {@link java.io.ObjectOutputStream} will fail.
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Note that this value merely specifies the initial setting employed by any newly created
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * proxy factory. The factory setting may be overwritten by calling factory instance method
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * {@link #setUseWriteReplace(boolean)}
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static volatile boolean useWriteReplace = true;
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /*
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * methods allowing individual factory settings for factoryUseCache and factoryWriteReplace to be reset
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * test whether this factory uses the proxy cache
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if this factory uses the proxy cache otherwise false
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isUseCache()
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return factoryUseCache;
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * configure whether this factory should use the proxy cache
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param useCache true if this factory should use the proxy cache and false if it should not use the cache
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @throws RuntimeException if a default interceptor has been set for the factory
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setUseCache(boolean useCache)
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // we cannot allow caching to be used if the factory is configured to install a default interceptor
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // field into generated classes
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (handler != null && useCache) {
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("caching cannot be enabled if the factory default interceptor has been set");
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        factoryUseCache = useCache;
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * test whether this factory installs a writeReplace method in created classes
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if this factory installs a writeReplace method in created classes otherwise false
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isUseWriteReplace()
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return factoryWriteReplace;
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * configure whether this factory should add a writeReplace method to created classes
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param useWriteReplace true if this factory should add a writeReplace method to created classes and false if it
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * should not add a writeReplace method
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setUseWriteReplace(boolean useWriteReplace)
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        factoryWriteReplace = useWriteReplace;
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static WeakHashMap proxyCache = new WeakHashMap();
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * determine if a class is a javassist proxy class
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cl
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true if the class is a javassist proxy class otherwise false
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static boolean isProxyClass(Class cl)
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // all proxies implement ProxyObject. nothing else should.
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return (ProxyObject.class.isAssignableFrom(cl));
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * used to store details of a specific proxy class in the second tier of the proxy cache. this entry
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * will be located in a hashmap keyed by the unique identifying name of the proxy class. the hashmap is
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * located in a weak hashmap keyed by the classloader common to all proxy classes in the second tier map.
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static class ProxyDetails {
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /**
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * the unique signature of any method filter whose behaviour will be met by this class. each bit in
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * the byte array is set if the filter redirects the corresponding super or interface method and clear
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * if it does not redirect it.
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        byte[] signature;
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /**
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * a hexadecimal string representation of the signature bit sequence. this string also forms part
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * of the proxy class name.
31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        WeakReference proxyClass;
31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /**
31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * a flag which is true this class employs writeReplace to perform serialization of its instances
31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * and false if serialization must employ of a ProxyObjectOutputStream and ProxyObjectInputStream
31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean isUseWriteReplace;
32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ProxyDetails(byte[] signature, Class proxyClass, boolean isUseWriteReplace)
32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        {
32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            this.signature = signature;
32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            this.proxyClass = new WeakReference(proxyClass);
32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            this.isUseWriteReplace = isUseWriteReplace;
32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a factory of proxy class.
33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ProxyFactory() {
33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        superClass = null;
33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        interfaces = null;
33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methodFilter = null;
33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        handler = null;
33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signature = null;
33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signatureMethods = null;
34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        thisClass = null;
34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        writeDirectory = null;
34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        factoryUseCache = useCache;
34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        factoryWriteReplace = useWriteReplace;
34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets the super class of a proxy class.
34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setSuperclass(Class clazz) {
35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        superClass = clazz;
35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // force recompute of signature
35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signature = null;
35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the super class set by <code>setSuperclass()</code>.
35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Class getSuperclass() { return superClass; }
36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets the interfaces of a proxy class.
36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setInterfaces(Class[] ifs) {
36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        interfaces = ifs;
36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // force recompute of signature
36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signature = null;
36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the interfaces set by <code>setInterfaces</code>.
37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Class[] getInterfaces() { return interfaces; }
37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets a filter that selects the methods that will be controlled by a handler.
38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setFilter(MethodFilter mf) {
38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methodFilter = mf;
38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // force recompute of signature
38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signature = null;
38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Generates a proxy class using the current filter.
38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Class createClass() {
39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (signature == null) {
39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            computeSignature(methodFilter);
39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return createClass1();
39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Generates a proxy class using the supplied filter.
39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Class createClass(MethodFilter filter) {
40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        computeSignature(filter);
40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return createClass1();
40369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
40469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
40569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
40669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Generates a proxy class with a specific signature.
40769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * access is package local so ProxyObjectInputStream can use this
40869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param signature
40969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return
41069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
41169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    Class createClass(byte[] signature)
41269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
41369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        installSignature(signature);
41469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return createClass1();
41569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
41669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
41769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Class createClass1() {
41869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (thisClass == null) {
41969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ClassLoader cl = getClassLoader();
42069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            synchronized (proxyCache) {
42169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (factoryUseCache)
42269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    createClass2(cl);
42369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                else
42469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    createClass3(cl);
42569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
42669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
42769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
42869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // don't retain any unwanted references
42969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class result = thisClass;
43069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        thisClass = null;
43169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
43269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return result;
43369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
43469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
43569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static char[] hexDigits =
43669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            { '0', '1', '2', '3', '4', '5', '6', '7',
43769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
43869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
43969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getKey(Class superClass, Class[] interfaces, byte[] signature, boolean useWriteReplace)
44069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
44169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        StringBuffer sbuf = new StringBuffer();
44269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (superClass != null){
44369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(superClass.getName());
44469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
44569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        sbuf.append(":");
44669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < interfaces.length; i++) {
44769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(interfaces[i].getName());
44869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(":");
44969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
45069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < signature.length; i++) {
45169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            byte b = signature[i];
45269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int lo = b & 0xf;
45369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int hi = (b >> 4) & 0xf;
45469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(hexDigits[lo]);
45569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(hexDigits[hi]);
45669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
45769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (useWriteReplace) {
45869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sbuf.append(":w");
45969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
46069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
46169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return sbuf.toString();
46269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
46369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
46469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void createClass2(ClassLoader cl) {
46569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String key = getKey(superClass, interfaces, signature, factoryWriteReplace);
46669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /*
46769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * Excessive concurrency causes a large memory footprint and slows the
46869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * execution speed down (with JDK 1.5).  Thus, we use a jumbo lock for
46969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * reducing concrrency.
47069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
47169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // synchronized (proxyCache) {
47269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
47369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ProxyDetails details;
47469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (cacheForTheLoader == null) {
47569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                cacheForTheLoader = new HashMap();
47669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                proxyCache.put(cl, cacheForTheLoader);
47769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
47869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            details = (ProxyDetails)cacheForTheLoader.get(key);
47969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (details != null) {
48069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                WeakReference reference = details.proxyClass;
48169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                thisClass = (Class)reference.get();
48269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (thisClass != null) {
48369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    return;
48469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
48569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
48669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            createClass3(cl);
48769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            details = new  ProxyDetails(signature, thisClass, factoryWriteReplace);
48869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cacheForTheLoader.put(key, details);
48969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // }
49069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
49169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
49269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void createClass3(ClassLoader cl) {
49369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // we need a new class so we need a new class name
49469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        allocateClassName();
49569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
49669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
49769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ClassFile cf = make();
49869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (writeDirectory != null)
49969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                FactoryHelper.writeFile(cf, writeDirectory);
50069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
50169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            thisClass = FactoryHelper.toClass(cf, cl, getDomain());
50269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            setField(FILTER_SIGNATURE_FIELD, signature);
50369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // legacy behaviour : we only set the default interceptor static field if we are not using the cache
50469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (!factoryUseCache) {
50569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                setField(DEFAULT_INTERCEPTOR, handler);
50669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
50769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
50869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (CannotCompileException e) {
50969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e.getMessage(), e);
51069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
51169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
51269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
51369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
51469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void setField(String fieldName, Object value) {
51569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (thisClass != null && value != null)
51669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
51769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Field f = thisClass.getField(fieldName);
51869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                SecurityActions.setAccessible(f, true);
51969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                f.set(null, value);
52069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                SecurityActions.setAccessible(f, false);
52169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
52269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (Exception e) {
52369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new RuntimeException(e);
52469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
52569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
52669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
52769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static byte[] getFilterSignature(Class clazz) {
52869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return (byte[])getField(clazz, FILTER_SIGNATURE_FIELD);
52969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
53069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
53169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Object getField(Class clazz, String fieldName) {
53269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
53369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Field f = clazz.getField(fieldName);
53469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            f.setAccessible(true);
53569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Object value = f.get(null);
53669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            f.setAccessible(false);
53769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return value;
53869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
53969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception e) {
54069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e);
54169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
54269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
54369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
54469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
54569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * A provider of class loaders.
54669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
54769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see #classLoaderProvider
54869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
54969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
55069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static interface ClassLoaderProvider {
55169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /**
55269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * Returns a class loader.
55369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *
55469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * @param pf    a proxy factory that is going to obtain a class loader.
55569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
55669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        public ClassLoader get(ProxyFactory pf);
55769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
55869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
55969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
56069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * A provider used by <code>createClass()</code> for obtaining
56169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * a class loader.
56269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>get()</code> on this <code>ClassLoaderProvider</code> object
56369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is called to obtain a class loader.
56469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
56569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>The value of this field can be updated for changing the default
56669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * implementation.
56769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
56869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Example:
56969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <ul><pre>
57069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * ProxyFactory.classLoaderProvider = new ProxyFactory.ClassLoaderProvider() {
57169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *     public ClassLoader get(ProxyFactory pf) {
57269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *         return Thread.currentThread().getContextClassLoader();
57369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *     }
57469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * };
57569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * </pre></ul>
57669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
57769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
57869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
57969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static ClassLoaderProvider classLoaderProvider
58069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        = new ClassLoaderProvider() {
58169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal              public ClassLoader get(ProxyFactory pf) {
58269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                  return pf.getClassLoader0();
58369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal              }
58469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal          };
58569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
58669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ClassLoader getClassLoader() {
58769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return classLoaderProvider.get(this);
58869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
58969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
59069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ClassLoader getClassLoader0() {
59169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassLoader loader = null;
59269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (superClass != null && !superClass.getName().equals("java.lang.Object"))
59369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            loader = superClass.getClassLoader();
59469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (interfaces != null && interfaces.length > 0)
59569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            loader = interfaces[0].getClassLoader();
59669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
59769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (loader == null) {
59869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            loader = getClass().getClassLoader();
59969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // In case javassist is in the endorsed dir
60069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (loader == null) {
60169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                loader = Thread.currentThread().getContextClassLoader();
60269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (loader == null)
60369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    loader = ClassLoader.getSystemClassLoader();
60469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
60569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
60669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
60769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return loader;
60869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
60969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
61069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ProtectionDomain getDomain() {
61169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class clazz;
61269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (superClass != null && !superClass.getName().equals("java.lang.Object"))
61369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = superClass;
61469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (interfaces != null && interfaces.length > 0)
61569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = interfaces[0];
61669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
61769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            clazz = this.getClass();
61869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
61969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return clazz.getProtectionDomain();
62069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
62169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
62269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
62369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Creates a proxy class and returns an instance of that class.
62469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
62569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param paramTypes    parameter types for a constructor.
62669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param args          arguments passed to a constructor.
62769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param mh            the method handler for the proxy class.
62869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.4
62969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
63069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object create(Class[] paramTypes, Object[] args, MethodHandler mh)
63169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws NoSuchMethodException, IllegalArgumentException,
63269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               InstantiationException, IllegalAccessException, InvocationTargetException
63369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
63469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Object obj = create(paramTypes, args);
63569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ((ProxyObject)obj).setHandler(mh);
63669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return obj;
63769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
63869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
63969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
64069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Creates a proxy class and returns an instance of that class.
64169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
64269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param paramTypes    parameter types for a constructor.
64369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param args          arguments passed to a constructor.
64469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
64569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object create(Class[] paramTypes, Object[] args)
64669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws NoSuchMethodException, IllegalArgumentException,
64769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               InstantiationException, IllegalAccessException, InvocationTargetException
64869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
64969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class c = createClass();
65069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Constructor cons = c.getConstructor(paramTypes);
65169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return cons.newInstance(args);
65269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
65369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
65469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
65569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets the default invocation handler.  This invocation handler is shared
65669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * among all the instances of a proxy class unless another is explicitly
65769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * specified.
65869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @deprecated since 3.12
65969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * use of this method is incompatible  with proxy class caching.
66069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * instead clients should call method {@link ProxyObject#setHandler(MethodHandler)} to set the handler
66169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * for each newly created  proxy instance.
66269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * calling this method will automatically disable caching of classes created by the proxy factory.
66369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
66469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setHandler(MethodHandler mi) {
66569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // if we were using the cache and the handler is non-null then we must stop caching
66669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (factoryUseCache && mi != null)  {
66769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            factoryUseCache = false;
66869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // clear any currently held class so we don't try to reuse it or set its handler field
66969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal          thisClass  = null;
67069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
67169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        handler = mi;
67269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // this retains the behaviour of the old code which resets any class we were holding on to
67369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // this is probably not what is wanted
67469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setField(DEFAULT_INTERCEPTOR, handler);
67569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
67669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
67769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int counter = 0;
67869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
67969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static synchronized String makeProxyName(String classname) {
68069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return classname + "_$$_javassist_" + counter++;
68169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
68269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
68369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ClassFile make() throws CannotCompileException {
68469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassFile cf = new ClassFile(false, classname, superName);
68569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.setAccessFlags(AccessFlag.PUBLIC);
68669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setInterfaces(cf, interfaces);
68769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool pool = cf.getConstPool();
68869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
68969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // legacy: we only add the static field for the default interceptor if caching is disabled
69069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if  (!factoryUseCache) {
69169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
69269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
69369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cf.addField(finfo);
69469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
69569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
69669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // handler is per instance
69769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
69869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        finfo2.setAccessFlags(AccessFlag.PRIVATE);
69969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addField(finfo2);
70069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
70169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // filter signature is per class
70269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        FieldInfo finfo3 = new FieldInfo(pool, FILTER_SIGNATURE_FIELD, FILTER_SIGNATURE_TYPE);
70369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
70469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addField(finfo3);
70569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
70669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // the proxy class serial uid must always be a fixed value
70769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        FieldInfo finfo4 = new FieldInfo(pool, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
70869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        finfo4.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC| AccessFlag.FINAL);
70969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addField(finfo4);
71069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
71169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // HashMap allMethods = getMethods(superClass, interfaces);
71269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // int size = allMethods.size();
71369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        makeConstructors(classname, cf, pool, classname);
71469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int s = overrideMethods(cf, pool, classname);
71569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addMethodsHolder(cf, pool, classname, s);
71669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addSetter(classname, cf, pool);
71769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addGetter(classname, cf, pool);
71869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
71969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (factoryWriteReplace) {
72069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
72169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                cf.addMethod(makeWriteReplace(pool));
72269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
72369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (DuplicateMemberException e) {
72469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // writeReplace() is already declared in the super class/interfaces.
72569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
72669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
72769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
72869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        thisClass = null;
72969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return cf;
73069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
73169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
73269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void checkClassAndSuperName()
73369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
73469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (interfaces == null)
73569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            interfaces = new Class[0];
73669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
73769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (superClass == null) {
73869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            superClass = OBJECT_TYPE;
73969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            superName = superClass.getName();
74069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            basename = interfaces.length == 0 ? superName
74169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                               : interfaces[0].getName();
74269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else {
74369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            superName = superClass.getName();
74469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            basename = superName;
74569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
74669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
74769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (Modifier.isFinal(superClass.getModifiers()))
74869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(superName + " is final");
74969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
75069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (basename.startsWith("java."))
75169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            basename = "org.javassist.tmp." + basename;
75269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
75369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
75469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void allocateClassName()
75569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
75669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classname = makeProxyName(basename);
75769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
75869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
75969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static Comparator sorter = new Comparator() {
76069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
76169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        public int compare(Object o1, Object o2) {
76269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e1 = (Map.Entry)o1;
76369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e2 = (Map.Entry)o2;
76469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String key1 = (String)e1.getKey();
76569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String key2 = (String)e2.getKey();
76669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return key1.compareTo(key2);
76769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
76869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    };
76969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
77069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void makeSortedMethodList()
77169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
77269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        checkClassAndSuperName();
77369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
77469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        HashMap allMethods = getMethods(superClass, interfaces);
77569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signatureMethods = new ArrayList(allMethods.entrySet());
77669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Collections.sort(signatureMethods, sorter);
77769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
77869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
77969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void computeSignature(MethodFilter filter) // throws CannotCompileException
78069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
78169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        makeSortedMethodList();
78269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
78369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int l = signatureMethods.size();
78469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int maxBytes = ((l + 7) >> 3);
78569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        signature = new byte[maxBytes];
78669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int idx = 0; idx < l; idx++)
78769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        {
78869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e = (Map.Entry)signatureMethods.get(idx);
78969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Method m = (Method)e.getValue();
79069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = m.getModifiers();
79169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
79269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && isVisible(mod, basename, m) && (filter == null || filter.isHandled(m))) {
79369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                setBit(signature, idx);
79469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
79569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
79669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
79769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
79869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void installSignature(byte[] signature) // throws CannotCompileException
79969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
80069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        makeSortedMethodList();
80169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
80269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int l = signatureMethods.size();
80369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int maxBytes = ((l + 7) >> 3);
80469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (signature.length != maxBytes) {
80569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("invalid filter signature length for deserialized proxy class");
80669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
80769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
80869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.signature =  signature;
80969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
81069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
81169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean testBit(byte[] signature, int idx)
81269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
81369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int byteIdx = idx >> 3;
81469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (byteIdx > signature.length) {
81569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
81669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else {
81769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int bitIdx = idx & 0x7;
81869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mask = 0x1 << bitIdx;
81969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int sigByte = signature[byteIdx];
82069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return ((sigByte & mask) != 0);
82169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
82269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
82369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
82469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void setBit(byte[] signature, int idx)
82569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
82669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int byteIdx = idx >> 3;
82769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (byteIdx < signature.length) {
82869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int bitIdx = idx & 0x7;
82969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mask = 0x1 << bitIdx;
83069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int sigByte = signature[byteIdx];
83169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            signature[byteIdx] = (byte)(sigByte | mask);
83269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
83369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
83469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
83569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void setInterfaces(ClassFile cf, Class[] interfaces) {
83669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String setterIntf = ProxyObject.class.getName();
83769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String[] list;
83869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (interfaces == null || interfaces.length == 0)
83969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            list = new String[] { setterIntf };
84069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
84169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            list = new String[interfaces.length + 1];
84269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            for (int i = 0; i < interfaces.length; i++)
84369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                list[i] = interfaces[i].getName();
84469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
84569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            list[interfaces.length] = setterIntf;
84669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
84769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
84869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.setInterfaces(list);
84969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
85069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
85169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void addMethodsHolder(ClassFile cf, ConstPool cp,
85269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                         String classname, int size)
85369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
85469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
85569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
85669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
85769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addField(finfo);
85869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
85969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setAccessFlags(AccessFlag.STATIC);
86069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 0, 0);
86169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIconst(size * 2);
86269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAnewarray("java.lang.reflect.Method");
86369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
86469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // also need to set serial version uid
86569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addLconst(-1L);
86669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
86769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Bytecode.RETURN);
86869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setCodeAttribute(code.toCodeAttribute());
86969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addMethod(minfo);
87069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
87169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
87269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void addSetter(String classname, ClassFile cf, ConstPool cp)
87369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
87469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
87569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
87669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          HANDLER_SETTER_TYPE);
87769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setAccessFlags(AccessFlag.PUBLIC);
87869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 2, 2);
87969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
88069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(1);
88169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addPutfield(classname, HANDLER, HANDLER_TYPE);
88269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Bytecode.RETURN);
88369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setCodeAttribute(code.toCodeAttribute());
88469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addMethod(minfo);
88569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
88669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
88769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void addGetter(String classname, ClassFile cf, ConstPool cp)
88869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
88969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
89069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo minfo = new MethodInfo(cp, HANDLER_GETTER,
89169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                          HANDLER_GETTER_TYPE);
89269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setAccessFlags(AccessFlag.PUBLIC);
89369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 1, 1);
89469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
89569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addGetfield(classname, HANDLER, HANDLER_TYPE);
89669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Bytecode.ARETURN);
89769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setCodeAttribute(code.toCodeAttribute());
89869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addMethod(minfo);
89969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
90069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
90169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private int overrideMethods(ClassFile cf, ConstPool cp, String className)
90269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
90369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
90469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String prefix = makeUniqueName("_d", signatureMethods);
90569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Iterator it = signatureMethods.iterator();
90669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int index = 0;
90769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (it.hasNext()) {
90869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e = (Map.Entry)it.next();
90969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String key = (String)e.getKey();
91069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Method meth = (Method)e.getValue();
91169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = meth.getModifiers();
91269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (testBit(signature, index)) {
91369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                override(className, meth, prefix, index,
91469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        keyToDesc(key), cf, cp);
91569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
91669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            index++;
91769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
91869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
91969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return index;
92069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
92169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
92269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void override(String thisClassname, Method meth, String prefix,
92369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                          int index, String desc, ClassFile cf, ConstPool cp)
92469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
92569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
92669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class declClass = meth.getDeclaringClass();
92769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String delegatorName = prefix + index + meth.getName();
92869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (Modifier.isAbstract(meth.getModifiers()))
92969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            delegatorName = null;
93069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
93169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            MethodInfo delegator
93269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                = makeDelegator(meth, desc, cp, declClass, delegatorName);
93369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // delegator is not a bridge method.  See Sec. 15.12.4.5 of JLS 3rd Ed.
93469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            delegator.setAccessFlags(delegator.getAccessFlags() & ~AccessFlag.BRIDGE);
93569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            cf.addMethod(delegator);
93669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
93769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
93869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo forwarder
93969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = makeForwarder(thisClassname, meth, desc, cp, declClass,
94069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            delegatorName, index);
94169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cf.addMethod(forwarder);
94269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
94369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
94469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void makeConstructors(String thisClassName, ClassFile cf,
94569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ConstPool cp, String classname) throws CannotCompileException
94669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
94769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Constructor[] cons = SecurityActions.getDeclaredConstructors(superClass);
94869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // legacy: if we are not caching then we need to initialise the default handler
94969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean doHandlerInit = !factoryUseCache;
95069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < cons.length; i++) {
95169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Constructor c = cons[i];
95269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int mod = c.getModifiers();
95369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
95469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && isVisible(mod, basename, c)) {
95569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                MethodInfo m = makeConstructor(thisClassName, c, cp, superClass, doHandlerInit);
95669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                cf.addMethod(m);
95769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
95869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
95969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
96069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
96169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static String makeUniqueName(String name, List sortedMethods) {
96269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (makeUniqueName0(name, sortedMethods.iterator()))
96369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return name;
96469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
96569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 100; i < 999; i++) {
96669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String s = name + i;
96769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (makeUniqueName0(s, sortedMethods.iterator()))
96869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return s;
96969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
97069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
97169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new RuntimeException("cannot make a unique method name");
97269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
97369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
97469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static boolean makeUniqueName0(String name, Iterator it) {
97569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (it.hasNext()) {
97669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e = (Map.Entry)it.next();
97769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String key = (String)e.getKey();
97869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (key.startsWith(name))
97969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return false;
98069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
98169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
98269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return true;
98369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
98469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
98569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
98669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if the method is visible from the package.
98769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
98869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param mod       the modifiers of the method.
98969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
99069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static boolean isVisible(int mod, String from, Member meth) {
99169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if ((mod & Modifier.PRIVATE) != 0)
99269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
99369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
99469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return true;
99569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
99669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String p = getPackageName(from);
99769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String q = getPackageName(meth.getDeclaringClass().getName());
99869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (p == null)
99969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return q == null;
100069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
100169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return p.equals(q);
100269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
100369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
100469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
100569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static String getPackageName(String name) {
100669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int i = name.lastIndexOf('.');
100769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (i < 0)
100869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return null;
100969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
101069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return name.substring(0, i);
101169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
101269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
101369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static HashMap getMethods(Class superClass, Class[] interfaceTypes) {
101469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        HashMap hash = new HashMap();
101569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < interfaceTypes.length; i++)
101669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            getMethods(hash, interfaceTypes[i]);
101769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
101869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        getMethods(hash, superClass);
101969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return hash;
102069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
102169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
102269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void getMethods(HashMap hash, Class clazz) {
102369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class[] ifs = clazz.getInterfaces();
102469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < ifs.length; i++)
102569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            getMethods(hash, ifs[i]);
102669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
102769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class parent = clazz.getSuperclass();
102869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (parent != null)
102969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            getMethods(hash, parent);
103069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
103169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Method[] methods = SecurityActions.getDeclaredMethods(clazz);
103269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < methods.length; i++)
103369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (!Modifier.isPrivate(methods[i].getModifiers())) {
103469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Method m = methods[i];
103569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);
103669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // JIRA JASSIST-85
103769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // put the method to the cache, retrieve previous definition (if any)
103869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Method oldMethod = (Method)hash.put(key, methods[i]);
103969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
104069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                // check if visibility has been reduced
104169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (null != oldMethod && Modifier.isPublic(oldMethod.getModifiers())
104269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                      && !Modifier.isPublic(methods[i].getModifiers()) ) {
104369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    // we tried to overwrite a public definition with a non-public definition,
104469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    // use the old definition instead.
104569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    hash.put(key, oldMethod);
104669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
104769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
104869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
104969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
105069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static String keyToDesc(String key) {
105169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return key.substring(key.indexOf(':') + 1);
105269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
105369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
105469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static MethodInfo makeConstructor(String thisClassName, Constructor cons,
105569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                              ConstPool cp, Class superClass, boolean doHandlerInit) {
105669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),
105769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                                    Void.TYPE);
105869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
105969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setAccessFlags(Modifier.PUBLIC);      // cons.getModifiers() & ~Modifier.NATIVE
106069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setThrows(minfo, cp, cons.getExceptionTypes());
106169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 0, 0);
106269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
106369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // legacy: if we are not using caching then we initialise the instance's handler
106469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // from the class's static default interceptor and skip the next few instructions if
106569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // it is non-null
106669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (doHandlerInit) {
106769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addAload(0);
106869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
106969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
107069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
107169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addOpcode(Opcode.IFNONNULL);
107269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addIndex(10);
107369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
107469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // if caching is enabled then we don't have a handler to initialise so this else branch will install
107569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // the handler located in the static field of class RuntimeSupport.
107669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
107769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
107869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
107969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int pc = code.currentPc();
108069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
108169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
108269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int s = addLoadParameters(code, cons.getParameterTypes(), 1);
108369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokespecial(superClass.getName(), "<init>", desc);
108469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Opcode.RETURN);
108569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.setMaxLocals(s + 1);
108669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute ca = code.toCodeAttribute();
108769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setCodeAttribute(ca);
108869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
108969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        StackMapTable.Writer writer = new StackMapTable.Writer(32);
109069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        writer.sameFrame(pc);
109169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ca.setAttribute(writer.toStackMapTable(cp));
109269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return minfo;
109369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
109469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
109569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static MethodInfo makeDelegator(Method meth, String desc,
109669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ConstPool cp, Class declClass, String delegatorName) {
109769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
109869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
109969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                | (meth.getModifiers() & ~(Modifier.PRIVATE
110069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           | Modifier.PROTECTED
110169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           | Modifier.ABSTRACT
110269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           | Modifier.NATIVE
110369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           | Modifier.SYNCHRONIZED)));
110469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setThrows(delegator, cp, meth);
110569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 0, 0);
110669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
110769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int s = addLoadParameters(code, meth.getParameterTypes(), 1);
110869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokespecial(declClass.getName(), meth.getName(), desc);
110969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addReturn(code, meth.getReturnType());
111069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.setMaxLocals(++s);
111169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        delegator.setCodeAttribute(code.toCodeAttribute());
111269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return delegator;
111369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
111469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
111569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
111669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param delegatorName     null if the original method is abstract.
111769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
111869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static MethodInfo makeForwarder(String thisClassName,
111969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    Method meth, String desc, ConstPool cp,
112069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    Class declClass, String delegatorName, int index) {
112169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
112269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        forwarder.setAccessFlags(Modifier.FINAL
112369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    | (meth.getModifiers() & ~(Modifier.ABSTRACT
112469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                               | Modifier.NATIVE
112569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                               | Modifier.SYNCHRONIZED)));
112669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setThrows(forwarder, cp, meth);
112769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int args = Descriptor.paramSize(desc);
112869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 0, args + 2);
112969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        /*
113069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * if (methods[index * 2] == null) {
113169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *   methods[index * 2]
113269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *     = RuntimeSupport.findSuperMethod(this, <overridden name>, <desc>);
113369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *   methods[index * 2 + 1]
113469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *     = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
113569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *     or = null // the original method is abstract.
113669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * }
113769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         * return ($r)handler.invoke(this, methods[index * 2],
113869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         *                methods[index * 2 + 1], $args);
113969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal         */
114069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int origIndex = index * 2;
114169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int delIndex = index * 2 + 1;
114269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int arrayVar = args + 1;
114369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
114469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAstore(arrayVar);
114569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
114669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        callFind2Methods(code, meth.getName(), delegatorName, origIndex, desc, arrayVar);
114769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
114869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
114969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
115069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
115169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
115269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(arrayVar);
115369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIconst(origIndex);
115469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Opcode.AALOAD);
115569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
115669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(arrayVar);
115769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIconst(delIndex);
115869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Opcode.AALOAD);
115969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
116069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        makeParameterList(code, meth.getParameterTypes());
116169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokeinterface(MethodHandler.class.getName(), "invoke",
116269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
116369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            5);
116469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class retType = meth.getReturnType();
116569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addUnwrapper(code, retType);
116669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addReturn(code, retType);
116769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
116869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute ca = code.toCodeAttribute();
116969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        forwarder.setCodeAttribute(ca);
117069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return forwarder;
117169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
117269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
117369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
117469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class[] exceptions = orig.getExceptionTypes();
117569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setThrows(minfo, cp, exceptions);
117669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
117769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
117869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void setThrows(MethodInfo minfo, ConstPool cp,
117969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  Class[] exceptions) {
118069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (exceptions.length == 0)
118169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return;
118269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
118369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String[] list = new String[exceptions.length];
118469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < exceptions.length; i++)
118569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            list[i] = exceptions[i].getName();
118669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
118769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ExceptionsAttribute ea = new ExceptionsAttribute(cp);
118869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ea.setExceptions(list);
118969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setExceptionsAttribute(ea);
119069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
119169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
119269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int addLoadParameters(Bytecode code, Class[] params,
119369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                         int offset) {
119469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int stacksize = 0;
119569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = params.length;
119669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i)
119769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stacksize += addLoad(code, stacksize + offset, params[i]);
119869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
119969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return stacksize;
120069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
120169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
120269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int addLoad(Bytecode code, int n, Class type) {
120369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type.isPrimitive()) {
120469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (type == Long.TYPE) {
120569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addLload(n);
120669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return 2;
120769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
120869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if (type == Float.TYPE)
120969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addFload(n);
121069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if (type == Double.TYPE) {
121169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addDload(n);
121269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return 2;
121369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
121469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
121569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addIload(n);
121669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
121769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
121869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addAload(n);
121969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
122069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return 1;
122169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
122269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
122369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int addReturn(Bytecode code, Class type) {
122469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type.isPrimitive()) {
122569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (type == Long.TYPE) {
122669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.LRETURN);
122769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return 2;
122869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
122969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if (type == Float.TYPE)
123069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.FRETURN);
123169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if (type == Double.TYPE) {
123269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.DRETURN);
123369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return 2;
123469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
123569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else if (type == Void.TYPE) {
123669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.RETURN);
123769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return 0;
123869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
123969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
124069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.IRETURN);
124169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
124269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
124369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addOpcode(Opcode.ARETURN);
124469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
124569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return 1;
124669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
124769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
124869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void makeParameterList(Bytecode code, Class[] params) {
124969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int regno = 1;
125069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = params.length;
125169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIconst(n);
125269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAnewarray("java/lang/Object");
125369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; i++) {
125469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addOpcode(Opcode.DUP);
125569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addIconst(i);
125669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Class type = params[i];
125769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (type.isPrimitive())
125869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                regno = makeWrapper(code, type, regno);
125969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else {
126069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addAload(regno);
126169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                regno++;
126269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
126369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
126469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addOpcode(Opcode.AASTORE);
126569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
126669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
126769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
126869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static int makeWrapper(Bytecode code, Class type, int regno) {
126969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int index = FactoryHelper.typeIndex(type);
127069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String wrapper = FactoryHelper.wrapperTypes[index];
127169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addNew(wrapper);
127269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Opcode.DUP);
127369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addLoad(code, regno, type);
127469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokespecial(wrapper, "<init>",
127569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                              FactoryHelper.wrapperDesc[index]);
127669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return regno + FactoryHelper.dataSize[index];
127769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
127869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
127969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
128069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param thisMethod        might be null.
128169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
128269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
128369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                         int index, String desc, int arrayVar) {
128469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String findClass = RuntimeSupport.class.getName();
128569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String findDesc
128669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
128769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
128869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
128969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addLdc(superMethod);
129069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (thisMethod == null)
129169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addOpcode(Opcode.ACONST_NULL);
129269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
129369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addLdc(thisMethod);
129469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
129569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addIconst(index);
129669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addLdc(desc);
129769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(arrayVar);
129869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokestatic(findClass, "find2Methods", findDesc);
129969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
130069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
130169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void addUnwrapper(Bytecode code, Class type) {
130269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type.isPrimitive()) {
130369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (type == Void.TYPE)
130469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addOpcode(Opcode.POP);
130569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else {
130669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int index = FactoryHelper.typeIndex(type);
130769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String wrapper = FactoryHelper.wrapperTypes[index];
130869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addCheckcast(wrapper);
130969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                code.addInvokevirtual(wrapper,
131069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                      FactoryHelper.unwarpMethods[index],
131169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                      FactoryHelper.unwrapDesc[index]);
131269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
131369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
131469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
131569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            code.addCheckcast(type.getName());
131669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
131769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
131869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static MethodInfo makeWriteReplace(ConstPool cp) {
131969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
132069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String[] list = new String[1];
132169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        list[0] = "java.io.ObjectStreamException";
132269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ExceptionsAttribute ea = new ExceptionsAttribute(cp);
132369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ea.setExceptions(list);
132469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setExceptionsAttribute(ea);
132569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode code = new Bytecode(cp, 0, 1);
132669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addAload(0);
132769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
132869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                             "makeSerializedProxy",
132969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                             "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
133069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        code.addOpcode(Opcode.ARETURN);
133169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        minfo.setCodeAttribute(code.toCodeAttribute());
133269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return minfo;
133369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
133469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
1335