Author: niallp Date: Mon May 21 16:36:17 2007 New Revision: 540362 URL: http://svn.apache.org/viewvc?view=rev&rev=540362 Log: Fix for BEANUTILS-266 Log or throw exception in PropertyUtilsBean - thanks to Brian Ewins and Commons HttpClient. Added mechanism to initialize the "cause" on an Exception using reflection (copied from Commons HttpClient).
Modified: jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtils.java jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtilsBean.java jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java jakarta/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java Modified: jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtils.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtils.java?view=diff&rev=540362&r1=540361&r2=540362 ============================================================================== --- jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtils.java (original) +++ jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtils.java Mon May 21 16:36:17 2007 @@ -455,4 +455,15 @@ BeanUtilsBean.getInstance().setProperty(bean, name, value); } + + /** + * If we're running on JDK 1.4 or later, initialize the cause for the given throwable. + * + * @param throwable The throwable. + * @param cause The cause of the throwable. + * @return true if the cause was initialized, otherwise false. + */ + public static boolean initCause(Throwable throwable, Throwable cause) { + return BeanUtilsBean.getInstance().initCause(throwable, cause); + } } Modified: jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtilsBean.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtilsBean.java?view=diff&rev=540362&r1=540361&r2=540362 ============================================================================== --- jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtilsBean.java (original) +++ jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/BeanUtilsBean.java Mon May 21 16:36:17 2007 @@ -23,6 +23,7 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -103,6 +104,9 @@ /** Used to access properties*/ private PropertyUtilsBean propertyUtilsBean; + /** A reference to Throwable's initCause method, or null if it's not there in this JVM */ + private static final Method INIT_CAUSE_METHOD = getInitCauseMethod(); + // --------------------------------------------------------- Constuctors /** @@ -1028,5 +1032,51 @@ */ public PropertyUtilsBean getPropertyUtils() { return propertyUtilsBean; + } + + /** + * If we're running on JDK 1.4 or later, initialize the cause for the given throwable. + * + * @param throwable The throwable. + * @param cause The cause of the throwable. + * @return true if the cause was initialized, otherwise false. + */ + public boolean initCause(Throwable throwable, Throwable cause) { + if (INIT_CAUSE_METHOD != null && cause != null) { + try { + INIT_CAUSE_METHOD.invoke(throwable, new Object[] { cause }); + return true; + } catch (Throwable e) { + } + } + return false; + } + + /** + * Returns a <code>Method<code> allowing access to + * [EMAIL PROTECTED] Throwable#initCause(Throwable)} method of [EMAIL PROTECTED] Throwable}, + * or <code>null</code> if the method + * does not exist. + * + * @return A <code>Method<code> for <code>Throwable.initCause</code>, or + * <code>null</code> if unavailable. + */ + private static Method getInitCauseMethod() { + try { + Class[] paramsClasses = new Class[] { Throwable.class }; + return Throwable.class.getMethod("initCause", paramsClasses); + } catch (NoSuchMethodException e) { + Log log = LogFactory.getLog(BeanUtils.class); + if (log.isWarnEnabled()) { + log.warn("Throwable does not have initCause() method in JDK 1.3"); + } + return null; + } catch (Throwable e) { + Log log = LogFactory.getLog(BeanUtils.class); + if (log.isWarnEnabled()) { + log.warn("Error getting the Throwable initCause() method", e); + } + return null; + } } } Modified: jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java?view=diff&rev=540362&r1=540361&r2=540362 ============================================================================== --- jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java (original) +++ jakarta/commons/proper/beanutils/trunk/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java Mon May 21 16:36:17 2007 @@ -2001,7 +2001,7 @@ return method.invoke(bean, values); - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException cause) { if(bean == null) { throw new IllegalArgumentException("No bean specified " + "- this should have been checked before reaching this method"); @@ -2025,16 +2025,19 @@ expectedString += parTypes[i].getName(); } } - log.error("Method invocation failed", e); - throw new IllegalArgumentException( + IllegalArgumentException e = new IllegalArgumentException( "Cannot invoke " + method.getDeclaringClass().getName() + "." + method.getName() + " on bean class '" + bean.getClass() + - "' - " + e.getMessage() + "' - " + cause.getMessage() // as per https://issues.apache.org/jira/browse/BEANUTILS-224 + " - had objects of type \"" + valueString + "\" but expected signature \"" + expectedString + "\"" ); + if (!BeanUtils.initCause(e, cause)) { + log.error("Method invocation failed", cause); + } + throw e; } } Modified: jakarta/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java?view=diff&rev=540362&r1=540361&r2=540362 ============================================================================== --- jakarta/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java (original) +++ jakarta/commons/proper/beanutils/trunk/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java Mon May 21 16:36:17 2007 @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.StringTokenizer; import junit.framework.Test; import junit.framework.TestCase; @@ -1367,4 +1368,72 @@ "some.dotty.value", bean.getMapproperty("this.that.the-other")); } + + /** + * Test for [EMAIL PROTECTED] BeanUtilsBean#initCause(Throwable, Throwable)} method. + */ + public void testInitCause() { + if (isPre14JVM()) { + return; + } + String parentMsg = "PARENT-THROWABLE"; + String causeMsg = "THROWABLE-CAUSE"; + try { + initCauseAndThrowException(parentMsg, causeMsg); + } catch (Throwable thrownParent) { + assertEquals("Parent", parentMsg, thrownParent.getMessage()); + try { + assertEquals("Parent", parentMsg, thrownParent.getMessage()); + Throwable thrownCause = getCause(thrownParent); + assertNotNull("Cause Null", thrownCause); + assertEquals("Cause", causeMsg, thrownCause.getMessage()); + } catch (Throwable testError) { + fail("If you're running JDK 1.3 then don't worry this should fail," + + " if not then needs checking out: " + testError); + } + } + } + + /** + * Use reflection to get the cause + */ + private Throwable getCause(Throwable t) throws Throwable { + return (Throwable)PropertyUtils.getProperty(t, "cause"); + } + + /** + * Catch a cause, initialize using BeanUtils.initCause() and throw new exception + */ + private void initCauseAndThrowException(String parent, String cause) throws Throwable { + try { + throwException(cause); + } catch (Throwable e) { + Throwable t = new Exception(parent); + BeanUtils.initCause(t, e); + throw t; + } + } + + /** + * Throw an exception with the specified message. + */ + private void throwException(String msg) throws Throwable { + throw new Exception(msg); + } + + /** + * Test for JDK 1.4 + */ + private boolean isPre14JVM() { + String version = System.getProperty("java.specification.version"); + StringTokenizer tokenizer = new StringTokenizer(version,"."); + if (tokenizer.nextToken().equals("1")) { + String minorVersion = tokenizer.nextToken(); + if (minorVersion.equals("0")) return true; + if (minorVersion.equals("1")) return true; + if (minorVersion.equals("2")) return true; + if (minorVersion.equals("3")) return true; + } + return false; + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]