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