Author: niallp Date: Thu Aug 28 07:12:13 2008 New Revision: 689831 URL: http://svn.apache.org/viewvc?rev=689831&view=rev Log: BEANUTILS-291 - Re-create class reference if lost - fixes problem on JRockit JDK - thanks to Jörg Schaible
Modified: commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/memoryleaktests/MemoryLeakTestCase.java Modified: commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java?rev=689831&r1=689830&r2=689831&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java (original) +++ commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java Thu Aug 28 07:12:13 2008 @@ -452,6 +452,12 @@ if (m == null) { Class clazz = (Class)classRef.get(); if (clazz == null) { + clazz = reLoadClass(); + if (clazz != null) { + classRef = new WeakReference(clazz); + } + } + if (clazz == null) { throw new RuntimeException("Method " + methodName + " for " + className + " could not be reconstructed - class reference has gone"); } @@ -473,5 +479,29 @@ } return m; } + + /** + * Try to re-load the class + */ + private Class reLoadClass() { + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + // Try the context class loader + if (classLoader != null) { + try { + return classLoader.loadClass(className); + } catch (Throwable t) { + // ignore + } + } + + // Try this class's class loader + try { + return classLoader.loadClass(className); + } catch (Throwable t) { + return null; + } + } } } Modified: commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/memoryleaktests/MemoryLeakTestCase.java URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/memoryleaktests/MemoryLeakTestCase.java?rev=689831&r1=689830&r2=689831&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/memoryleaktests/MemoryLeakTestCase.java (original) +++ commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/memoryleaktests/MemoryLeakTestCase.java Thu Aug 28 07:12:13 2008 @@ -155,7 +155,7 @@ * Tests that MappedPropertyDescriptor can re-create the Method reference after it * has been garbage collected. */ - public void testMappedPropertyDescriptor_MappedMethodReference() throws Exception { + public void testMappedPropertyDescriptor_MappedMethodReference1() throws Exception { // Clear All BeanUtils caches before the test clearAllBeanUtilsCaches(); @@ -196,6 +196,55 @@ } /** + * Tests that MappedPropertyDescriptor can re-create the Method reference after it + * has been garbage collected. + */ + public void testMappedPropertyDescriptor_MappedMethodReference2() throws Exception { + + // Clear All BeanUtils caches before the test + clearAllBeanUtilsCaches(); + + String className = "org.apache.commons.beanutils.memoryleaktests.pojotests.SomeMappedPojo"; + ClassLoader loader = newClassLoader(); + Class beanClass = loader.loadClass(className); + Object bean = beanClass.newInstance(); + // ----------------------------------------------------------------------------- + + // Sanity checks only + assertNotNull("ClassLoader is null", loader); + assertNotNull("BeanClass is null", beanClass); + assertNotSame("ClassLoaders should be different..", getClass().getClassLoader(), beanClass.getClassLoader()); + assertSame("BeanClass ClassLoader incorrect", beanClass.getClassLoader(), loader); + + MappedPropertyDescriptor descriptor = new MappedPropertyDescriptor("mappedProperty", beanClass); + assertNotNull("1-Read Method null", descriptor.getMappedReadMethod()); + assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod()); + assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName()); + assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName()); + + // this should make the reference go away. + loader = null; + beanClass = null; + bean = null; + + forceGarbageCollection(); /* Try to force the garbage collector to run by filling up memory */ + + // The aim of this test is to check the functinality in MappedPropertyDescriptor which + // re-creates the Method references after they have been garbage collected. However theres no + // way of knowing the method references were garbage collected and that code was run, except by + // un-commeting the System.out statement in MappedPropertyDescriptor's MappedMethodReference's + // get() method. + + assertNotNull("1-Read Method null", descriptor.getMappedReadMethod()); + assertNotNull("1-Write Method null", descriptor.getMappedWriteMethod()); + assertEquals("1-Read Method name", "getMappedProperty", descriptor.getMappedReadMethod().getName()); + assertEquals("1-Read Write name", "setMappedProperty", descriptor.getMappedWriteMethod().getName()); + + // Clear All BeanUtils caches after the test + clearAllBeanUtilsCaches(); + } + + /** * Tests that MethodUtils's cache doesn't cause a memory leak. */ public void testMethodUtils_cache_memoryLeak() throws Exception {