diff options
Diffstat (limited to 'src/main/javassist/util/proxy/ProxyFactory.java')
-rw-r--r-- | src/main/javassist/util/proxy/ProxyFactory.java | 127 |
1 files changed, 89 insertions, 38 deletions
diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index 3dd5b1e6..444697ec 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -32,6 +32,11 @@ import java.lang.ref.WeakReference; 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. * @@ -92,6 +97,11 @@ import javassist.bytecode.*; * } * </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 */ @@ -117,6 +127,7 @@ public class ProxyFactory { 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"; @@ -137,8 +148,8 @@ public class ProxyFactory { 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; @@ -233,10 +244,12 @@ public class ProxyFactory { 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; @@ -244,7 +257,12 @@ public class ProxyFactory { 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(); @@ -264,9 +282,9 @@ public class ProxyFactory { } } } - } + // } - synchronized (key) { + // synchronized (key) { Class c = isValidEntry(key); if (c == null) { createClass3(cl); @@ -274,7 +292,7 @@ public class ProxyFactory { } else thisClass = c; - } + // } } private Class isValidEntry(CacheKey key) { @@ -295,7 +313,8 @@ public class ProxyFactory { 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); @@ -303,6 +322,40 @@ public class ProxyFactory { } + 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. * @@ -403,33 +456,7 @@ public class ProxyFactory { */ 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; @@ -473,6 +500,11 @@ public class ProxyFactory { 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); @@ -480,6 +512,8 @@ public class ProxyFactory { addMethodsHolder(cf, pool, classname, s); addSetter(classname, cf, pool); + cf.addMethod(makeWriteReplace(pool)); + thisClass = null; return cf; } @@ -932,4 +966,21 @@ public class ProxyFactory { 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; + } } |