import javassist.CannotCompileException;
import javassist.bytecode.*;
+/*
+ * This class is implemented only with the lower-level API of Javassist.
+ * This design decision is for maximizing performance.
+ */
+
/**
* Factory of dynamic proxy classes.
*
* }
* </pre></ul>
*
+ * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
+ * if its super class or interfaces implement a <code>java.io.Serializable</code>.
+ * However, a serialized proxy object will not be compatible with future releases.
+ * The serialization support should be used for short-term storage or RMI.
+ *
* @see MethodHandler
* @since 3.1
*/
private static final String HOLDER = "_methods_";
private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
+ private static final String METHOD_FILTER_FIELD = "_method_filter";
private static final String HANDLER = "handler";
private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
private static WeakHashMap proxyCache = new WeakHashMap();
static class CacheKey {
- private String classes;
- private MethodFilter filter;
+ String classes;
+ MethodFilter filter;
private int hash;
WeakReference proxyClass;
MethodHandler handler;
public Class createClass() {
if (thisClass == null) {
ClassLoader cl = getClassLoader();
- if (useCache)
- createClass2(cl);
- else
- createClass3(cl);
+ synchronized (proxyCache) {
+ if (useCache)
+ createClass2(cl);
+ else
+ createClass3(cl);
+ }
}
return thisClass;
private void createClass2(ClassLoader cl) {
CacheKey key = new CacheKey(superClass, interfaces, methodFilter, handler);
- synchronized (proxyCache) {
+ /*
+ * Excessive concurrency causes a large memory footprint and slows the
+ * execution speed down (with JDK 1.5). Thus, we use a jumbo lock for
+ * reducing concrrency.
+ */
+ // synchronized (proxyCache) {
HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
if (cacheForTheLoader == null) {
cacheForTheLoader = new HashMap();
}
}
}
- }
+ // }
- synchronized (key) {
+ // synchronized (key) {
Class c = isValidEntry(key);
if (c == null) {
createClass3(cl);
}
else
thisClass = c;
- }
+ // }
}
private Class isValidEntry(CacheKey key) {
FactoryHelper.writeFile(cf, writeDirectory);
thisClass = FactoryHelper.toClass(cf, cl, getDomain());
- setHandler();
+ setField(DEFAULT_INTERCEPTOR, handler);
+ setField(METHOD_FILTER_FIELD, methodFilter);
}
catch (CannotCompileException e) {
throw new RuntimeException(e.getMessage(), e);
}
+ private void setField(String fieldName, Object value) {
+ if (thisClass != null && value != null)
+ try {
+ Field f = thisClass.getField(fieldName);
+ f.setAccessible(true);
+ f.set(null, value);
+ f.setAccessible(false);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static MethodFilter getFilter(Class clazz) {
+ return (MethodFilter)getField(clazz, METHOD_FILTER_FIELD);
+ }
+
+ static MethodHandler getHandler(Class clazz) {
+ return (MethodHandler)getField(clazz, DEFAULT_INTERCEPTOR);
+ }
+
+ private static Object getField(Class clazz, String fieldName) {
+ try {
+ Field f = clazz.getField(fieldName);
+ f.setAccessible(true);
+ Object value = f.get(null);
+ f.setAccessible(false);
+ return value;
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* A provider of class loaders.
*
*/
public void setHandler(MethodHandler mi) {
handler = mi;
- setHandler();
- }
-
- private void setHandler() {
- if (thisClass != null && handler != null)
- try {
- Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
- f.setAccessible(true);
- f.set(null, handler);
- f.setAccessible(false);
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- static MethodHandler getHandler(Class clazz) {
- try {
- Field f = clazz.getField(DEFAULT_INTERCEPTOR);
- f.setAccessible(true);
- MethodHandler h = (MethodHandler)f.get(null);
- f.setAccessible(false);
- return h;
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
+ setField(DEFAULT_INTERCEPTOR, handler);
}
private static int counter = 0;
finfo2.setAccessFlags(AccessFlag.PRIVATE);
cf.addField(finfo2);
+ FieldInfo finfo3 = new FieldInfo(pool, METHOD_FILTER_FIELD,
+ "Ljavassist/util/proxy/MethodFilter;");
+ finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+ cf.addField(finfo3);
+
HashMap allMethods = getMethods(superClass, interfaces);
int size = allMethods.size();
makeConstructors(classname, cf, pool, classname);
addMethodsHolder(cf, pool, classname, s);
addSetter(classname, cf, pool);
+ cf.addMethod(makeWriteReplace(pool));
+
thisClass = null;
return cf;
}
else
code.addCheckcast(type.getName());
}
+
+ private static MethodInfo makeWriteReplace(ConstPool cp) {
+ MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
+ String[] list = new String[1];
+ list[0] = "java.io.ObjectStreamException";
+ ExceptionsAttribute ea = new ExceptionsAttribute(cp);
+ ea.setExceptions(list);
+ minfo.setExceptionsAttribute(ea);
+ Bytecode code = new Bytecode(cp, 0, 1);
+ code.addAload(0);
+ code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
+ "makeSerializedProxy",
+ "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
+ code.addOpcode(Opcode.ARETURN);
+ minfo.setCodeAttribute(code.toCodeAttribute());
+ return minfo;
+ }
}
package javassist.util.proxy;
import java.lang.reflect.Method;
+import java.io.Serializable;
/**
* Runtime support routines that the classes generated by ProxyFactory use.
/**
* A method handler that only executes a method.
*/
- public static MethodHandler default_interceptor = new MethodHandler() {
+ public static MethodHandler default_interceptor = new DefaultMethodHandler();
+
+ static class DefaultMethodHandler implements MethodHandler, Serializable {
public Object invoke(Object self, Method m,
Method proceed, Object[] args)
throws Exception
sbuf.append('L').append(type.getName().replace('.', '/'))
.append(';');
}
+
+ /**
+ * Converts a proxy object to an object that is writable to an
+ * object stream. This method is called by <code>writeReplace()</code>
+ * in a proxy class.
+ *
+ * @since 3.4
+ */
+ public static SerializedProxy makeSerializedProxy(Object proxy)
+ throws java.io.InvalidClassException
+ {
+ Class clazz = proxy.getClass();
+ return new SerializedProxy(clazz, ProxyFactory.getFilter(clazz),
+ ProxyFactory.getHandler(clazz));
+ }
}
--- /dev/null
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.util.proxy;
+
+import java.io.Serializable;
+import java.io.ObjectStreamException;
+
+/**
+ * A proxy object is converted into an instance of this class
+ * when it is written to an output stream.
+ *
+ * @see RuntimeSupport#makeSerializedProxy(Object)
+ */
+class SerializedProxy implements Serializable {
+ private String superClass;
+ private String[] interfaces;
+ private MethodFilter filter;
+ private MethodHandler handler;
+
+ SerializedProxy(Class proxy, MethodFilter f, MethodHandler h) {
+ filter = f;
+ handler = h;
+ superClass = proxy.getSuperclass().getName();
+ Class[] infs = proxy.getInterfaces();
+ int n = infs.length;
+ interfaces = new String[n - 1];
+ String setterInf = ProxyObject.class.getName();
+ for (int i = 0; i < n; i++) {
+ String name = infs[i].getName();
+ if (!name.equals(setterInf))
+ interfaces[i] = name;
+ }
+ }
+
+ Object readResolve() throws ObjectStreamException {
+ try {
+ int n = interfaces.length;
+ Class[] infs = new Class[n];
+ for (int i = 0; i < n; i++)
+ infs[i] = Class.forName(interfaces[i]);
+
+ ProxyFactory f = new ProxyFactory();
+ f.setSuperclass(Class.forName(superClass));
+ f.setInterfaces(infs);
+ f.setFilter(filter);
+ f.setHandler(handler);
+ return f.createClass().newInstance();
+ }
+ catch (ClassNotFoundException e) {
+ throw new java.io.InvalidClassException(e.getMessage());
+ }
+ catch (InstantiationException e2) {
+ throw new java.io.InvalidObjectException(e2.getMessage());
+ }
+ catch (IllegalAccessException e3) {
+ throw new java.io.InvalidClassException(e3.getMessage());
+ }
+ }
+}