From a904f21c6dead5d668205119241bc4206d70d064 Mon Sep 17 00:00:00 2001 From: chiba Date: Thu, 25 Oct 2012 16:38:40 +0000 Subject: fixed JASSIST-163. Eager initialization has been implemented. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@676 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- javassist.jar | Bin 699781 -> 700680 bytes src/main/javassist/util/proxy/MethodHandler.java | 4 +- src/main/javassist/util/proxy/ProxyFactory.java | 112 ++++++++++++++------- src/main/javassist/util/proxy/RuntimeSupport.java | 34 ++----- src/test/javassist/JvstTest.java | 4 +- .../javassist/proxyfactory/ProxyFactoryTest.java | 2 - src/test/test/javassist/proxy/ProxySimpleTest.java | 38 +++++++ 7 files changed, 128 insertions(+), 66 deletions(-) diff --git a/javassist.jar b/javassist.jar index 87393d38..6cd27e1c 100644 Binary files a/javassist.jar and b/javassist.jar differ diff --git a/src/main/javassist/util/proxy/MethodHandler.java b/src/main/javassist/util/proxy/MethodHandler.java index 9145895a..2cd8fb16 100644 --- a/src/main/javassist/util/proxy/MethodHandler.java +++ b/src/main/javassist/util/proxy/MethodHandler.java @@ -22,7 +22,7 @@ import java.lang.reflect.Method; * The interface implemented by the invocation handler of a proxy * instance. * - * @see ProxyFactory#setHandler(MethodHandler) + * @see Proxy#setHandler(MethodHandler) */ public interface MethodHandler { /** @@ -33,7 +33,7 @@ public interface MethodHandler { * @param thisMethod the overridden method declared in the super * class or interface. * @param proceed the forwarder method for invoking the overridden - * method. It is null if the overridden mehtod is + * method. It is null if the overridden method is * abstract or declared in the interface. * @param args an array of objects containing the values of * the arguments passed in the method invocation diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index 9bce51fa..957ba8f1 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -27,6 +27,7 @@ import java.util.*; import java.lang.ref.WeakReference; import javassist.CannotCompileException; +import javassist.NotFoundException; import javassist.bytecode.*; /* @@ -204,7 +205,7 @@ public class ProxyFactory { private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID"; private static final String SERIAL_VERSION_UID_TYPE = "J"; - private static final int SERIAL_VERSION_UID_VALUE = -1; + private static final long SERIAL_VERSION_UID_VALUE = -1L; /** * If true, a generated proxy class is cached and it will be reused @@ -736,8 +737,10 @@ public class ProxyFactory { // HashMap allMethods = getMethods(superClass, interfaces); // int size = allMethods.size(); makeConstructors(classname, cf, pool, classname); - int s = overrideMethods(cf, pool, classname); - addMethodsHolder(cf, pool, classname, s); + + ArrayList forwarders = new ArrayList(); + int s = overrideMethods(cf, pool, classname, forwarders); + addClassInitializer(cf, pool, classname, s, forwarders); addSetter(classname, cf, pool); if (!hasGetHandler) addGetter(classname, cf, pool); @@ -875,8 +878,8 @@ public class ProxyFactory { cf.setInterfaces(list); } - private static void addMethodsHolder(ClassFile cf, ConstPool cp, - String classname, int size) + private static void addClassInitializer(ClassFile cf, ConstPool cp, + String classname, int size, ArrayList forwarders) throws CannotCompileException { FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE); @@ -884,18 +887,61 @@ public class ProxyFactory { cf.addField(finfo); MethodInfo minfo = new MethodInfo(cp, "", "()V"); minfo.setAccessFlags(AccessFlag.STATIC); - Bytecode code = new Bytecode(cp, 0, 0); + setThrows(minfo, cp, new Class[] { ClassNotFoundException.class }); + + Bytecode code = new Bytecode(cp, 0, 2); code.addIconst(size * 2); code.addAnewarray("java.lang.reflect.Method"); + final int varArray = 0; + code.addAstore(varArray); + + // forName() must be called here. Otherwise, the class might be + // invisible. + code.addLdc(classname); + code.addInvokestatic("java.lang.Class", + "forName", "(Ljava/lang/String;)Ljava/lang/Class;"); + final int varClass = 1; + code.addAstore(varClass); + + Iterator it = forwarders.iterator(); + while (it.hasNext()) { + Find2MethodsArgs args = (Find2MethodsArgs)it.next(); + callFind2Methods(code, args.methodName, args.delegatorName, + args.origIndex, args.descriptor, varClass, varArray); + } + + code.addAload(varArray); code.addPutstatic(classname, HOLDER, HOLDER_TYPE); - // also need to set serial version uid - code.addLconst(-1L); + + code.addLconst(SERIAL_VERSION_UID_VALUE); code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE); code.addOpcode(Bytecode.RETURN); minfo.setCodeAttribute(code.toCodeAttribute()); cf.addMethod(minfo); } + /** + * @param thisMethod might be null. + */ + private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod, + int index, String desc, int classVar, int arrayVar) { + String findClass = RuntimeSupport.class.getName(); + String findDesc + = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V"; + + code.addAload(classVar); + code.addLdc(superMethod); + if (thisMethod == null) + code.addOpcode(Opcode.ACONST_NULL); + else + code.addLdc(thisMethod); + + code.addIconst(index); + code.addLdc(desc); + code.addAload(arrayVar); + code.addInvokestatic(findClass, "find2Methods", findDesc); + } + private static void addSetter(String classname, ClassFile cf, ConstPool cp) throws CannotCompileException { @@ -925,7 +971,7 @@ public class ProxyFactory { cf.addMethod(minfo); } - private int overrideMethods(ClassFile cf, ConstPool cp, String className) + private int overrideMethods(ClassFile cf, ConstPool cp, String className, ArrayList forwarders) throws CannotCompileException { String prefix = makeUniqueName("_d", signatureMethods); @@ -938,7 +984,7 @@ public class ProxyFactory { int mod = meth.getModifiers(); if (testBit(signature, index)) { override(className, meth, prefix, index, - keyToDesc(key, meth), cf, cp); + keyToDesc(key, meth), cf, cp, forwarders); } index++; } @@ -947,7 +993,7 @@ public class ProxyFactory { } private void override(String thisClassname, Method meth, String prefix, - int index, String desc, ClassFile cf, ConstPool cp) + int index, String desc, ClassFile cf, ConstPool cp, ArrayList forwarders) throws CannotCompileException { Class declClass = meth.getDeclaringClass(); @@ -964,7 +1010,7 @@ public class ProxyFactory { MethodInfo forwarder = makeForwarder(thisClassname, meth, desc, cp, declClass, - delegatorName, index); + delegatorName, index, forwarders); cf.addMethod(forwarder); } @@ -1154,7 +1200,8 @@ public class ProxyFactory { */ private static MethodInfo makeForwarder(String thisClassName, Method meth, String desc, ConstPool cp, - Class declClass, String delegatorName, int index) { + Class declClass, String delegatorName, int index, + ArrayList forwarders) { MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc); forwarder.setAccessFlags(Modifier.FINAL | (meth.getModifiers() & ~(Modifier.ABSTRACT @@ -1164,13 +1211,14 @@ public class ProxyFactory { int args = Descriptor.paramSize(desc); Bytecode code = new Bytecode(cp, 0, args + 2); /* - * if (methods[index * 2] == null) { + * static { * methods[index * 2] * = RuntimeSupport.findSuperMethod(this, , ); * methods[index * 2 + 1] * = RuntimeSupport.findMethod(this, , ); * or = null // the original method is abstract. * } + * : * return ($r)handler.invoke(this, methods[index * 2], * methods[index * 2 + 1], $args); */ @@ -1180,7 +1228,7 @@ public class ProxyFactory { code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE); code.addAstore(arrayVar); - callFind2Methods(code, meth.getName(), delegatorName, origIndex, desc, arrayVar); + forwarders.add(new Find2MethodsArgs(meth.getName(), delegatorName, desc, origIndex)); code.addAload(0); code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE); @@ -1207,6 +1255,18 @@ public class ProxyFactory { return forwarder; } + static class Find2MethodsArgs { + String methodName, delegatorName, descriptor; + int origIndex; + + Find2MethodsArgs(String mname, String dname, String desc, int index) { + methodName = mname; + delegatorName = dname; + descriptor = desc; + origIndex = index; + } + } + private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) { Class[] exceptions = orig.getExceptionTypes(); setThrows(minfo, cp, exceptions); @@ -1313,28 +1373,6 @@ public class ProxyFactory { return regno + FactoryHelper.dataSize[index]; } - /** - * @param thisMethod might be null. - */ - private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod, - int index, String desc, int arrayVar) { - String findClass = RuntimeSupport.class.getName(); - String findDesc - = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V"; - - code.addAload(0); - code.addLdc(superMethod); - if (thisMethod == null) - code.addOpcode(Opcode.ACONST_NULL); - else - code.addLdc(thisMethod); - - code.addIconst(index); - code.addLdc(desc); - code.addAload(arrayVar); - code.addInvokestatic(findClass, "find2Methods", findDesc); - } - private static void addUnwrapper(Bytecode code, Class type) { if (type.isPrimitive()) { if (type == Void.TYPE) diff --git a/src/main/javassist/util/proxy/RuntimeSupport.java b/src/main/javassist/util/proxy/RuntimeSupport.java index 48cacecd..4c5d8996 100644 --- a/src/main/javassist/util/proxy/RuntimeSupport.java +++ b/src/main/javassist/util/proxy/RuntimeSupport.java @@ -46,24 +46,13 @@ public class RuntimeSupport { * @throws RuntimeException if the methods are not found. * @see javassist.util.proxy.ProxyFactory */ - public static void find2Methods(Object self, String superMethod, + public static void find2Methods(Class clazz, String superMethod, String thisMethod, int index, String desc, java.lang.reflect.Method[] methods) { - /* Once methods[index] and methods[index + 1] are set to non-null, - * then their values never change. - */ - if (methods[index] == null || methods[index + 1] == null) { - Method m1 = thisMethod == null ? null - : findMethod(self, thisMethod, desc); - Method m0 = findSuperMethod(self, superMethod, desc); - synchronized (methods) { - if (methods[index] == null) { - methods[index + 1] = m1; - methods[index] = m0; - } - } - } + methods[index + 1] = thisMethod == null ? null + : findMethod(clazz, thisMethod, desc); + methods[index] = findSuperMethod(clazz, superMethod, desc); } /** @@ -72,10 +61,10 @@ public class RuntimeSupport { * * @throws RuntimeException if the method is not found. */ - public static Method findMethod(Object self, String name, String desc) { - Method m = findMethod2(self.getClass(), name, desc); + public static Method findMethod(Class clazz, String name, String desc) { + Method m = findMethod2(clazz, name, desc); if (m == null) - error(self, name, desc); + error(clazz, name, desc); return m; } @@ -86,21 +75,20 @@ public class RuntimeSupport { * * @throws RuntimeException if the method is not found. */ - public static Method findSuperMethod(Object self, String name, String desc) { - Class clazz = self.getClass(); + public static Method findSuperMethod(Class clazz, String name, String desc) { Method m = findSuperMethod2(clazz.getSuperclass(), name, desc); if (m == null) m = searchInterfaces(clazz, name, desc); if (m == null) - error(self, name, desc); + error(clazz, name, desc); return m; } - private static void error(Object self, String name, String desc) { + private static void error(Class clazz, String name, String desc) { throw new RuntimeException("not found " + name + ":" + desc - + " in " + self.getClass().getName()); + + " in " + clazz.getName()); } private static Method findSuperMethod2(Class clazz, String name, String desc) { diff --git a/src/test/javassist/JvstTest.java b/src/test/javassist/JvstTest.java index 4e22dbc1..596d62e2 100644 --- a/src/test/javassist/JvstTest.java +++ b/src/test/javassist/JvstTest.java @@ -1116,14 +1116,14 @@ public class JvstTest extends JvstTestRoot { suite.addTestSuite(javassist.bytecode.InsertGap0.class); suite.addTestSuite(javassist.tools.reflect.LoaderTest.class); suite.addTestSuite(testproxy.ProxyTester.class); - // suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class); + suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class); // remove? suite.addTestSuite(javassist.proxyfactory.ProxyFactoryTest.class); suite.addTestSuite(javassist.proxyfactory.Tester.class); suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class); suite.addTestSuite(test.javassist.convert.ArrayAccessReplaceTest.class); suite.addTestSuite(test.javassist.proxy.JASSIST113RegressionTest.class); suite.addTestSuite(test.javassist.proxy.JBPAPP9257Test.class); - //suite.addTestSuite(test.javassist.proxy.ProxyCacheGCTest.class); + suite.addTestSuite(test.javassist.proxy.ProxyCacheGCTest.class); // remvoe? suite.addTestSuite(test.javassist.proxy.ProxyFactoryCompatibilityTest.class); suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class); suite.addTestSuite(test.javassist.proxy.ProxySimpleTest.class); diff --git a/src/test/javassist/proxyfactory/ProxyFactoryTest.java b/src/test/javassist/proxyfactory/ProxyFactoryTest.java index 7224eb50..232a0165 100644 --- a/src/test/javassist/proxyfactory/ProxyFactoryTest.java +++ b/src/test/javassist/proxyfactory/ProxyFactoryTest.java @@ -12,8 +12,6 @@ import java.lang.reflect.Method; * Mark Struberg */ public class ProxyFactoryTest extends TestCase { - - public void testMethodHandlers() throws Exception { ProxyFactory fact = new ProxyFactory(); fact.setSuperclass(MyCls.class); diff --git a/src/test/test/javassist/proxy/ProxySimpleTest.java b/src/test/test/javassist/proxy/ProxySimpleTest.java index f74fce45..cab62397 100644 --- a/src/test/test/javassist/proxy/ProxySimpleTest.java +++ b/src/test/test/javassist/proxy/ProxySimpleTest.java @@ -9,9 +9,47 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Method; +import javassist.util.proxy.MethodFilter; +import javassist.util.proxy.MethodHandler; +import javassist.util.proxy.Proxy; import javassist.util.proxy.ProxyFactory; public class ProxySimpleTest extends TestCase { + + String testResult; + + public void testProxyFactory() throws Exception { + ProxyFactory f = new ProxyFactory(); + f.writeDirectory = "./proxy"; + f.setSuperclass(Foo.class); + f.setFilter(new MethodFilter() { + public boolean isHandled(Method m) { + return m.getName().startsWith("f"); + } + }); + Class c = f.createClass(); + MethodHandler mi = new MethodHandler() { + public Object invoke(Object self, Method m, Method proceed, + Object[] args) throws Throwable { + testResult += args[0].toString(); + return proceed.invoke(self, args); // execute the original method. + } + }; + Foo foo = (Foo)c.newInstance(); + ((Proxy)foo).setHandler(mi); + testResult = ""; + foo.foo(1); + foo.foo2(2); + foo.bar(3); + assertEquals("12", testResult); + } + + public static class Foo { + public int foo(int i) { return i + 1; } + public int foo2(int i) { return i + 2; } + public int bar(int i) { return i + 1; } + } + public void testReadWrite() throws Exception { final String fileName = "read-write.bin"; ProxyFactory.ClassLoaderProvider cp = ProxyFactory.classLoaderProvider; -- cgit v1.2.3