You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by df...@apache.org on 2009/02/24 18:31:00 UTC

svn commit: r747449 - in /commons/sandbox/dbutils/bugfixing/src: java/org/apache/commons/dbutils/QueryRunner.java test/org/apache/commons/dbutils/QueryRunnerTest.java

Author: dfabulich
Date: Tue Feb 24 17:30:59 2009
New Revision: 747449

URL: http://svn.apache.org/viewvc?rev=747449&view=rev
Log:
fillStatementWithBean: tweaked exception handling, added unit test

Added:
    commons/sandbox/dbutils/bugfixing/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
Modified:
    commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/QueryRunner.java

Modified: commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/QueryRunner.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/QueryRunner.java?rev=747449&r1=747448&r2=747449&view=diff
==============================================================================
--- commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/QueryRunner.java (original)
+++ commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/QueryRunner.java Tue Feb 24 17:30:59 2009
@@ -19,6 +19,8 @@
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.sql.Connection;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
@@ -212,16 +214,19 @@
         for (int i = 0; i < properties.length; i++) {
             PropertyDescriptor property = properties[i];
             Object value = null;
+            Method method = property.getReadMethod();
+            if (method == null)
+                throw new RuntimeException("No read method for bean property "
+                        + bean.getClass() + " " + property.getName());
             try {
-                if (property.getReadMethod().getParameterTypes().length > 0) {
-                    throw new SQLException(
-                            "Can't use an indexed bean property as a SQL parameter: "
-                                    + property.getName());
-                }
-                value = property.getReadMethod().invoke(bean, new Object[0]);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
+                value = method.invoke(bean, new Object[0]);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException("Couldn't invoke method: " + method, e);
+            } catch (IllegalArgumentException e) {
+                throw new RuntimeException("Couldn't invoke method with 0 arguments: " + method, e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("Couldn't invoke method: " + method, e);
+            } 
             params[i] = value;
         }
         fillStatement(stmt, params);
@@ -249,14 +254,13 @@
             descriptors = Introspector.getBeanInfo(bean.getClass())
                     .getPropertyDescriptors();
         } catch (IntrospectionException e) {
-            throw new RuntimeException(e);
+            throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e);
         }
         PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
         for (int i = 0; i < propertyNames.length; i++) {
             String propertyName = propertyNames[i];
             if (propertyName == null)
-                throw new NullPointerException("propertyName can't be null: "
-                        + i);
+                throw new NullPointerException("propertyName can't be null: " + i);
             boolean found = false;
             for (int j = 0; j < descriptors.length; j++) {
                 PropertyDescriptor descriptor = descriptors[j];

Added: commons/sandbox/dbutils/bugfixing/src/test/org/apache/commons/dbutils/QueryRunnerTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/bugfixing/src/test/org/apache/commons/dbutils/QueryRunnerTest.java?rev=747449&view=auto
==============================================================================
--- commons/sandbox/dbutils/bugfixing/src/test/org/apache/commons/dbutils/QueryRunnerTest.java (added)
+++ commons/sandbox/dbutils/bugfixing/src/test/org/apache/commons/dbutils/QueryRunnerTest.java Tue Feb 24 17:30:59 2009
@@ -0,0 +1,124 @@
+package org.apache.commons.dbutils;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class QueryRunnerTest extends TestCase {
+    QueryRunner runner;
+    PreparedStatement stmt;
+    
+    public void setUp() {
+        runner = new QueryRunner();
+        stmt = fakePreparedStatement();
+    }
+    
+    public void testFillStatementWithBean() throws SQLException {
+        TestBean tb = new TestBean();
+        tb.setOne("uno");
+        tb.setTwo("dos");
+        tb.setThree("tres");
+        NoOpFillStatement fakeQueryRunner = new NoOpFillStatement();
+        fakeQueryRunner.fillStatementWithBean(stmt, tb, new String[] {"three", "two", "one"});
+        String[] expected = new String[] {"tres", "dos", "uno"};
+        assertArrayEquals("Statement filled with incorrect parameters", expected, fakeQueryRunner.params);
+    }
+
+    private PreparedStatement fakePreparedStatement() {
+        InvocationHandler noOpHandler = new InvocationHandler() {
+            public Object invoke(Object proxy, Method method, Object[] args)
+                    throws Throwable {
+                return null;
+            }
+        };
+        PreparedStatement stmt = ProxyFactory.instance().createPreparedStatement(noOpHandler);
+        return stmt;
+    }
+    
+    public void testFillStatementWithBeanErrorNoReadMethod() throws Exception {
+        TestBean tb = new TestBean();
+        PropertyDescriptor noReadMethod = new PropertyDescriptor("one", TestBean.class, null, "setOne");
+        
+        PropertyDescriptor properties[] = new PropertyDescriptor[] { noReadMethod };
+        try {
+            runner.fillStatementWithBean(stmt, tb, properties);
+            fail("Expected RuntimeException: tried to use a property with no read method");
+        } catch (RuntimeException expected) {}
+    }
+    
+    public void testFillStatementWithBeanErrorBadReadMethod() throws Exception {
+        PropertyDescriptor badReadMethod = new IndexedPropertyDescriptor("indexed", getClass(), null, null, "getIndexed", null) {
+            public synchronized Method getReadMethod() {
+                return super.getIndexedReadMethod();
+            }
+        };
+        PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
+        try {
+            runner.fillStatementWithBean(stmt, this, properties);
+            fail("Expected RuntimeException: tried to use a property with no no-arg read method");
+        } catch (RuntimeException expected) {}
+    }
+    
+    public void testFillStatementWithBeanErrorReadMethodThrows() throws Exception {
+        PropertyDescriptor badReadMethod = new PropertyDescriptor("throwsException", getClass(), "getThrowsException", null);
+        PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
+        try {
+            runner.fillStatementWithBean(stmt, this, properties);
+            fail("Expected RuntimeException: tried to call a method that throws");
+        } catch (RuntimeException expected) {}
+    }
+    
+    public void testFillStatementWithBeanErrorReadMethodPrivate() throws Exception {
+        getPrivate();
+        Method getPrivate = getClass().getDeclaredMethod("getPrivate", new Class[0]);
+        PropertyDescriptor badReadMethod = new PropertyDescriptor("throwsException", getPrivate, null);
+        PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
+        try {
+            runner.fillStatementWithBean(stmt, this, properties);
+            fail("Expected RuntimeException: tried to call a private method");
+        } catch (RuntimeException expected) {}
+    }
+    
+    public void testRethrowNullMessage() throws SQLException {
+        // DBUTILS-40
+        SQLException sqe = new SQLException((String)null);
+        QueryRunner qr = new QueryRunner();
+        try {
+            qr.rethrow(sqe, "foo", new Object[] {"bar"});
+            fail("rethrow didn't throw");
+        } catch (SQLException expected) {};
+    }
+    
+    // indexed bean property
+    public String getIndexed(int index) {
+        return null;
+    }
+    
+    public String getThrowsException() {
+        throw new RuntimeException("this getter always throws an exception");
+    }
+    
+    private String getPrivate() {
+        return null;
+    }
+    
+    private void assertArrayEquals(String message, Object[] expected, Object[] actual) {
+        assertEquals(message, Arrays.asList(expected).toString(), Arrays.asList(actual).toString());
+        assertEquals(message, expected.length, actual.length);
+    }
+    
+    
+    private class NoOpFillStatement extends QueryRunner {
+        Object[] params;
+        public void fillStatement(PreparedStatement stmt, Object[] params)
+                throws SQLException {
+            this.params = params;
+        }
+    }
+}