Author: niallp Date: Fri Sep 10 12:19:08 2010 New Revision: 995768 URL: http://svn.apache.org/viewvc?rev=995768&view=rev Log: BEANUTILS-380 BeanMap methods should initialize the root cause of exceptions that are thrown when running on JDK 1.4+ - thanks to Brendan Nolan
Modified: commons/proper/beanutils/trunk/src/changes/changes.xml commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanMap.java commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanMapTestCase.java commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanUtilsTestCase.java Modified: commons/proper/beanutils/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/changes/changes.xml?rev=995768&r1=995767&r2=995768&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/changes/changes.xml (original) +++ commons/proper/beanutils/trunk/src/changes/changes.xml Fri Sep 10 12:19:08 2010 @@ -39,6 +39,13 @@ The <action> type attribute can be add,u </properties> <body> + <release version="1.8.4" date="in SVN" description="Bug fix for 1.8.3"> + <action dev="niallp" type="fix" issue="BEANUTILS-380" due-to="Brendan Nolan"> + BeanMap methods should initialize the root cause of exceptions that are thrown + when running on JDK 1.4+ + </action> + </release> + <release version="1.8.3" date="2010-03-28" description="Bug fix for 1.8.2"> <action dev="niallp" type="fix" issue="BEANUTILS-373" due-to="Andrew Sunde"> MethodUtils is not thread safe because WeakFastHashMap which uses WeakHashMap is not thread-safe Modified: commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanMap.java URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanMap.java?rev=995768&r1=995767&r2=995768&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanMap.java (original) +++ commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanMap.java Fri Sep 10 12:19:08 2010 @@ -261,17 +261,21 @@ public class BeanMap extends AbstractMap newBean = beanClass.newInstance(); } catch (Exception e) { // unable to instantiate - throw new CloneNotSupportedException + CloneNotSupportedException cnse = new CloneNotSupportedException ("Unable to instantiate the underlying bean \"" + beanClass.getName() + "\": " + e); + BeanUtils.initCause(cnse, e); + throw cnse; } try { newMap.setBean(newBean); } catch (Exception exception) { - throw new CloneNotSupportedException + CloneNotSupportedException cnse = new CloneNotSupportedException ("Unable to set bean in the cloned bean map: " + exception); + BeanUtils.initCause(cnse, exception); + throw cnse; } try { @@ -286,9 +290,11 @@ public class BeanMap extends AbstractMap } } } catch (Exception exception) { - throw new CloneNotSupportedException + CloneNotSupportedException cnse = new CloneNotSupportedException ("Unable to copy bean values to cloned bean map: " + exception); + BeanUtils.initCause(cnse, exception); + throw cnse; } return newMap; @@ -330,7 +336,10 @@ public class BeanMap extends AbstractMap bean = beanClass.newInstance(); } catch (Exception e) { - throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass ); + UnsupportedOperationException uoe = + new UnsupportedOperationException("Could not create new instance of class: " + beanClass); + BeanUtils.initCause(uoe, e); + throw uoe; } } @@ -434,12 +443,18 @@ public class BeanMap extends AbstractMap firePropertyChange( name, oldValue, newValue ); } catch ( InvocationTargetException e ) { - logInfo( e ); - throw new IllegalArgumentException( e.getMessage() ); + IllegalArgumentException iae = new IllegalArgumentException(e.getMessage()); + if (BeanUtils.initCause(iae, e) == false) { + logInfo(e); + } + throw iae; } catch ( IllegalAccessException e ) { - logInfo( e ); - throw new IllegalArgumentException( e.getMessage() ); + IllegalArgumentException iae = new IllegalArgumentException(e.getMessage()); + if (BeanUtils.initCause(iae, e) == false) { + logInfo(e); + } + throw iae; } return oldValue; } @@ -771,12 +786,19 @@ public class BeanMap extends AbstractMap return answer; } catch ( InvocationTargetException e ) { - logInfo( e ); - throw new IllegalArgumentException( e.getMessage() ); + IllegalArgumentException iae = new IllegalArgumentException(e.getMessage()); + if (BeanUtils.initCause(iae, e) == false) { + logInfo(e); + } + throw iae; } catch ( InstantiationException e ) { - logInfo( e ); - throw new IllegalArgumentException( e.getMessage() ); + IllegalArgumentException iae = new IllegalArgumentException(e.getMessage()); + if (BeanUtils.initCause(iae, e) == false) { + logInfo(e); + } + BeanUtils.initCause(iae, e); + throw iae; } } Modified: commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanMapTestCase.java URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanMapTestCase.java?rev=995768&r1=995767&r2=995768&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanMapTestCase.java (original) +++ commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanMapTestCase.java Fri Sep 10 12:19:08 2010 @@ -17,6 +17,7 @@ package org.apache.commons.beanutils; import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.HashMap; @@ -24,6 +25,7 @@ import java.util.HashMap; import junit.framework.Test; import junit.textui.TestRunner; +import org.apache.commons.beanutils.bugs.other.Jira87BeanFactory; import org.apache.commons.collections.map.AbstractTestMap; import org.apache.commons.collections.BulkTest; import org.apache.commons.collections.Transformer; @@ -151,6 +153,23 @@ public class BeanMapTestCase extends Abs someObject = value; } } + + public static class BeanThrowingExceptions extends BeanWithProperties { + private static final long serialVersionUID = 1L; + public void setValueThrowingException(String value) { + throw new TestException(); + } + public String getValueThrowingException() { + throw new TestException(); + } + } + + /** + * Exception for testing exception handling. + */ + public static class TestException extends RuntimeException { + private static final long serialVersionUID = 1L; + } // note to self. The Sample keys were generated by copying the field // declarations and using the following regular expression search and replace: @@ -413,5 +432,105 @@ public class BeanMapTestCase extends Abs // expected result } } - + + /** + * Test that the cause of exception thrown by a clone() is initialised. + */ + public void testExceptionThrowFromClone() { + + if (BeanUtilsTestCase.isPre14JVM()) { + System.out.println("testExceptionThrowFromClone() skipped on pre 1.4 JVM"); + return; + } + + // Test cloning a non-public bean (instantiation exception) + try { + Object bean = Jira87BeanFactory.createMappedPropertyBean(); + BeanMap map = new BeanMap(bean); + map.clone(); + fail("Non-public bean clone() - expected CloneNotSupportedException"); + } catch (CloneNotSupportedException e) { + Throwable cause = null; + try { + cause = (Throwable)PropertyUtils.getProperty(e, "cause"); + } catch (Exception e2) { + fail("Non-public bean - retrieving the cause threw " + e2); + } + assertNotNull("Non-public bean cause null", cause); + assertEquals("Non-public bean cause", IllegalAccessException.class, cause.getClass()); + } + + // Test cloning a bean that throws exception + try { + BeanMap map = new BeanMap(new BeanThrowingExceptions()); + map.clone(); + fail("Setter Exception clone() - expected CloneNotSupportedException"); + } catch (CloneNotSupportedException e) { + Throwable cause = null; + try { + cause = (Throwable)PropertyUtils.getProperty(e, "cause"); + } catch (Exception e2) { + fail("Setter Exception - retrieving the cause threw " + e2); + } + assertNotNull("Setter Exception cause null", cause); + assertEquals("Setter Exception cause", IllegalArgumentException.class, cause.getClass()); + } + } + + /** + * Test that the cause of exception thrown by clear() is initialised. + */ + public void testExceptionThrowFromClear() { + + if (BeanUtilsTestCase.isPre14JVM()) { + System.out.println("testExceptionThrowFromClear() skipped on pre 1.4 JVM"); + return; + } + + try { + Object bean = Jira87BeanFactory.createMappedPropertyBean(); + BeanMap map = new BeanMap(bean); + map.clear(); + fail("clear() - expected UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + Throwable cause = null; + try { + cause = (Throwable)PropertyUtils.getProperty(e, "cause"); + } catch (Exception e2) { + fail("Retrieving the cause threw " + e2); + } + assertNotNull("Cause null", cause); + assertEquals("Cause", IllegalAccessException.class, cause.getClass()); + } + } + + /** + * Test that the cause of exception thrown by put() is initialised. + */ + public void testExceptionThrowFromPut() { + + if (BeanUtilsTestCase.isPre14JVM()) { + System.out.println("testExceptionThrowFromPut() skipped on pre 1.4 JVM"); + return; + } + + try { + Map map = new BeanMap(new BeanThrowingExceptions()); + map.put("valueThrowingException", "value"); + fail("Setter exception - expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Throwable cause1 = null; + Throwable cause2 = null; + try { + cause1 = (Throwable)PropertyUtils.getProperty(e, "cause"); + cause2 = (Throwable)PropertyUtils.getProperty(e, "cause.cause"); + } catch (Exception e2) { + fail("Setter exception - retrieving the cause threw " + e2); + } + assertNotNull("Setter exception cause 1 null", cause1); + assertEquals("Setter exception cause 1", InvocationTargetException.class, cause1.getClass()); + assertNotNull("Setter exception cause 2 null", cause2); + assertEquals("Setter exception cause 2", TestException.class, cause2.getClass()); + } + } } Modified: commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanUtilsTestCase.java URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanUtilsTestCase.java?rev=995768&r1=995767&r2=995768&view=diff ============================================================================== --- commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanUtilsTestCase.java (original) +++ commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanUtilsTestCase.java Fri Sep 10 12:19:08 2010 @@ -1645,7 +1645,7 @@ public class BeanUtilsTestCase extends T /** * Test for JDK 1.4 */ - private boolean isPre14JVM() { + public static boolean isPre14JVM() { String version = System.getProperty("java.specification.version"); StringTokenizer tokenizer = new StringTokenizer(version,"."); if (tokenizer.nextToken().equals("1")) {