commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dgra...@apache.org
Subject cvs commit: jakarta-commons-sandbox/mapper/src/share/org/apache/commons/mapper/jdbc JdbcHelper.java
Date Thu, 28 Aug 2003 01:37:57 GMT
dgraham     2003/08/27 18:37:57

  Modified:    mapper/src/share/org/apache/commons/mapper/jdbc
                        JdbcHelper.java
  Log:
  Replaced the old getField() methods with new, more flexible getField() methods.
  The new versions use ResultSet.getObject() to allow the JDBC driver
  to convert the data into a Java type matching the underlying column
  type instead of always returning a String.
  
  Revision  Changes    Path
  1.11      +252 -189  jakarta-commons-sandbox/mapper/src/share/org/apache/commons/mapper/jdbc/JdbcHelper.java
  
  Index: JdbcHelper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/mapper/src/share/org/apache/commons/mapper/jdbc/JdbcHelper.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- JdbcHelper.java	28 Aug 2003 00:13:37 -0000	1.10
  +++ JdbcHelper.java	28 Aug 2003 01:37:57 -0000	1.11
  @@ -66,6 +66,7 @@
   import java.sql.ResultSet;
   import java.sql.SQLException;
   import java.sql.Statement;
  +import java.util.ArrayList;
   import java.util.List;
   
   import javax.sql.DataSource;
  @@ -81,6 +82,22 @@
   public class JdbcHelper {
   
       /**
  +     * An implementation of StatementPreparer that fills a PreparedStatement 
  +     * with values from an Object[].
  +     */
  +    private static final StatementPreparer ARRAY_PREPARER =
  +        new StatementPreparer() {
  +        public void prepareStatement(PreparedStatement stmt, Object obj)
  +            throws SQLException {
  +
  +            Object[] args = (Object[]) obj;
  +            for (int i = 0; i < args.length; i++) {
  +                stmt.setObject(i + 1, args[i]);
  +            }
  +        }
  +    };
  +
  +    /**
        * An implementation of StatementPreparer that does nothing.  Useful when 
        * there are no replacement parameters to be set on the PreparedStatement.
        */
  @@ -92,18 +109,18 @@
       };
   
       /**
  -     * An implementation of StatementPreparer that fills a PreparedStatement 
  -     * with values from an Object[].
  +     * Places the first column from the first row into a List and returns it.
        */
  -    private static final StatementPreparer ARRAY_PREPARER =
  -        new StatementPreparer() {
  -        public void prepareStatement(PreparedStatement stmt, Object obj)
  -            throws SQLException {
  +    private static final ResultSetProcessor SCALAR_PROCESSOR =
  +        new ResultSetProcessor() {
  +        public List process(ResultSet rs) throws SQLException {
  +            List list = new ArrayList();
   
  -            Object[] args = (Object[]) obj;
  -            for (int i = 0; i < args.length; i++) {
  -                stmt.setObject(i + 1, args[i]);
  +            if (rs.next()) {
  +                list.add(rs.getObject(1));
               }
  +
  +            return list;
           }
       };
   
  @@ -132,44 +149,174 @@
       }
   
       /**
  -     * Executes the given INSERT, UPDATE, or DELETE SQL statement.  The 
  -     * statement is executed in it's own transaction that will be committed or 
  -     * rolled back depending on any SQLExceptions thrown.
  +     * Attempts to close the given connection wrapping any SQLExceptions that 
  +     * occur in a MapperException.  Typically, a mapper's methods throw 
  +     * MapperException rather than SQLException so this simplifies Connection 
  +     * cleanup.  Connection objects should <strong>always</strong> be closed
in 
  +     * case the DataSource is performing Connection pooling so the Connection 
  +     * can be returned to the pool.
  +     * @param conn The Connection to close.  A null value for this argument 
  +     * is legal.
  +     * @throws MapperException if an SQLException is thrown closing the 
  +     * Connection.
  +     */
  +    public void closeConnection(Connection conn) throws MapperException {
  +        try {
  +            if (conn != null) {
  +                conn.close();
  +            }
  +        } catch (SQLException e) {
  +            throw new MapperException(e);
  +        }
  +    }
  +
  +    /**
  +     * Attempts to close the given ResultSet wrapping any SQLExceptions that 
  +     * occur in a MapperException.
  +     * @param rs The ResultSet to close.  A null value for this argument is 
  +     * legal.
  +     * @throws MapperException if an SQLException is thrown closing the 
  +     * ResultSet.
  +     */
  +    public void closeResultSet(ResultSet rs) throws MapperException {
  +        try {
  +            if (rs != null) {
  +                rs.close();
  +            }
  +        } catch (SQLException e) {
  +            throw new MapperException(e);
  +        }
  +    }
  +
  +    /**
  +     * Attempts to close the given Statement wrapping any SQLExceptions that 
  +     * occur in a MapperException.  Typically, a mapper's methods throw 
  +     * MapperException rather than SQLException so this simplifies Statement 
  +     * cleanup.  Statement objects (especially PreparedStatements) should 
  +     * <strong>always</strong> be closed in case the DataSource is performing

  +     * Statement pooling so the Statement can be returned to the pool.
  +     * @param stmt The Statment to close.  A null value for this argument is 
  +     * legal.
  +     * @throws MapperException if an SQLException is thrown closing the 
  +     * Statement.
  +     */
  +    public void closeStatement(Statement stmt) throws MapperException {
  +        try {
  +            if (stmt != null) {
  +                stmt.close();
  +            }
  +        } catch (SQLException e) {
  +            throw new MapperException(e);
  +        }
  +    }
  +
  +    /**
  +     * When executeQuery() and executeUpdate() catch an SQLException they call
  +     * this factory method to generate a MapperException to throw to the 
  +     * caller.  This can be useful for generating a specific MapperException
  +     * subclass that is more descriptive of the error.  For example, this method
  +     * could examine the SQLState and ErrorCode of the SQLException to determine
  +     * that a unique constraint was violated and throw a 
  +     * UniqueFieldAlreadyExistsException. This implementation always returns 
  +     * a MapperException wrapping the given SQLException.
  +     * @param e The SQLException that caused the query to fail.
  +     * @return A MapperException for the given SQLException.  
  +     */
  +    protected MapperException createMapperException(SQLException e) {
  +        return new MapperException(e);
  +    }
  +
  +    /**
  +     * Executes the given SELECT SQL query and returns a List of results.  
  +     * This is useful for queries with only one replacement parameter and is 
  +     * the equivalent of calling 
  +     * <code>executeQuery(sql, new Object[] { param }, factory)</code>.
        * @param sql The SQL statement to execute.
  -     * @param preparer Initializes the PreparedStatement's IN (ie. '?') 
  -     * parameters.
  +     * @param param An object to fill one sql '?' marker with.
  +     * @param processor The processor to generate objects with.
  +     * @return A list of objects generated by the resultFactory.
  +     * @throws MapperException
  +     * @see #executeQuery(String, Object[], ResultSetProcessor)
  +     */
  +    public List executeQuery(String sql, Object param, ResultSetProcessor processor)
  +        throws MapperException {
  +
  +        return this.executeQuery(
  +            sql,
  +            ARRAY_PREPARER,
  +            new Object[] { param },
  +            processor);
  +    }
  +
  +    /**
  +     * Executes the given SELECT SQL query and returns a List of results.
  +     * @param sql The SQL statement to execute.
  +     * @param params An array of values to fill the sql '?' markers with.
  +     * @param processor The processor to generate objects with.
  +     * @return A list of objects generated by the resultFactory.
  +     * @throws MapperException
  +     * @see #executeQuery(String, StatementPreparer, Object, ResultSetProcessor)
  +     */
  +    public List executeQuery(
  +        String sql,
  +        Object[] params,
  +        ResultSetProcessor processor)
  +        throws MapperException {
  +
  +        return this.executeQuery(sql, ARRAY_PREPARER, params, processor);
  +    }
  +
  +    /**
  +     * Executes a query that doesn't need parameter replacement.
  +     * @param sql The SQL statement to execute.
  +     * @param processor The processor to generate objects with.
  +     * @return A list of objects generated by the resultFactory.
  +     * @throws MapperException
  +     * @see #executeQuery(String, StatementPreparer, Object, ResultSetProcessor)
  +     */
  +    public List executeQuery(String sql, ResultSetProcessor processor)
  +        throws MapperException {
  +
  +        return this.executeQuery(sql, NULL_PREPARER, null, processor);
  +    }
  +
  +    /**
  +     * Executes the given SELECT SQL query and returns a List of results.
  +     * @param sql The SQL statement to execute.
  +     * @param preparer Initializes the PreparedStatement's IN parameters.
        * @param prepareObject An object to pass to the preparer to setup the 
        * PreparedStatement.
  +     * @param processor The processor used to create the result objects from 
  +     * the ResultSet.
  +     * @return A list of objects generated by the processor.
        * @throws MapperException
  -     * @return The number of rows updated.
        */
  -    public int executeUpdate(
  +    public List executeQuery(
           String sql,
           StatementPreparer preparer,
  -        Object prepareObject)
  +        Object prepareObject,
  +        ResultSetProcessor processor)
           throws MapperException {
   
           Connection conn = null;
           PreparedStatement stmt = null;
  -        boolean autoCommit = false;
  -        int rows = 0;
  +        ResultSet rs = null;
  +
  +        List rows = null;
   
           try {
               conn = this.getConnection();
  -            autoCommit = conn.getAutoCommit(); // save old value
  -            conn.setAutoCommit(false); // single transaction.
  -
               stmt = conn.prepareStatement(sql);
  +
               preparer.prepareStatement(stmt, prepareObject);
  -            rows = stmt.executeUpdate();
   
  -            conn.commit();
  +            rs = stmt.executeQuery();
  +            rows = processor.process(rs);
   
           } catch (SQLException e) {
  -            this.rollback(conn);
               throw this.createMapperException(e);
           } finally {
  -            this.setAutoCommit(autoCommit, conn);
  +            this.closeResultSet(rs);
               this.closeStatement(stmt);
               this.closeConnection(conn);
           }
  @@ -180,14 +327,14 @@
       /**
        * Executes the given INSERT, UPDATE, or DELETE SQL statement.  The 
        * statement is executed in it's own transaction that will be committed or 
  -     * rolled back depending on any SQLExceptions thrown.
  +     * rolled back depending on any SQLExceptions thrown.  This is 
  +     * useful for queries without any replacement parameters.
        * @param sql The SQL statement to execute.
  -     * @param params An array of values to fill the sql '?' markers with.
        * @throws MapperException
        * @return The number of rows updated.
        */
  -    public int executeUpdate(String sql, Object[] params) throws MapperException {
  -        return this.executeUpdate(sql, ARRAY_PREPARER, params);
  +    public int executeUpdate(String sql) throws MapperException {
  +        return this.executeUpdate(sql, NULL_PREPARER, null);
       }
   
       /**
  @@ -208,53 +355,55 @@
       /**
        * Executes the given INSERT, UPDATE, or DELETE SQL statement.  The 
        * statement is executed in it's own transaction that will be committed or 
  -     * rolled back depending on any SQLExceptions thrown.  This is 
  -     * useful for queries without any replacement parameters.
  +     * rolled back depending on any SQLExceptions thrown.
        * @param sql The SQL statement to execute.
  +     * @param params An array of values to fill the sql '?' markers with.
        * @throws MapperException
        * @return The number of rows updated.
        */
  -    public int executeUpdate(String sql) throws MapperException {
  -        return this.executeUpdate(sql, NULL_PREPARER, null);
  +    public int executeUpdate(String sql, Object[] params) throws MapperException {
  +        return this.executeUpdate(sql, ARRAY_PREPARER, params);
       }
   
       /**
  -     * Executes the given SELECT SQL query and returns a List of results.
  +     * Executes the given INSERT, UPDATE, or DELETE SQL statement.  The 
  +     * statement is executed in it's own transaction that will be committed or 
  +     * rolled back depending on any SQLExceptions thrown.
        * @param sql The SQL statement to execute.
  -     * @param preparer Initializes the PreparedStatement's IN parameters.
  +     * @param preparer Initializes the PreparedStatement's IN (ie. '?') 
  +     * parameters.
        * @param prepareObject An object to pass to the preparer to setup the 
        * PreparedStatement.
  -     * @param processor The processor used to create the result objects from 
  -     * the ResultSet.
  -     * @return A list of objects generated by the processor.
        * @throws MapperException
  +     * @return The number of rows updated.
        */
  -    public List executeQuery(
  +    public int executeUpdate(
           String sql,
           StatementPreparer preparer,
  -        Object prepareObject,
  -        ResultSetProcessor processor)
  +        Object prepareObject)
           throws MapperException {
   
           Connection conn = null;
           PreparedStatement stmt = null;
  -        ResultSet rs = null;
  -
  -        List rows = null;
  +        boolean autoCommit = false;
  +        int rows = 0;
   
           try {
               conn = this.getConnection();
  -            stmt = conn.prepareStatement(sql);
  +            autoCommit = conn.getAutoCommit(); // save old value
  +            conn.setAutoCommit(false); // single transaction.
   
  +            stmt = conn.prepareStatement(sql);
               preparer.prepareStatement(stmt, prepareObject);
  +            rows = stmt.executeUpdate();
   
  -            rs = stmt.executeQuery();
  -            rows = processor.process(rs);
  +            conn.commit();
   
           } catch (SQLException e) {
  +            this.rollback(conn);
               throw this.createMapperException(e);
           } finally {
  -            this.closeResultSet(rs);
  +            this.setAutoCommit(autoCommit, conn);
               this.closeStatement(stmt);
               this.closeConnection(conn);
           }
  @@ -263,73 +412,69 @@
       }
   
       /**
  -     * When executeQuery() and executeUpdate() catch an SQLException they call
  -     * this factory method to generate a MapperException to throw to the 
  -     * caller.  This can be useful for generating a specific MapperException
  -     * subclass that is more descriptive of the error.  For example, this method
  -     * could examine the SQLState and ErrorCode of the SQLException to determine
  -     * that a unique constraint was violated and throw a 
  -     * UniqueFieldAlreadyExistsException. This implementation always returns 
  -     * a MapperException wrapping the given SQLException.
  -     * @param e The SQLException that caused the query to fail.
  -     * @return A MapperException for the given SQLException.  
  +     * JdbcHelper uses this method internally whenever it needs a database 
  +     * Connection.  This implementation retrieves a Connection from the 
  +     * DataSource.  Subclasses can override this method to change how 
  +     * Connections are retrieved, perhaps supplying a username and password 
  +     * other than what was configured in the DataSource. 
  +     * @return A database Connection.
  +     * @throws SQLException
        */
  -    protected MapperException createMapperException(SQLException e) {
  -        return new MapperException(e);
  +    protected Connection getConnection() throws SQLException {
  +        return this.ds.getConnection();
       }
   
       /**
  -     * Executes the given SELECT SQL query and returns a List of results.
  -     * @param sql The SQL statement to execute.
  -     * @param params An array of values to fill the sql '?' markers with.
  -     * @param processor The processor to generate objects with.
  -     * @return A list of objects generated by the resultFactory.
  -     * @throws MapperException
  -     * @see #executeQuery(String, StatementPreparer, Object, ResultSetProcessor)
  +     * Returns the <code>DataSource</code> this helper is using.
        */
  -    public List executeQuery(
  -        String sql,
  -        Object[] params,
  -        ResultSetProcessor processor)
  -        throws MapperException {
  -
  -        return this.executeQuery(sql, ARRAY_PREPARER, params, processor);
  +    public DataSource getDataSource() {
  +        return this.ds;
       }
   
       /**
  -     * Executes the given SELECT SQL query and returns a List of results.  
  -     * This is useful for queries with only one replacement parameter and is 
  -     * the equivalent of calling 
  -     * <code>executeQuery(sql, new Object[] { param }, factory)</code>.
  -     * @param sql The SQL statement to execute.
  -     * @param param An object to fill one sql '?' marker with.
  -     * @param processor The processor to generate objects with.
  -     * @return A list of objects generated by the resultFactory.
  -     * @throws MapperException
  -     * @see #executeQuery(String, Object[], ResultSetProcessor)
  -     */
  -    public List executeQuery(String sql, Object param, ResultSetProcessor processor)
  -        throws MapperException {
  -
  -        return this.executeQuery(
  -            sql,
  -            ARRAY_PREPARER,
  -            new Object[] { param },
  -            processor);
  +     * Executes the query and returns the first column's value from the first 
  +     * returned row.  This is helpful when finding the last generated ID in 
  +     * a table but can be used to return any single column value.  This is 
  +     * equivalent to calling <code>getField(sql, new Object[] { param })</code>.
  +     * 
  +     * @param sql A valid SQL SELECT query that returns at least one column.
  +     * @param param One SQL IN parameter to fill the query with.
  +     * 
  +     * @return The first column from the first row as returned by 
  +     * <code>ResultSet.getObject(1)</code>.  The type of the returned object

  +     * will correspond to the underlying database column type.
  +     * 
  +     * @throws MapperException if a database access error occurs 
  +     * @throws IllegalArgumentException if the given query returned 0 rows.
  +     */
  +    public Object getField(String sql, Object param) throws MapperException {
  +        return this.getField(sql, new Object[] { param });
       }
   
       /**
  -     * Executes a query that doesn't need parameter replacement.
  -     * @param sql The SQL statement to execute.
  -     * @param processor The processor to generate objects with.
  -     * @return A list of objects generated by the resultFactory.
  -     * @throws MapperException
  -     * @see #executeQuery(String, StatementPreparer, Object, ResultSetProcessor)
  -     */
  -    public List executeQuery(String sql, ResultSetProcessor processor)
  -        throws MapperException {
  +     * Executes the query and returns the first column's value from the first 
  +     * returned row.  This is helpful when finding the last generated ID in 
  +     * a table but can be used to return any single column value.
  +     * 
  +     * @param sql A valid SQL SELECT query that returns at least one column.
  +     * @param params SQL IN parameters to fill the query with.
  +     * 
  +     * @return The first column from the first row as returned by 
  +     * <code>ResultSet.getObject(1)</code>.  The type of the returned object

  +     * will correspond to the underlying database column type.
  +     * 
  +     * @throws MapperException if a database access error occurs 
  +     * @throws IllegalArgumentException if the given query returned 0 rows.
  +     */
  +    public Object getField(String sql, Object[] params) throws MapperException {
  +        List found = this.executeQuery(sql, params, SCALAR_PROCESSOR);
  +
  +        if (found.isEmpty()) {
  +            throw new IllegalArgumentException(
  +                "Query: " + sql + " returned 0 columns.");
  +        }
   
  -        return this.executeQuery(sql, NULL_PREPARER, null, processor);
  +        return found.get(0);
       }
   
       /**
  @@ -369,88 +514,6 @@
                   throw new MapperException(e);
               }
           }
  -    }
  -
  -    /**
  -     * Attempts to close the given connection wrapping any SQLExceptions that 
  -     * occur in a MapperException.  Typically, a mapper's methods throw 
  -     * MapperException rather than SQLException so this simplifies Connection 
  -     * cleanup.  Connection objects should <strong>always</strong> be closed
in 
  -     * case the DataSource is performing Connection pooling so the Connection 
  -     * can be returned to the pool.
  -     * @param conn The Connection to close.  A null value for this argument 
  -     * is legal.
  -     * @throws MapperException if an SQLException is thrown closing the 
  -     * Connection.
  -     */
  -    public void closeConnection(Connection conn) throws MapperException {
  -        try {
  -            if (conn != null) {
  -                conn.close();
  -            }
  -        } catch (SQLException e) {
  -            throw new MapperException(e);
  -        }
  -    }
  -
  -    /**
  -     * Attempts to close the given Statement wrapping any SQLExceptions that 
  -     * occur in a MapperException.  Typically, a mapper's methods throw 
  -     * MapperException rather than SQLException so this simplifies Statement 
  -     * cleanup.  Statement objects (especially PreparedStatements) should 
  -     * <strong>always</strong> be closed in case the DataSource is performing

  -     * Statement pooling so the Statement can be returned to the pool.
  -     * @param stmt The Statment to close.  A null value for this argument is 
  -     * legal.
  -     * @throws MapperException if an SQLException is thrown closing the 
  -     * Statement.
  -     */
  -    public void closeStatement(Statement stmt) throws MapperException {
  -        try {
  -            if (stmt != null) {
  -                stmt.close();
  -            }
  -        } catch (SQLException e) {
  -            throw new MapperException(e);
  -        }
  -    }
  -
  -    /**
  -     * Attempts to close the given ResultSet wrapping any SQLExceptions that 
  -     * occur in a MapperException.
  -     * @param rs The ResultSet to close.  A null value for this argument is 
  -     * legal.
  -     * @throws MapperException if an SQLException is thrown closing the 
  -     * ResultSet.
  -     */
  -    public void closeResultSet(ResultSet rs) throws MapperException {
  -        try {
  -            if (rs != null) {
  -                rs.close();
  -            }
  -        } catch (SQLException e) {
  -            throw new MapperException(e);
  -        }
  -    }
  -
  -    /**
  -     * JdbcHelper uses this method internally whenever it needs a database 
  -     * Connection.  This implementation retrieves a Connection from the 
  -     * DataSource.  Subclasses can override this method to change how 
  -     * Connections are retrieved, perhaps supplying a username and password 
  -     * other than what was configured in the DataSource. 
  -     * @return A database Connection.
  -     * @throws SQLException
  -     */
  -    protected Connection getConnection() throws SQLException {
  -        return this.ds.getConnection();
  -    }
  -
  -    /**
  -     * Returns the <code>DataSource</code> this helper is using.
  -     */
  -    public DataSource getDataSource() {
  -        return this.ds;
       }
   
       /**
  
  
  

Mime
View raw message