package test.javassist.proxy; import javassist.*; import javassist.util.proxy.MethodFilter; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; import junit.framework.TestCase; /** * test which checks that proxy classes are not retained after their classloader is released. * this is a before and after test which validates JASSIST-104 */ @SuppressWarnings({"rawtypes","unchecked"}) public class ProxyCacheGCTest extends TestCase { /** * creates a large number of proxies in separate classloaders then lets go of the classloaders and * forces a GC. If we run out of heap then we know there is a problem. */ public final static int REPETITION_COUNT = 10000; private ClassPool basePool; private CtClass baseHandler; private CtClass baseFilter; protected void setUp() { basePool = ClassPool.getDefault(); try { baseHandler = basePool.get("javassist.util.proxy.MethodHandler"); baseFilter = basePool.get("javassist.util.proxy.MethodFilter"); } catch (NotFoundException e) { e.printStackTrace(); fail("could not find class " + e); } } public void testCacheGC() { ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); try { ProxyFactory.useCache = false; for (int i = 0; i < REPETITION_COUNT; i++) { ClassLoader newCL = new TestLoader(); try { Thread.currentThread().setContextClassLoader(newCL); createProxy(i); } finally { Thread.currentThread().setContextClassLoader(oldCL); } } } finally { ProxyFactory.useCache = true; } } /** * called when a specific classloader is in place on the thread to create a method handler, method filter * and proxy in the current loader and then */ public void createProxy(int counter) { try { ClassPool classPool = new ClassPool(basePool); // create a target class in the current class loader String targetName = "test.javassist.MyTarget_" + counter; String targetConstructorName = "MyTarget_" + counter; CtClass ctTargetClass = classPool.makeClass(targetName); CtMethod targetMethod = CtNewMethod.make("public Object test() { return this; }", ctTargetClass); ctTargetClass.addMethod(targetMethod); CtConstructor targetConstructor = CtNewConstructor.make("public " + targetConstructorName + "() { }", ctTargetClass); ctTargetClass.addConstructor(targetConstructor); // create a handler in the current classloader String handlerName = "test.javassist.MyHandler_" + counter; CtClass ctHandlerClass = classPool.makeClass(handlerName); ctHandlerClass.addInterface(baseHandler); CtMethod handlerInvoke = CtNewMethod.make("public Object invoke(Object self, java.lang.reflect.Method thisMethod, java.lang.reflect.Method proceed, Object[] args) throws Throwable { return proceed.invoke(self, args); }", ctHandlerClass); ctHandlerClass.addMethod(handlerInvoke); // create a filter in the current classloader String filterName = "test.javassist.MyFilter" + counter; CtClass ctFilterClass = classPool.makeClass(filterName); ctFilterClass.addInterface(baseFilter); CtMethod filterIsHandled = CtNewMethod.make("public boolean isHandled(java.lang.reflect.Method m) { return true; }", ctFilterClass); ctFilterClass.addMethod(filterIsHandled); // now create a proxyfactory and use it to create a proxy ProxyFactory factory = new ProxyFactory(); Class javaTargetClass = classPool.toClass(ctTargetClass, test.javassist.DefineClassCapability.class); Class javaHandlerClass = classPool.toClass(ctHandlerClass, test.javassist.DefineClassCapability.class); Class javaFilterClass = classPool.toClass(ctFilterClass, test.javassist.DefineClassCapability.class); MethodHandler handler= (MethodHandler)javaHandlerClass.getConstructor().newInstance(); MethodFilter filter = (MethodFilter)javaFilterClass.getConstructor().newInstance(); // ok, now create a factory and a proxy class and proxy from that factory factory.setFilter(filter); factory.setSuperclass(javaTargetClass); // factory.setSuperclass(Object.class); Class proxyClass = factory.createClass(); Object target = proxyClass.getConstructor().newInstance(); ((ProxyObject)target).setHandler(handler); } catch (Exception e) { e.printStackTrace(); fail("cannot create proxy " + e); } } /** * a classloader which inherits from the system class loader and within which a proxy handler, * filter and proxy will be located. */ public static class TestLoader extends ClassLoader { } }