aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/util/proxy/ProxyFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/util/proxy/ProxyFactory.java')
-rw-r--r--src/main/javassist/util/proxy/ProxyFactory.java127
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;
+ }
}