http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/BeanProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/BeanProcessor.java 
b/src/main/java/org/apache/commons/dbutils2/BeanProcessor.java
new file mode 100644
index 0000000..46c089b
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/BeanProcessor.java
@@ -0,0 +1,504 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.beans.BeanInfo;
+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.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * <code>BeanProcessor</code> matches column names to bean property names
+ * and converts <code>ResultSet</code> columns into objects for those bean
+ * properties.  Subclasses should override the methods in the processing chain
+ * to customize behavior.
+ * </p>
+ *
+ * <p>
+ * This class is thread-safe.
+ * </p>
+ *
+ * @see BasicRowProcessor
+ *
+ * @since DbUtils 1.1
+ */
+public class BeanProcessor {
+
+    /**
+     * Special array value used by <code>mapColumnsToProperties</code> that
+     * indicates there is no bean property that matches a column from a
+     * <code>ResultSet</code>.
+     */
+    protected static final int PROPERTY_NOT_FOUND = -1;
+
+    /**
+     * Set a bean's primitive properties to these defaults when SQL NULL
+     * is returned.  These are the same as the defaults that ResultSet get*
+     * methods return in the event of a NULL column.
+     */
+    private static final Map<Class<?>, Object> primitiveDefaults = new 
HashMap<Class<?>, Object>();
+
+    /**
+     * ResultSet column to bean property name overrides.
+     */
+    private final Map<String, String> columnToPropertyOverrides;
+
+    static {
+        primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
+        primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
+        primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
+        primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
+        primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
+        primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
+        primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
+        primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
+    }
+
+    /**
+     * Constructor for BeanProcessor.
+     */
+    public BeanProcessor() {
+        this(new HashMap<String, String>());
+    }
+
+    /**
+     * Constructor for BeanProcessor configured with column to property name 
overrides.
+     *
+     * @param columnToPropertyOverrides ResultSet column to bean property name 
overrides
+     * @since 1.5
+     */
+    public BeanProcessor(Map<String, String> columnToPropertyOverrides) {
+        super();
+        if (columnToPropertyOverrides == null) {
+            throw new IllegalArgumentException("columnToPropertyOverrides map 
cannot be null");
+        }
+        this.columnToPropertyOverrides = columnToPropertyOverrides;
+    }
+
+    /**
+     * Convert a <code>ResultSet</code> row into a JavaBean.  This
+     * implementation uses reflection and <code>BeanInfo</code> classes to
+     * match column names to bean property names.  Properties are matched to
+     * columns based on several factors:
+     * <br/>
+     * <ol>
+     *     <li>
+     *     The class has a writable property with the same name as a column.
+     *     The name comparison is case insensitive.
+     *     </li>
+     *
+     *     <li>
+     *     The column type can be converted to the property's set method
+     *     parameter type with a ResultSet.get* method.  If the conversion 
fails
+     *     (ie. the property was an int and the column was a Timestamp) an
+     *     SQLException is thrown.
+     *     </li>
+     * </ol>
+     *
+     * <p>
+     * Primitive bean properties are set to their defaults when SQL NULL is
+     * returned from the <code>ResultSet</code>.  Numeric fields are set to 0
+     * and booleans are set to false.  Object bean properties are set to
+     * <code>null</code> when SQL NULL is returned.  This is the same behavior
+     * as the <code>ResultSet</code> get* methods.
+     * </p>
+     * @param <T> The type of bean to create
+     * @param rs ResultSet that supplies the bean data
+     * @param type Class from which to create the bean instance
+     * @throws SQLException if a database access error occurs
+     * @return the newly created bean
+     */
+    public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {
+
+        PropertyDescriptor[] props = this.propertyDescriptors(type);
+
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
+
+        return this.createBean(rs, type, props, columnToProperty);
+    }
+
+    /**
+     * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans.
+     * This implementation uses reflection and <code>BeanInfo</code> classes to
+     * match column names to bean property names. Properties are matched to
+     * columns based on several factors:
+     * <br/>
+     * <ol>
+     *     <li>
+     *     The class has a writable property with the same name as a column.
+     *     The name comparison is case insensitive.
+     *     </li>
+     *
+     *     <li>
+     *     The column type can be converted to the property's set method
+     *     parameter type with a ResultSet.get* method.  If the conversion 
fails
+     *     (ie. the property was an int and the column was a Timestamp) an
+     *     SQLException is thrown.
+     *     </li>
+     * </ol>
+     *
+     * <p>
+     * Primitive bean properties are set to their defaults when SQL NULL is
+     * returned from the <code>ResultSet</code>.  Numeric fields are set to 0
+     * and booleans are set to false.  Object bean properties are set to
+     * <code>null</code> when SQL NULL is returned.  This is the same behavior
+     * as the <code>ResultSet</code> get* methods.
+     * </p>
+     * @param <T> The type of bean to create
+     * @param rs ResultSet that supplies the bean data
+     * @param type Class from which to create the bean instance
+     * @throws SQLException if a database access error occurs
+     * @return the newly created List of beans
+     */
+    public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws 
SQLException {
+        List<T> results = new ArrayList<T>();
+
+        if (!rs.next()) {
+            return results;
+        }
+
+        PropertyDescriptor[] props = this.propertyDescriptors(type);
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
+
+        do {
+            results.add(this.createBean(rs, type, props, columnToProperty));
+        } while (rs.next());
+
+        return results;
+    }
+
+    /**
+     * Creates a new object and initializes its fields from the ResultSet.
+     * @param <T> The type of bean to create
+     * @param rs The result set.
+     * @param type The bean type (the return type of the object).
+     * @param props The property descriptors.
+     * @param columnToProperty The column indices in the result set.
+     * @return An initialized object.
+     * @throws SQLException if a database error occurs.
+     */
+    private <T> T createBean(ResultSet rs, Class<T> type,
+            PropertyDescriptor[] props, int[] columnToProperty)
+            throws SQLException {
+
+        T bean = this.newInstance(type);
+
+        for (int i = 1; i < columnToProperty.length; i++) {
+
+            if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
+                continue;
+            }
+
+            PropertyDescriptor prop = props[columnToProperty[i]];
+            Class<?> propType = prop.getPropertyType();
+
+            Object value = this.processColumn(rs, i, propType);
+
+            if (propType != null && value == null && propType.isPrimitive()) {
+                value = primitiveDefaults.get(propType);
+            }
+
+            this.callSetter(bean, prop, value);
+        }
+
+        return bean;
+    }
+
+    /**
+     * Calls the setter method on the target object for the given property.
+     * If no setter method exists for the property, this method does nothing.
+     * @param target The object to set the property on.
+     * @param prop The property to set.
+     * @param value The value to pass into the setter.
+     * @throws SQLException if an error occurs setting the property.
+     */
+    private void callSetter(Object target, PropertyDescriptor prop, Object 
value)
+            throws SQLException {
+
+        Method setter = prop.getWriteMethod();
+
+        if (setter == null) {
+            return;
+        }
+
+        Class<?>[] params = setter.getParameterTypes();
+        try {
+            // convert types for some popular ones
+            if (value instanceof java.util.Date) {
+                final String targetType = params[0].getName();
+                if ("java.sql.Date".equals(targetType)) {
+                    value = new java.sql.Date(((java.util.Date) 
value).getTime());
+                } else
+                if ("java.sql.Time".equals(targetType)) {
+                    value = new java.sql.Time(((java.util.Date) 
value).getTime());
+                } else
+                if ("java.sql.Timestamp".equals(targetType)) {
+                    value = new java.sql.Timestamp(((java.util.Date) 
value).getTime());
+                }
+            }
+
+            // Don't call setter if the value object isn't the right type
+            if (this.isCompatibleType(value, params[0])) {
+                setter.invoke(target, new Object[]{value});
+            } else {
+              throw new SQLException(
+                  "Cannot set " + prop.getName() + ": incompatible types, 
cannot convert "
+                  + value.getClass().getName() + " to " + params[0].getName());
+                  // value cannot be null here because isCompatibleType allows 
null
+            }
+
+        } catch (IllegalArgumentException e) {
+            throw new SQLException(
+                "Cannot set " + prop.getName() + ": " + e.getMessage());
+
+        } catch (IllegalAccessException e) {
+            throw new SQLException(
+                "Cannot set " + prop.getName() + ": " + e.getMessage());
+
+        } catch (InvocationTargetException e) {
+            throw new SQLException(
+                "Cannot set " + prop.getName() + ": " + e.getMessage());
+        }
+    }
+
+    /**
+     * ResultSet.getObject() returns an Integer object for an INT column.  The
+     * setter method for the property might take an Integer or a primitive int.
+     * This method returns true if the value can be successfully passed into
+     * the setter method.  Remember, Method.invoke() handles the unwrapping
+     * of Integer into an int.
+     *
+     * @param value The value to be passed into the setter method.
+     * @param type The setter's parameter type (non-null)
+     * @return boolean True if the value is compatible (null => true)
+     */
+    private boolean isCompatibleType(Object value, Class<?> type) {
+        // Do object check first, then primitives
+        if (value == null || type.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Integer.TYPE) && 
Integer.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) 
{
+            return true;
+
+        } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Character.TYPE) && 
Character.class.isInstance(value)) {
+            return true;
+
+        } else if (type.equals(Boolean.TYPE) && 
Boolean.class.isInstance(value)) {
+            return true;
+
+        }
+        return false;
+
+    }
+
+    /**
+     * Factory method that returns a new instance of the given Class.  This
+     * is called at the start of the bean creation process and may be
+     * overridden to provide custom behavior like returning a cached bean
+     * instance.
+     * @param <T> The type of object to create
+     * @param c The Class to create an object from.
+     * @return A newly created object of the Class.
+     * @throws SQLException if creation failed.
+     */
+    protected <T> T newInstance(Class<T> c) throws SQLException {
+        try {
+            return c.newInstance();
+
+        } catch (InstantiationException e) {
+            throw new SQLException(
+                "Cannot create " + c.getName() + ": " + e.getMessage());
+
+        } catch (IllegalAccessException e) {
+            throw new SQLException(
+                "Cannot create " + c.getName() + ": " + e.getMessage());
+        }
+    }
+
+    /**
+     * Returns a PropertyDescriptor[] for the given Class.
+     *
+     * @param c The Class to retrieve PropertyDescriptors for.
+     * @return A PropertyDescriptor[] describing the Class.
+     * @throws SQLException if introspection failed.
+     */
+    private PropertyDescriptor[] propertyDescriptors(Class<?> c)
+        throws SQLException {
+        // Introspector caches BeanInfo classes for better performance
+        BeanInfo beanInfo = null;
+        try {
+            beanInfo = Introspector.getBeanInfo(c);
+
+        } catch (IntrospectionException e) {
+            throw new SQLException(
+                "Bean introspection failed: " + e.getMessage());
+        }
+
+        return beanInfo.getPropertyDescriptors();
+    }
+
+    /**
+     * The positions in the returned array represent column numbers.  The
+     * values stored at each position represent the index in the
+     * <code>PropertyDescriptor[]</code> for the bean property that matches
+     * the column name.  If no bean property was found for a column, the
+     * position is set to <code>PROPERTY_NOT_FOUND</code>.
+     *
+     * @param rsmd The <code>ResultSetMetaData</code> containing column
+     * information.
+     *
+     * @param props The bean property descriptors.
+     *
+     * @throws SQLException if a database access error occurs
+     *
+     * @return An int[] with column index to property index mappings.  The 0th
+     * element is meaningless because JDBC column indexing starts at 1.
+     */
+    protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
+            PropertyDescriptor[] props) throws SQLException {
+
+        int cols = rsmd.getColumnCount();
+        int[] columnToProperty = new int[cols + 1];
+        Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
+
+        for (int col = 1; col <= cols; col++) {
+            String columnName = rsmd.getColumnLabel(col);
+            if (null == columnName || 0 == columnName.length()) {
+              columnName = rsmd.getColumnName(col);
+            }
+            String propertyName = columnToPropertyOverrides.get(columnName);
+            if (propertyName == null) {
+                propertyName = columnName;
+            }
+            for (int i = 0; i < props.length; i++) {
+
+                if (propertyName.equalsIgnoreCase(props[i].getName())) {
+                    columnToProperty[col] = i;
+                    break;
+                }
+            }
+        }
+
+        return columnToProperty;
+    }
+
+    /**
+     * Convert a <code>ResultSet</code> column into an object.  Simple
+     * implementations could just call <code>rs.getObject(index)</code> while
+     * more complex implementations could perform type manipulation to match
+     * the column's type to the bean property type.
+     *
+     * <p>
+     * This implementation calls the appropriate <code>ResultSet</code> getter
+     * method for the given property type to perform the type conversion.  If
+     * the property type doesn't match one of the supported
+     * <code>ResultSet</code> types, <code>getObject</code> is called.
+     * </p>
+     *
+     * @param rs The <code>ResultSet</code> currently being processed.  It is
+     * positioned on a valid row before being passed into this method.
+     *
+     * @param index The current column index being processed.
+     *
+     * @param propType The bean property type that this column needs to be
+     * converted into.
+     *
+     * @throws SQLException if a database access error occurs
+     *
+     * @return The object from the <code>ResultSet</code> at the given column
+     * index after optional type processing or <code>null</code> if the column
+     * value was SQL NULL.
+     */
+    protected Object processColumn(ResultSet rs, int index, Class<?> propType)
+        throws SQLException {
+
+        if ( !propType.isPrimitive() && rs.getObject(index) == null ) {
+            return null;
+        }
+
+        if (propType.equals(String.class)) {
+            return rs.getString(index);
+
+        } else if (
+            propType.equals(Integer.TYPE) || propType.equals(Integer.class)) {
+            return Integer.valueOf(rs.getInt(index));
+
+        } else if (
+            propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) {
+            return Boolean.valueOf(rs.getBoolean(index));
+
+        } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) {
+            return Long.valueOf(rs.getLong(index));
+
+        } else if (
+            propType.equals(Double.TYPE) || propType.equals(Double.class)) {
+            return Double.valueOf(rs.getDouble(index));
+
+        } else if (
+            propType.equals(Float.TYPE) || propType.equals(Float.class)) {
+            return Float.valueOf(rs.getFloat(index));
+
+        } else if (
+            propType.equals(Short.TYPE) || propType.equals(Short.class)) {
+            return Short.valueOf(rs.getShort(index));
+
+        } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) {
+            return Byte.valueOf(rs.getByte(index));
+
+        } else if (propType.equals(Timestamp.class)) {
+            return rs.getTimestamp(index);
+
+        } else if (propType.equals(SQLXML.class)) {
+            return rs.getSQLXML(index);
+
+        } else {
+            return rs.getObject(index);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/DbUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/DbUtils.java 
b/src/main/java/org/apache/commons/dbutils2/DbUtils.java
new file mode 100644
index 0000000..5968d4e
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/DbUtils.java
@@ -0,0 +1,406 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import static java.sql.DriverManager.registerDriver;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * A collection of JDBC helper methods.  This class is thread safe.
+ */
+public final class DbUtils {
+
+    /**
+     * Utility classes do not have a public default constructor.
+     *
+     * @since 1.4
+     */
+    private DbUtils() {
+        // do nothing
+    }
+
+    /**
+     * Close a <code>Connection</code>, avoid closing if null.
+     *
+     * @param conn Connection to close.
+     * @throws SQLException if a database access error occurs
+     */
+    public static void close(Connection conn) throws SQLException {
+        if (conn != null) {
+            conn.close();
+        }
+    }
+
+    /**
+     * Close a <code>ResultSet</code>, avoid closing if null.
+     *
+     * @param rs ResultSet to close.
+     * @throws SQLException if a database access error occurs
+     */
+    public static void close(ResultSet rs) throws SQLException {
+        if (rs != null) {
+            rs.close();
+        }
+    }
+
+    /**
+     * Close a <code>Statement</code>, avoid closing if null.
+     *
+     * @param stmt Statement to close.
+     * @throws SQLException if a database access error occurs
+     */
+    public static void close(Statement stmt) throws SQLException {
+        if (stmt != null) {
+            stmt.close();
+        }
+    }
+
+    /**
+     * Close a <code>Connection</code>, avoid closing if null and hide
+     * any SQLExceptions that occur.
+     *
+     * @param conn Connection to close.
+     */
+    public static void closeQuietly(Connection conn) {
+        try {
+            close(conn);
+        } catch (SQLException e) { // NOPMD
+            // quiet
+        }
+    }
+
+    /**
+     * Close a <code>Connection</code>, <code>Statement</code> and
+     * <code>ResultSet</code>.  Avoid closing if null and hide any
+     * SQLExceptions that occur.
+     *
+     * @param conn Connection to close.
+     * @param stmt Statement to close.
+     * @param rs ResultSet to close.
+     */
+    public static void closeQuietly(Connection conn, Statement stmt,
+            ResultSet rs) {
+
+        try {
+            closeQuietly(rs);
+        } finally {
+            try {
+                closeQuietly(stmt);
+            } finally {
+                closeQuietly(conn);
+            }
+        }
+
+    }
+
+    /**
+     * Close a <code>ResultSet</code>, avoid closing if null and hide any
+     * SQLExceptions that occur.
+     *
+     * @param rs ResultSet to close.
+     */
+    public static void closeQuietly(ResultSet rs) {
+        try {
+            close(rs);
+        } catch (SQLException e) { // NOPMD
+            // quiet
+        }
+    }
+
+    /**
+     * Close a <code>Statement</code>, avoid closing if null and hide
+     * any SQLExceptions that occur.
+     *
+     * @param stmt Statement to close.
+     */
+    public static void closeQuietly(Statement stmt) {
+        try {
+            close(stmt);
+        } catch (SQLException e) { // NOPMD
+            // quiet
+        }
+    }
+
+    /**
+     * Commits a <code>Connection</code> then closes it, avoid closing if null.
+     *
+     * @param conn Connection to close.
+     * @throws SQLException if a database access error occurs
+     */
+    public static void commitAndClose(Connection conn) throws SQLException {
+        if (conn != null) {
+            try {
+                conn.commit();
+            } finally {
+                conn.close();
+            }
+        }
+    }
+
+    /**
+     * Commits a <code>Connection</code> then closes it, avoid closing if null
+     * and hide any SQLExceptions that occur.
+     *
+     * @param conn Connection to close.
+     */
+    public static void commitAndCloseQuietly(Connection conn) {
+        try {
+            commitAndClose(conn);
+        } catch (SQLException e) { // NOPMD
+            // quiet
+        }
+    }
+
+    /**
+     * Loads and registers a database driver class.
+     * If this succeeds, it returns true, else it returns false.
+     *
+     * @param driverClassName of driver to load
+     * @return boolean <code>true</code> if the driver was found, otherwise 
<code>false</code>
+     */
+    public static boolean loadDriver(String driverClassName) {
+        return loadDriver(DbUtils.class.getClassLoader(), driverClassName);
+    }
+
+    /**
+     * Loads and registers a database driver class.
+     * If this succeeds, it returns true, else it returns false.
+     *
+     * @param classLoader the class loader used to load the driver class
+     * @param driverClassName of driver to load
+     * @return boolean <code>true</code> if the driver was found, otherwise 
<code>false</code>
+     * @since 1.4
+     */
+    public static boolean loadDriver(ClassLoader classLoader, String 
driverClassName) {
+        try {
+            Class<?> loadedClass = classLoader.loadClass(driverClassName);
+
+            if (!Driver.class.isAssignableFrom(loadedClass)) {
+                return false;
+            }
+
+            @SuppressWarnings("unchecked") // guarded by previous check
+            Class<Driver> driverClass = (Class<Driver>) loadedClass;
+            Constructor<Driver> driverConstructor = 
driverClass.getConstructor();
+
+            // make Constructor accessible if it is private
+            boolean isConstructorAccessible = driverConstructor.isAccessible();
+            if (!isConstructorAccessible) {
+                driverConstructor.setAccessible(true);
+            }
+
+            try {
+                Driver driver = driverConstructor.newInstance();
+                registerDriver(new DriverProxy(driver));
+            } finally {
+                driverConstructor.setAccessible(isConstructorAccessible);
+            }
+
+            return true;
+        } catch (Exception e) {
+            return false;
+
+        }
+    }
+
+    /**
+     * Print the stack trace for a SQLException to STDERR.
+     *
+     * @param e SQLException to print stack trace of
+     */
+    public static void printStackTrace(SQLException e) {
+        printStackTrace(e, new PrintWriter(System.err));
+    }
+
+    /**
+     * Print the stack trace for a SQLException to a
+     * specified PrintWriter.
+     *
+     * @param e SQLException to print stack trace of
+     * @param pw PrintWriter to print to
+     */
+    public static void printStackTrace(SQLException e, PrintWriter pw) {
+
+        SQLException next = e;
+        while (next != null) {
+            next.printStackTrace(pw);
+            next = next.getNextException();
+            if (next != null) {
+                pw.println("Next SQLException:");
+            }
+        }
+    }
+
+    /**
+     * Print warnings on a Connection to STDERR.
+     *
+     * @param conn Connection to print warnings from
+     */
+    public static void printWarnings(Connection conn) {
+        printWarnings(conn, new PrintWriter(System.err));
+    }
+
+    /**
+     * Print warnings on a Connection to a specified PrintWriter.
+     *
+     * @param conn Connection to print warnings from
+     * @param pw PrintWriter to print to
+     */
+    public static void printWarnings(Connection conn, PrintWriter pw) {
+        if (conn != null) {
+            try {
+                printStackTrace(conn.getWarnings(), pw);
+            } catch (SQLException e) {
+                printStackTrace(e, pw);
+            }
+        }
+    }
+
+    /**
+     * Rollback any changes made on the given connection.
+     * @param conn Connection to rollback.  A null value is legal.
+     * @throws SQLException if a database access error occurs
+     */
+    public static void rollback(Connection conn) throws SQLException {
+        if (conn != null) {
+            conn.rollback();
+        }
+    }
+
+    /**
+     * Performs a rollback on the <code>Connection</code> then closes it,
+     * avoid closing if null.
+     *
+     * @param conn Connection to rollback.  A null value is legal.
+     * @throws SQLException if a database access error occurs
+     * @since DbUtils 1.1
+     */
+    public static void rollbackAndClose(Connection conn) throws SQLException {
+        if (conn != null) {
+            try {
+                conn.rollback();
+            } finally {
+                conn.close();
+            }
+        }
+    }
+
+    /**
+     * Performs a rollback on the <code>Connection</code> then closes it,
+     * avoid closing if null and hide any SQLExceptions that occur.
+     *
+     * @param conn Connection to rollback.  A null value is legal.
+     * @since DbUtils 1.1
+     */
+    public static void rollbackAndCloseQuietly(Connection conn) {
+        try {
+            rollbackAndClose(conn);
+        } catch (SQLException e) { // NOPMD
+            // quiet
+        }
+    }
+
+    /**
+     * Simple {@link Driver} proxy class that proxies a JDBC Driver loaded 
dynamically.
+     *
+     * @since 1.6
+     */
+    private static final class DriverProxy implements Driver {
+
+        /**
+         * The adapted JDBC Driver loaded dynamically.
+         */
+        private final Driver adapted;
+
+        /**
+         * Creates a new JDBC Driver that adapts a JDBC Driver loaded 
dynamically.
+         *
+         * @param adapted the adapted JDBC Driver loaded dynamically.
+         */
+        public DriverProxy(Driver adapted) {
+            this.adapted = adapted;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean acceptsURL(String url) throws SQLException {
+            return adapted.acceptsURL(url);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Connection connect(String url, Properties info) throws 
SQLException {
+            return adapted.connect(url, info);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int getMajorVersion() {
+            return adapted.getMajorVersion();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int getMinorVersion() {
+            return adapted.getMinorVersion();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public DriverPropertyInfo[] getPropertyInfo(String url, Properties 
info) throws SQLException {
+            return adapted.getPropertyInfo(url, info);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean jdbcCompliant() {
+            return adapted.jdbcCompliant();
+        }
+
+        /**
+         * Java 1.7 method.
+         */
+        @SuppressWarnings("unused")
+        public Logger getParentLogger() throws SQLFeatureNotSupportedException 
{
+            throw new SQLFeatureNotSupportedException();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/GenerousBeanProcessor.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbutils2/GenerousBeanProcessor.java 
b/src/main/java/org/apache/commons/dbutils2/GenerousBeanProcessor.java
new file mode 100644
index 0000000..b85b66e
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/GenerousBeanProcessor.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+
+import java.beans.PropertyDescriptor;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+
+/**
+ * Provides generous name matching (e.g. underscore-aware) from DB
+ * columns to Java Bean properties.
+ */
+public class GenerousBeanProcessor extends BeanProcessor {
+    
+    /**
+     * Default constructor.
+     */
+    public GenerousBeanProcessor() {
+        super();
+    }
+    
+    @Override
+    protected int[] mapColumnsToProperties(final ResultSetMetaData rsmd,
+                                           final PropertyDescriptor[] props) 
throws SQLException {
+
+        final int cols = rsmd.getColumnCount();
+        final int[] columnToProperty = new int[cols + 1];
+        Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
+
+        for (int col = 1; col <= cols; col++) {
+            String columnName = rsmd.getColumnLabel(col);
+            
+            if (null == columnName || 0 == columnName.length()) {
+                columnName = rsmd.getColumnName(col);
+            }
+            
+            final String generousColumnName = columnName.replace("_","");
+
+            for (int i = 0; i < props.length; i++) {
+                final String propName = props[i].getName();
+                
+                // see if either the column name, or the generous one matches
+                if (columnName.equalsIgnoreCase(propName) ||
+                    generousColumnName.equalsIgnoreCase(propName)) {
+                    columnToProperty[col] = i;
+                    break;
+                }
+            }
+        }
+
+        return columnToProperty;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/InsertExecutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/InsertExecutor.java 
b/src/main/java/org/apache/commons/dbutils2/InsertExecutor.java
new file mode 100644
index 0000000..39a6db6
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/InsertExecutor.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+
+public class InsertExecutor extends AbstractExecutor<InsertExecutor> {
+
+    private final boolean closeConn;
+
+    public InsertExecutor(final Connection conn, final String sql, final 
boolean closeConnection) throws SQLException {
+        super(conn, sql);
+        this.closeConn = closeConnection;
+    }
+
+    /**
+     * Executes the given INSERT SQL statement.
+     * 
+     * @param handler The handler used to create the result object from
+     * the <code>ResultSet</code> of auto-generated keys.
+     *
+     * @return An object generated by the handler.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public <T> T execute(ResultSetHandler<T> handler) throws SQLException {
+        // throw an exception if there are unmapped parameters
+        this.throwIfUnmappedParams();
+
+        // make sure our handler is not null
+        if (handler == null) {
+            if (closeConn) {
+                close(getConnection());
+            }
+            throw new SQLException("Null ResultSetHandler");
+        }
+
+        try {
+            // execute the update
+            getStatement().executeUpdate();
+            
+            // get the result set
+            final ResultSet resultSet = getStatement().getGeneratedKeys();
+            
+            // run the handler over the results and return them
+            return handler.handle(resultSet);
+        } catch (SQLException e) {
+            this.rethrow(e);
+        } finally {
+            close(getStatement());
+            if (closeConn) {
+                close(getConnection());
+            }
+        }
+
+        // we get here only if something is thrown
+        return null;
+    }
+    
+    /**
+     * Executes the given INSERT SQL statement.
+     * @return the number of rows updated.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public int execute() throws SQLException {
+        // throw an exception if there are unmapped parameters
+        this.throwIfUnmappedParams();
+
+        try {
+            // execute the insert
+            return getStatement().executeUpdate();
+        } catch (SQLException e) {
+            this.rethrow(e);
+        } finally {
+            close(getStatement());
+            if (closeConn) {
+                close(getConnection());
+            }
+        }
+        
+        return 0; // only get here on an error
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/ProxyFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/ProxyFactory.java 
b/src/main/java/org/apache/commons/dbutils2/ProxyFactory.java
new file mode 100644
index 0000000..9410f27
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/ProxyFactory.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+
+/**
+ * Creates proxy implementations of JDBC interfaces.  This avoids
+ * incompatibilities between the JDBC 2 and JDBC 3 interfaces.  This class is
+ * thread safe.
+ *
+ * @see java.lang.reflect.Proxy
+ * @see java.lang.reflect.InvocationHandler
+ */
+public class ProxyFactory {
+
+    /**
+     * The Singleton instance of this class.
+     */
+    private static final ProxyFactory instance = new ProxyFactory();
+
+    /**
+     * Returns the Singleton instance of this class.
+     *
+     * @return singleton instance
+     */
+    public static ProxyFactory instance() {
+        return instance;
+    }
+
+    /**
+     * Protected constructor for ProxyFactory subclasses to use.
+     */
+    protected ProxyFactory() {
+        super();
+    }
+
+    /**
+     * Convenience method to generate a single-interface proxy using the 
handler's classloader
+     *
+     * @param <T> The type of object to proxy
+     * @param type The type of object to proxy
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied object
+     */
+    public <T> T newProxyInstance(Class<T> type, InvocationHandler handler) {
+        return 
type.cast(Proxy.newProxyInstance(handler.getClass().getClassLoader(), new 
Class<?>[] {type}, handler));
+    }
+
+    /**
+     * Creates a new proxy <code>CallableStatement</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied CallableStatement
+     */
+    public CallableStatement createCallableStatement(InvocationHandler 
handler) {
+        return newProxyInstance(CallableStatement.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>Connection</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied Connection
+     */
+    public Connection createConnection(InvocationHandler handler) {
+        return newProxyInstance(Connection.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>Driver</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied Driver
+     */
+    public Driver createDriver(InvocationHandler handler) {
+        return newProxyInstance(Driver.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>PreparedStatement</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied PreparedStatement
+     */
+    public PreparedStatement createPreparedStatement(InvocationHandler 
handler) {
+        return newProxyInstance(PreparedStatement.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>ResultSet</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied ResultSet
+     */
+    public ResultSet createResultSet(InvocationHandler handler) {
+        return newProxyInstance(ResultSet.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>ResultSetMetaData</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied ResultSetMetaData
+     */
+    public ResultSetMetaData createResultSetMetaData(InvocationHandler 
handler) {
+        return newProxyInstance(ResultSetMetaData.class, handler);
+    }
+
+    /**
+     * Creates a new proxy <code>Statement</code> object.
+     * @param handler The handler that intercepts/overrides method calls.
+     * @return proxied Statement
+     */
+    public Statement createStatement(InvocationHandler handler) {
+        return newProxyInstance(Statement.class, handler);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/QueryExecutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/QueryExecutor.java 
b/src/main/java/org/apache/commons/dbutils2/QueryExecutor.java
new file mode 100644
index 0000000..4a7c317
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/QueryExecutor.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Fluent class for executing a query.
+ * 
+ * @since 2.0
+ * @author William Speirs <[email protected]>
+ */
+class QueryExecutor extends AbstractExecutor<QueryExecutor> {
+    
+    private final boolean closeConn;
+
+    public QueryExecutor(final Connection conn, final String sql, final 
boolean closeConnection) throws SQLException {
+        super(conn, sql);
+        this.closeConn = closeConnection;
+    }
+
+    /**
+     * Calls query after checking the parameters to ensure nothing is null.
+     *
+     * @param rsh The handler that converts the results into an object.
+     *
+     * @return The results of the query.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public <T> T execute(ResultSetHandler<T> handler) throws SQLException {
+        // throw an exception if there are unmapped parameters
+        this.throwIfUnmappedParams();
+        
+        // make sure our handler is not null
+        if (handler == null) {
+            if (closeConn) {
+                close(getConnection());
+            }
+            throw new SQLException("Null ResultSetHandler");
+        }
+
+        ResultSet resultSet = null;
+
+        try {
+            // execute the query, wrapping it
+            resultSet = this.wrap(getStatement().executeQuery());
+            // execute the handler
+            return handler.handle(resultSet);
+        } catch (SQLException e) {
+            // rethrow our exception printing more information
+            this.rethrow(e);
+        } finally {
+            try {
+                close(resultSet);
+            } finally {
+                close(getStatement());
+                if (closeConn) {
+                    close(getConnection());
+                }
+            }
+        }
+
+        // we get here only if something is thrown
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/QueryLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/QueryLoader.java 
b/src/main/java/org/apache/commons/dbutils2/QueryLoader.java
new file mode 100644
index 0000000..df6db6f
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/QueryLoader.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * <code>QueryLoader</code> is a registry for sets of queries so
+ * that multiple copies of the same queries aren't loaded into memory.
+ * This implementation loads properties files filled with query name to
+ * SQL mappings.  This class is thread safe.
+ */
+public class QueryLoader {
+
+    /**
+     * The Singleton instance of this class.
+     */
+    private static final QueryLoader instance = new QueryLoader();
+
+    /**
+     * Return an instance of this class.
+     * @return The Singleton instance.
+     */
+    public static QueryLoader instance() {
+        return instance;
+    }
+
+    /**
+     * Maps query set names to Maps of their queries.
+     */
+    private final Map<String, Map<String, String>> queries = new 
HashMap<String, Map<String, String>>();
+
+    /**
+     * QueryLoader constructor.
+     */
+    protected QueryLoader() {
+        super();
+    }
+
+    /**
+     * Loads a Map of query names to SQL values.  The Maps are cached so a
+     * subsequent request to load queries from the same path will return
+     * the cached Map.
+     *
+     * @param path The path that the ClassLoader will use to find the file.
+     * This is <strong>not</strong> a file system path.  If you had a jarred
+     * Queries.properties file in the com.yourcorp.app.jdbc package you would
+     * pass "/com/yourcorp/app/jdbc/Queries.properties" to this method.
+     * @throws IOException if a file access error occurs
+     * @throws IllegalArgumentException if the ClassLoader can't find a file at
+     * the given path.
+     * @return Map of query names to SQL values
+     */
+    public synchronized Map<String, String> load(String path) throws 
IOException {
+
+        Map<String, String> queryMap = this.queries.get(path);
+
+        if (queryMap == null) {
+            queryMap = this.loadQueries(path);
+            this.queries.put(path, queryMap);
+        }
+
+        return queryMap;
+    }
+
+    /**
+     * Loads a set of named queries into a Map object.  This implementation
+     * reads a properties file at the given path.
+     * @param path The path that the ClassLoader will use to find the file.
+     * @throws IOException if a file access error occurs
+     * @throws IllegalArgumentException if the ClassLoader can't find a file at
+     * the given path.
+     * @since DbUtils 1.1
+     * @return Map of query names to SQL values
+     */
+    protected Map<String, String> loadQueries(String path) throws IOException {
+        // Findbugs flags getClass().getResource as a bad practice; maybe we 
should change the API?
+        InputStream in = getClass().getResourceAsStream(path);
+
+        if (in == null) {
+            throw new IllegalArgumentException(path + " not found.");
+        }
+
+        Properties props = new Properties();
+        try {
+            props.load(in);
+        } finally {
+            in.close();
+        }
+
+        // Copy to HashMap for better performance
+
+        @SuppressWarnings({ "rawtypes", "unchecked" }) // load() always 
creates <String,String> entries
+        HashMap<String, String> hashMap = new HashMap(props);
+        return hashMap;
+    }
+
+    /**
+     * Removes the queries for the given path from the cache.
+     * @param path The path that the queries were loaded from.
+     */
+    public synchronized void unload(String path) {
+        this.queries.remove(path);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/QueryRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/QueryRunner.java 
b/src/main/java/org/apache/commons/dbutils2/QueryRunner.java
new file mode 100644
index 0000000..9dbc292
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/QueryRunner.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import javax.sql.DataSource;
+
+/**
+ * Executes SQL queries with pluggable strategies for handling
+ * <code>ResultSet</code>s.  This class is thread safe.
+ *
+ * @see ResultSetHandler
+ */
+public class QueryRunner {
+    /**
+     * The DataSource to retrieve connections from.
+     */
+    private final DataSource ds;
+
+    /**
+     * Constructor for QueryRunner.
+     */
+    public QueryRunner() {
+        ds = null;
+    }
+
+    /**
+     * Constructor for QueryRunner that takes a <code>DataSource</code> to use.
+     *
+     * Methods that do not take a <code>Connection</code> parameter will 
retrieve connections from this
+     * <code>DataSource</code>.
+     *
+     * @param ds The <code>DataSource</code> to retrieve connections from.
+     */
+    public QueryRunner(final DataSource ds) {
+        this.ds = ds;
+    }
+    
+    /**
+     * Returns the <code>DataSource</code> this runner is using.
+     * <code>QueryRunner</code> methods always call this method to get the
+     * <code>DataSource</code> so subclasses can provide specialized behavior.
+     *
+     * @return DataSource the runner is using
+     */
+    public DataSource getDataSource() {
+        return this.ds;
+    }
+
+    /**
+     * Factory method that creates and initializes a <code>Connection</code>
+     * object. <code>QueryRunner</code> methods always call this method to
+     * retrieve connections from its DataSource. Subclasses can override this
+     * method to provide special <code>Connection</code> configuration if
+     * needed. This implementation simply calls 
<code>ds.getConnection()</code>.
+     *
+     * @return An initialized <code>Connection</code>.
+     * @throws SQLException if a database access error occurs
+     */
+    protected Connection prepareConnection() throws SQLException {
+        if (this.getDataSource() == null) {
+            throw new SQLException(
+                    "QueryRunner requires a DataSource to be "
+                    + "invoked in this way, or a Connection should be passed 
in");
+        }
+        return this.getDataSource().getConnection();
+    }
+
+    /**
+     * Close a <code>Connection</code>. This implementation avoids closing if
+     * null and does <strong>not</strong> suppress any exceptions. Subclasses
+     * can override to provide special handling like logging.
+     *
+     * @param conn Connection to close
+     * @throws SQLException if a database access error occurs
+     */
+    private void close(Connection conn) throws SQLException {
+        DbUtils.close(conn);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.BatchExecutor} for the 
given SQL.
+     * <code>Connection</code> is retrieved from the <code>DataSource</code>
+     * set in the constructor.  This <code>Connection</code> must be in
+     * auto-commit mode or the insert will not be saved. The 
<code>Connection</code> is
+     * closed after the call. 
+     * 
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.BatchExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public BatchExecutor batch(String sql) throws SQLException {
+        return this.batch(this.prepareConnection(), true, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.BatchExecutor} for the 
given SQL statement and connection.
+     * The connection is <b>NOT</b> closed after execution.
+     *
+     * @param conn The connection to use for the batch call.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.BatchExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public BatchExecutor batch(Connection conn, String sql) throws 
SQLException {
+        return this.batch(conn, true, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.BatchExecutor} for the 
given SQL statement and connection.
+     * 
+     * @param conn The connection to use for the batch call.
+     * @param closeConn True if the connection should be closed, false 
otherwise.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.BatchExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public BatchExecutor batch(Connection conn, boolean closeConn, String sql) 
throws SQLException {
+        if (conn == null) {
+            throw new SQLException("Null connection");
+        }
+
+        if (sql == null) {
+            if (closeConn) {
+                close(conn);
+            }
+            throw new SQLException("Null SQL statement");
+        }
+        
+        return new BatchExecutor(conn, sql, closeConn);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.QueryExecutor} for the 
given SQL.
+     * <code>Connection</code> is retrieved from the <code>DataSource</code>
+     * set in the constructor.  This <code>Connection</code> must be in
+     * auto-commit mode or the insert will not be saved. The 
<code>Connection</code> is
+     * closed after the call. 
+     * 
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.QueryExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public QueryExecutor query(String sql) throws SQLException {
+        return this.query(this.prepareConnection(), true, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.QueryExecutor} for the 
given SQL statement and connection.
+     * The connection is <b>NOT</b> closed after execution.
+     * 
+     * @param conn The connection to use for the update call.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.QueryExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public QueryExecutor query(Connection conn, String sql) throws 
SQLException {
+        return this.query(conn, false, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.QueryExecutor} for the 
given SQL statement and connection.
+     * 
+     * @param conn The connection to use for the query call.
+     * @param closeConn True if the connection should be closed, false 
otherwise.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.QueryExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public QueryExecutor query(Connection conn, boolean closeConn, String sql) 
throws SQLException {
+        if (conn == null) {
+            throw new SQLException("Null connection");
+        }
+
+        if (sql == null) {
+            if (closeConn) {
+                close(conn);
+            }
+            throw new SQLException("Null SQL statement");
+        }
+        
+        return new QueryExecutor(conn, sql, closeConn);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.UpdateExecutor} for the 
given SQL.
+     * <code>Connection</code> is retrieved from the <code>DataSource</code>
+     * set in the constructor.  This <code>Connection</code> must be in
+     * auto-commit mode or the insert will not be saved. The 
<code>Connection</code> is
+     * closed after the call. 
+     *
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.UpdateExecutor} for this 
SQL statement.
+     * @throws SQLException if a database access error occurs
+     */
+    public UpdateExecutor update(String sql) throws SQLException {
+        return this.update(this.prepareConnection(), true, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.UpdateExecutor} for the 
given SQL statement and connection.
+     * The connection is <b>NOT</b> closed after execution.
+     * 
+     * @param conn The connection to use for the update call.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.UpdateExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public UpdateExecutor update(Connection conn, String sql) throws 
SQLException {
+        return this.update(conn, false, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.UpdateExecutor} for the 
given SQL statement and connection.
+     * 
+     * @param conn The connection to use for the update call.
+     * @param closeConn True if the connection should be closed, false 
otherwise.
+     * @param sql The SQL statement to execute.
+     * 
+     * @return An {@link org.apache.commons.dbutils2.UpdateExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public UpdateExecutor update(Connection conn, boolean closeConn, String 
sql) throws SQLException {
+        if (conn == null) {
+            throw new SQLException("Null connection");
+        }
+
+        if (sql == null) {
+            if (closeConn) {
+                close(conn);
+            }
+            throw new SQLException("Null SQL statement");
+        }
+
+        return new UpdateExecutor(conn, sql, closeConn);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.InsertExecutor} for the 
given SQL.
+     * <code>Connection</code> is retrieved from the <code>DataSource</code>
+     * set in the constructor.  This <code>Connection</code> must be in
+     * auto-commit mode or the insert will not be saved. The 
<code>Connection</code> is
+     * closed after the call. 
+     * 
+     * @param sql The SQL statement to execute.
+     *
+     * @return An {@link org.apache.commons.dbutils2.InsertExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public InsertExecutor insert(String sql) throws SQLException {
+        return insert(this.prepareConnection(), true, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.InsertExecutor} for the 
given SQL and connection
+     * The connection is <b>NOT</b> closed after execution.
+     * 
+     * @param conn The connection to use for the query call.
+     * @param sql The SQL statement to execute.
+     *
+     * @return An {@link org.apache.commons.dbutils2.InsertExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public InsertExecutor insert(Connection conn, String sql) throws 
SQLException {
+        return insert(conn, false, sql);
+    }
+
+    /**
+     * Creates an {@link org.apache.commons.dbutils2.InsertExecutor} for the 
given SQL and connection.
+     * 
+     * @param conn The connection to use for the insert call.
+     * @param closeConn True if the connection should be closed, false 
otherwise.
+     * @param sql The SQL statement to execute.
+     *
+     * @return An {@link org.apache.commons.dbutils2.InsertExecutor} for this 
SQL statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public InsertExecutor insert(Connection conn, boolean closeConn, String 
sql) throws SQLException {
+        if (conn == null) {
+            throw new SQLException("Null connection");
+        }
+
+        if (sql == null) {
+            if (closeConn) {
+                close(conn);
+            }
+            throw new SQLException("Null SQL statement");
+        }
+        
+        return new InsertExecutor(conn, sql, closeConn);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/ResultSetHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/ResultSetHandler.java 
b/src/main/java/org/apache/commons/dbutils2/ResultSetHandler.java
new file mode 100644
index 0000000..f7ba0bd
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/ResultSetHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Implementations of this interface convert ResultSets into other objects.
+ *
+ * @param <T> the target type the input ResultSet will be converted to.
+ */
+public interface ResultSetHandler<T> {
+
+    /**
+     * Turn the <code>ResultSet</code> into an Object.
+     *
+     * @param rs The <code>ResultSet</code> to handle.  It has not been touched
+     * before being passed to this method.
+     *
+     * @return An Object initialized with <code>ResultSet</code> data. It is
+     * legal for implementations to return <code>null</code> if the
+     * <code>ResultSet</code> contained 0 rows.
+     *
+     * @throws SQLException if a database access error occurs
+     */
+    T handle(ResultSet rs) throws SQLException;
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/ResultSetIterator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/ResultSetIterator.java 
b/src/main/java/org/apache/commons/dbutils2/ResultSetIterator.java
new file mode 100644
index 0000000..ef05213
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/ResultSetIterator.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+/**
+ * <p>
+ * Wraps a <code>ResultSet</code> in an <code>Iterator<Object[]></code>.  This 
is useful
+ * when you want to present a non-database application layer with domain
+ * neutral data.
+ * </p>
+ *
+ * <p>
+ * This implementation requires the <code>ResultSet.isLast()</code> method
+ * to be implemented.
+ * </p>
+ */
+public class ResultSetIterator implements Iterator<Object[]> {
+
+    /**
+     * The wrapped <code>ResultSet</code>.
+     */
+    private final ResultSet rs;
+
+    /**
+     * The processor to use when converting a row into an Object[].
+     */
+    private final RowProcessor convert;
+
+    /**
+     * Constructor for ResultSetIterator.
+     * @param rs Wrap this <code>ResultSet</code> in an <code>Iterator</code>.
+     */
+    public ResultSetIterator(ResultSet rs) {
+        this(rs, new BasicRowProcessor());
+    }
+
+    /**
+     * Constructor for ResultSetIterator.
+     * @param rs Wrap this <code>ResultSet</code> in an <code>Iterator</code>.
+     * @param convert The processor to use when converting a row into an
+     * <code>Object[]</code>.  Defaults to a
+     * <code>BasicRowProcessor</code>.
+     */
+    public ResultSetIterator(ResultSet rs, RowProcessor convert) {
+        this.rs = rs;
+        this.convert = convert;
+    }
+
+    /**
+     * Returns true if there are more rows in the ResultSet.
+     * @return boolean <code>true</code> if there are more rows
+     * @throws RuntimeException if an SQLException occurs.
+     */
+    @Override
+    public boolean hasNext() {
+        try {
+            return !rs.isLast();
+        } catch (SQLException e) {
+            rethrow(e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns the next row as an <code>Object[]</code>.
+     * @return An <code>Object[]</code> with the same number of elements as
+     * columns in the <code>ResultSet</code>.
+     * @see java.util.Iterator#next()
+     * @throws RuntimeException if an SQLException occurs.
+     */
+    @Override
+    public Object[] next() {
+        try {
+            rs.next();
+            return this.convert.toArray(rs);
+        } catch (SQLException e) {
+            rethrow(e);
+            return null;
+        }
+    }
+
+    /**
+     * Deletes the current row from the <code>ResultSet</code>.
+     * @see java.util.Iterator#remove()
+     * @throws RuntimeException if an SQLException occurs.
+     */
+    @Override
+    public void remove() {
+        try {
+            this.rs.deleteRow();
+        } catch (SQLException e) {
+            rethrow(e);
+        }
+    }
+
+    /**
+     * Rethrow the SQLException as a RuntimeException.  This implementation
+     * creates a new RuntimeException with the SQLException's error message.
+     * @param e SQLException to rethrow
+     * @since DbUtils 1.1
+     */
+    protected void rethrow(SQLException e) {
+        throw new RuntimeException(e.getMessage());
+    }
+
+    /**
+     * Generates an <code>Iterable</code>, suitable for use in for-each loops.
+     *
+     * @param rs Wrap this <code>ResultSet</code> in an <code>Iterator</code>.
+     * @return an <code>Iterable</code>, suitable for use in for-each loops.
+     */
+    public static Iterable<Object[]> iterable(final ResultSet rs) {
+        return new Iterable<Object[]>() {
+
+            @Override
+            public Iterator<Object[]> iterator() {
+                return new ResultSetIterator(rs);
+            }
+
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/RowProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/RowProcessor.java 
b/src/main/java/org/apache/commons/dbutils2/RowProcessor.java
new file mode 100644
index 0000000..b896b01
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/RowProcessor.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <code>RowProcessor</code> implementations convert
+ * <code>ResultSet</code> rows into various other objects.  Implementations
+ * can extend <code>BasicRowProcessor</code> to protect themselves
+ * from changes to this interface.
+ *
+ * @see BasicRowProcessor
+ */
+public interface RowProcessor {
+
+    /**
+     * Create an <code>Object[]</code> from the column values in one
+     * <code>ResultSet</code> row.  The <code>ResultSet</code> should be
+     * positioned on a valid row before passing it to this method.
+     * Implementations of this method must not alter the row position of
+     * the <code>ResultSet</code>.
+     *
+     * @param rs ResultSet that supplies the array data
+     * @throws SQLException if a database access error occurs
+     * @return the newly created array
+     */
+    Object[] toArray(ResultSet rs) throws SQLException;
+
+    /**
+     * Create a JavaBean from the column values in one <code>ResultSet</code>
+     * row.  The <code>ResultSet</code> should be positioned on a valid row 
before
+     * passing it to this method.  Implementations of this method must not
+     * alter the row position of the <code>ResultSet</code>.
+     * @param <T> The type of bean to create
+     * @param rs ResultSet that supplies the bean data
+     * @param type Class from which to create the bean instance
+     * @throws SQLException if a database access error occurs
+     * @return the newly created bean
+     */
+    <T> T toBean(ResultSet rs, Class<T> type) throws SQLException;
+
+    /**
+     * Create a <code>List</code> of JavaBeans from the column values in all
+     * <code>ResultSet</code> rows.  <code>ResultSet.next()</code> should
+     * <strong>not</strong> be called before passing it to this method.
+     * @param <T> The type of bean to create
+     * @param rs ResultSet that supplies the bean data
+     * @param type Class from which to create the bean instance
+     * @throws SQLException if a database access error occurs
+     * @return A <code>List</code> of beans with the given type in the order
+     * they were returned by the <code>ResultSet</code>.
+     */
+    <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException;
+
+    /**
+     * Create a <code>Map</code> from the column values in one
+     * <code>ResultSet</code> row.  The <code>ResultSet</code> should be
+     * positioned on a valid row before
+     * passing it to this method.  Implementations of this method must not
+     * alter the row position of the <code>ResultSet</code>.
+     *
+     * @param rs ResultSet that supplies the map data
+     * @throws SQLException if a database access error occurs
+     * @return the newly created Map
+     */
+    Map<String, Object> toMap(ResultSet rs) throws SQLException;
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/UpdateExecutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils2/UpdateExecutor.java 
b/src/main/java/org/apache/commons/dbutils2/UpdateExecutor.java
new file mode 100644
index 0000000..590f069
--- /dev/null
+++ b/src/main/java/org/apache/commons/dbutils2/UpdateExecutor.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+
+public class UpdateExecutor extends AbstractExecutor<UpdateExecutor> {
+
+    private final boolean closeConn;
+    
+    public UpdateExecutor(final Connection conn, final String sql, final 
boolean closeConnection) throws SQLException {
+        super(conn, sql);
+        this.closeConn = closeConnection;
+    }
+
+    /**
+     * Calls update after checking the parameters to ensure nothing is null.
+     * @return The number of rows updated.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    public int execute() throws SQLException {
+        // throw an exception if there are unmapped parameters
+        this.throwIfUnmappedParams();
+
+        try {
+            return getStatement().executeUpdate();
+        } catch (SQLException e) {
+            this.rethrow(e);
+
+        } finally {
+            close(getStatement());
+            if (closeConn) {
+                close(getConnection());
+            }
+        }
+
+        // we get here only if something is thrown
+        return 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/handlers/AbstractKeyedHandler.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbutils2/handlers/AbstractKeyedHandler.java 
b/src/main/java/org/apache/commons/dbutils2/handlers/AbstractKeyedHandler.java
new file mode 100644
index 0000000..14e0b63
--- /dev/null
+++ 
b/src/main/java/org/apache/commons/dbutils2/handlers/AbstractKeyedHandler.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2.handlers;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.dbutils2.ResultSetHandler;
+
+/**
+ * <p>
+ * <code>ResultSetHandler</code> implementation that returns a Map.
+ * <code>ResultSet</code> rows are converted into objects (Vs) which are then 
stored
+ * in a Map under the given keys (Ks).
+ * </p>
+ *
+ * @param <K> the type of keys maintained by the returned map
+ * @param <V> the type of mapped values
+ * @see org.apache.commons.dbutils2.ResultSetHandler
+ * @since DbUtils 1.3
+ */
+public abstract class AbstractKeyedHandler<K, V> implements 
ResultSetHandler<Map<K, V>> {
+
+
+    /**
+     * Convert each row's columns into a Map and store then
+     * in a <code>Map</code> under <code>ResultSet.getObject(key)</code> key.
+     * @param rs <code>ResultSet</code> to process.
+     * @return A <code>Map</code>, never <code>null</code>.
+     * @throws SQLException if a database access error occurs
+     * @see 
org.apache.commons.dbutils2.ResultSetHandler#handle(java.sql.ResultSet)
+     */
+    @Override
+    public Map<K, V> handle(ResultSet rs) throws SQLException {
+        Map<K, V> result = createMap();
+        while (rs.next()) {
+            result.put(createKey(rs), createRow(rs));
+        }
+        return result;
+    }
+
+    /**
+     * This factory method is called by <code>handle()</code> to create the Map
+     * to store records in.  This implementation returns a <code>HashMap</code>
+     * instance.
+     *
+     * @return Map to store records in
+     */
+    protected Map<K, V> createMap() {
+        return new HashMap<K, V>();
+    }
+
+    /**
+     * This factory method is called by <code>handle()</code> to retrieve the
+     * key value from the current <code>ResultSet</code> row.
+     * @param rs ResultSet to create a key from
+     * @return K from the configured key column name/index
+     * @throws SQLException if a database access error occurs
+     */
+    protected abstract K createKey(ResultSet rs) throws SQLException;
+
+    /**
+     * This factory method is called by <code>handle()</code> to store the
+     * current <code>ResultSet</code> row in some object.
+     * @param rs ResultSet to create a row from
+     * @return V object created from the current row
+     * @throws SQLException if a database access error occurs
+     */
+    protected abstract V createRow(ResultSet rs) throws SQLException;
+
+}

http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/41d6d58c/src/main/java/org/apache/commons/dbutils2/handlers/AbstractListHandler.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/dbutils2/handlers/AbstractListHandler.java 
b/src/main/java/org/apache/commons/dbutils2/handlers/AbstractListHandler.java
new file mode 100644
index 0000000..8b4b68e
--- /dev/null
+++ 
b/src/main/java/org/apache/commons/dbutils2/handlers/AbstractListHandler.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils2.handlers;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.dbutils2.ResultSetHandler;
+
+/**
+ * Abstract class that simplify development of <code>ResultSetHandler</code>
+ * classes that convert <code>ResultSet</code> into <code>List</code>.
+ *
+ * @param <T> the target List generic type
+ * @see org.apache.commons.dbutils2.ResultSetHandler
+ */
+public abstract class AbstractListHandler<T> implements 
ResultSetHandler<List<T>> {
+    /**
+     * Whole <code>ResultSet</code> handler. It produce <code>List</code> as
+     * result. To convert individual rows into Java objects it uses
+     * <code>handleRow(ResultSet)</code> method.
+     *
+     * @see #handleRow(ResultSet)
+     * @param rs <code>ResultSet</code> to process.
+     * @return a list of all rows in the result set
+     * @throws SQLException error occurs
+     */
+    @Override
+    public List<T> handle(ResultSet rs) throws SQLException {
+        List<T> rows = new ArrayList<T>();
+        while (rs.next()) {
+            rows.add(this.handleRow(rs));
+        }
+        return rows;
+    }
+
+    /**
+     * Row handler. Method converts current row into some Java object.
+     *
+     * @param rs <code>ResultSet</code> to process.
+     * @return row processing result
+     * @throws SQLException error occurs
+     */
+    protected abstract T handleRow(ResultSet rs) throws SQLException;
+}

Reply via email to