Open Source Repository

Home /commons-beanutils/commons-beanutils-1.8.3 | Repository Home


org/apache/commons/beanutils/ResultSetDynaClass.java
/*
 * 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.beanutils;


import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;


/**
 <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the
 <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>.
 * The normal usage pattern is something like:</p>
 <pre>
 *   ResultSet rs = ...;
 *   ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
 *   Iterator rows = rsdc.iterator();
 *   while (rows.hasNext())  {
 *     DynaBean row = (DynaBean) rows.next();
 *     ... process this row ...
 *   }
 *   rs.close();
 </pre>
 *
 <p>Each column in the result set will be represented as a DynaBean
 * property of the corresponding name (optionally forced to lower case
 * for portability).</p>
 *
 <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by
 * this class, or from the <code>Iterator</code> returned by the
 <code>iterator()</code> method, is directly linked to the row that the
 * underlying result set is currently positioned at.  This has the following
 * implications:</p>
 <ul>
 <li>Once you retrieve a different {@link DynaBean} instance, you should
 *     no longer use any previous instance.</li>
 <li>Changing the position of the underlying result set will change the
 *     data that the {@link DynaBean} references.</li>
 <li>Once the underlying result set is closed, the {@link DynaBean}
 *     instance may no longer be used.</li>
 </ul>
 *
 <p>Any database data that you wish to utilize outside the context of the
 * current row of an open result set must be copied.  For example, you could
 * use the following code to create standalone copies of the information in
 * a result set:</p>
 <pre>
 *   ArrayList results = new ArrayList(); // To hold copied list
 *   ResultSetDynaClass rsdc = ...;
 *   DynaProperty[] properties = rsdc.getDynaProperties();
 *   BasicDynaClass bdc =
 *     new BasicDynaClass("foo", BasicDynaBean.class,
 *                        rsdc.getDynaProperties());
 *   Iterator rows = rsdc.iterator();
 *   while (rows.hasNext()) {
 *     DynaBean oldRow = (DynaBean) rows.next();
 *     DynaBean newRow = bdc.newInstance();
 *     PropertyUtils.copyProperties(newRow, oldRow);
 *     results.add(newRow);
 *   }
 </pre>
 *
 @author Craig R. McClanahan
 @version $Revision: 926685 $ $Date: 2010-03-23 17:59:08 +0000 (Tue, 23 Mar 2010) $
 */

public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass {


    // ----------------------------------------------------------- Constructors


    /**
     <p>Construct a new ResultSetDynaClass for the specified
     <code>ResultSet</code>.  The property names corresponding
     * to column names in the result set will be lower cased.</p>
     *
     @param resultSet The result set to be wrapped
     *
     @exception NullPointerException if <code>resultSet</code>
     *  is <code>null</code>
     @exception SQLException if the metadata for this result set
     *  cannot be introspected
     */
    public ResultSetDynaClass(ResultSet resultSetthrows SQLException {

        this(resultSet, true);

    }


    /**
     <p>Construct a new ResultSetDynaClass for the specified
     <code>ResultSet</code>.  The property names corresponding
     * to the column names in the result set will be lower cased or not,
     * depending on the specified <code>lowerCase</code> value.</p>
     *
     <p><strong>WARNING</strong> - If you specify <code>false</code>
     * for <code>lowerCase</code>, the returned property names will
     * exactly match the column names returned by your JDBC driver.
     * Because different drivers might return column names in different
     * cases, the property names seen by your application will vary
     * depending on which JDBC driver you are using.</p>
     *
     @param resultSet The result set to be wrapped
     @param lowerCase Should property names be lower cased?
     *
     @exception NullPointerException if <code>resultSet</code>
     *  is <code>null</code>
     @exception SQLException if the metadata for this result set
     *  cannot be introspected
     */
    public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase)
        throws SQLException {

        this(resultSet, lowerCase, false);

    }


    /**
     <p>Construct a new ResultSetDynaClass for the specified
     <code>ResultSet</code>.  The property names corresponding
     * to the column names in the result set will be lower cased or not,
     * depending on the specified <code>lowerCase</code> value.</p>
     *
     <p><strong>WARNING</strong> - If you specify <code>false</code>
     * for <code>lowerCase</code>, the returned property names will
     * exactly match the column names returned by your JDBC driver.
     * Because different drivers might return column names in different
     * cases, the property names seen by your application will vary
     * depending on which JDBC driver you are using.</p>
     *
     @param resultSet The result set to be wrapped
     @param lowerCase Should property names be lower cased?
     @param useColumnLabel true if the column label should be used, otherwise false
     *
     @exception NullPointerException if <code>resultSet</code>
     *  is <code>null</code>
     @exception SQLException if the metadata for this result set
     *  cannot be introspected
     @since 1.8.3
     */
    public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase, boolean useColumnLabel)
        throws SQLException {

        if (resultSet == null) {
            throw new NullPointerException();
        }
        this.resultSet = resultSet;
        this.lowerCase = lowerCase;
        setUseColumnLabel(useColumnLabel);
        introspect(resultSet);

    }


    // ----------------------------------------------------- Instance Variables


    /**
     <p>The <code>ResultSet</code> we are wrapping.</p>
     */
    protected ResultSet resultSet = null;


    // --------------------------------------------------------- Public Methods


    /**
     <p>Return an <code>Iterator</code> of {@link DynaBean} instances for
     * each row of the wrapped <code>ResultSet</code>, in "forward" order.
     * Unless the underlying result set supports scrolling, this method
     * should be called only once.</p>
     @return An <code>Iterator</code> of {@link DynaBean} instances
     */
    public Iterator iterator() {

        return (new ResultSetIterator(this));

    }


    /**
     * Get a value from the {@link ResultSet} for the specified
     * property name.
     *
     @param name The property name
     @return The value
     @throws SQLException if an error occurs
     @since 1.8.0
     */
    public Object getObjectFromResultSet(String namethrows SQLException {
        return getObject(getResultSet(), name);
    }

    // -------------------------------------------------------- Package Methods


    /**
     <p>Return the result set we are wrapping.</p>
     */
    ResultSet getResultSet() {

        return (this.resultSet);

    }


    // ------------------------------------------------------ Protected Methods
    
    /**
     <p>Loads the class of the given name which by default uses the class loader used 
     * to load this library.
     * Dervations of this class could implement alternative class loading policies such as
     * using custom ClassLoader or using the Threads's context class loader etc.
     </p>
     @param className The name of the class to load
     @return The loaded class
     @throws SQLException if the class cannot be loaded
     */        
    protected Class loadClass(String classNamethrows SQLException {

        try {
            return getClass().getClassLoader().loadClass(className);
        
        catch (Exception e) {
            throw new SQLException("Cannot load column class '" +
                                   className + "': " + e);
        }
    }
}