You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ni...@apache.org on 2007/05/22 01:36:17 UTC

svn commit: r540362 - in /jakarta/commons/proper/beanutils/trunk/src: java/org/apache/commons/beanutils/ test/org/apache/commons/beanutils/

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
+     * {@link Throwable#initCause(Throwable)} method of {@link 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 {@link 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: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org