View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18
    19  package org.apache.commons.beanutils;
    20
    21
    22  import java.sql.ResultSet;
    23  import java.sql.SQLException;
    24  import java.util.Iterator;
    25
    26
    27  /***
    28   * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the
    29   * <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>.
    30   * The normal usage pattern is something like:</p>
    31   * <pre>
    32   *   ResultSet rs = ...;
    33   *   ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
    34   *   Iterator rows = rsdc.iterator();
    35   *   while (rows.hasNext())  {
    36   *     DynaBean row = (DynaBean) rows.next();
    37   *     ... process this row ...
    38   *   }
    39   *   rs.close();
    40   * </pre>
    41   *
    42   * <p>Each column in the result set will be represented as a DynaBean
    43   * property of the corresponding name (optionally forced to lower case
    44   * for portability).</p>
    45   *
    46   * <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by
    47   * this class, or from the <code>Iterator</code> returned by the
    48   * <code>iterator()</code> method, is directly linked to the row that the
    49   * underlying result set is currently positioned at.  This has the following
    50   * implications:</p>
    51   * <ul>
    52   * <li>Once you retrieve a different {@link DynaBean} instance, you should
    53   *     no longer use any previous instance.</li>
    54   * <li>Changing the position of the underlying result set will change the
    55   *     data that the {@link DynaBean} references.</li>
    56   * <li>Once the underlying result set is closed, the {@link DynaBean}
    57   *     instance may no longer be used.</li>
    58   * </ul>
    59   *
    60   * <p>Any database data that you wish to utilize outside the context of the
    61   * current row of an open result set must be copied.  For example, you could
    62   * use the following code to create standalone copies of the information in
    63   * a result set:</p>
    64   * <pre>
    65   *   ArrayList results = new ArrayList(); // To hold copied list
    66   *   ResultSetDynaClass rsdc = ...;
    67   *   DynaProperty[] properties = rsdc.getDynaProperties();
    68   *   BasicDynaClass bdc =
    69   *     new BasicDynaClass("foo", BasicDynaBean.class,
    70   *                        rsdc.getDynaProperties());
    71   *   Iterator rows = rsdc.iterator();
    72   *   while (rows.hasNext()) {
    73   *     DynaBean oldRow = (DynaBean) rows.next();
    74   *     DynaBean newRow = bdc.newInstance();
    75   *     PropertyUtils.copyProperties(newRow, oldRow);
    76   *     results.add(newRow);
    77   *   }
    78   * </pre>
    79   *
    80   * @author Craig R. McClanahan
    81   * @version $Revision: 556229 $ $Date: 2007-07-14 07:11:19 +0100 (Sat, 14 Jul 2007) $
    82   */
    83
    84  public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass {
    85
    86
    87      // ----------------------------------------------------------- Constructors
    88
    89
    90      /***
    91       * <p>Construct a new ResultSetDynaClass for the specified
    92       * <code>ResultSet</code>.  The property names corresponding
    93       * to column names in the result set will be lower cased.</p>
    94       *
    95       * @param resultSet The result set to be wrapped
    96       *
    97       * @exception NullPointerException if <code>resultSet</code>
    98       *  is <code>null</code>
    99       * @exception SQLException if the metadata for this result set
    100      *  cannot be introspected
    101      */
    102     public ResultSetDynaClass(ResultSet resultSet) throws SQLException {
    103
    104         this(resultSet, true);
    105
    106     }
    107
    108
    109     /***
    110      * <p>Construct a new ResultSetDynaClass for the specified
    111      * <code>ResultSet</code>.  The property names corresponding
    112      * to the column names in the result set will be lower cased or not,
    113      * depending on the specified <code>lowerCase</code> value.</p>
    114      *
    115      * <p><strong>WARNING</strong> - If you specify <code>false</code>
    116      * for <code>lowerCase</code>, the returned property names will
    117      * exactly match the column names returned by your JDBC driver.
    118      * Because different drivers might return column names in different
    119      * cases, the property names seen by your application will vary
    120      * depending on which JDBC driver you are using.</p>
    121      *
    122      * @param resultSet The result set to be wrapped
    123      * @param lowerCase Should property names be lower cased?
    124      *
    125      * @exception NullPointerException if <code>resultSet</code>
    126      *  is <code>null</code>
    127      * @exception SQLException if the metadata for this result set
    128      *  cannot be introspected
    129      */
    130     public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase)
    131         throws SQLException {
    132
    133         if (resultSet == null) {
    134             throw new NullPointerException();
    135         }
    136         this.resultSet = resultSet;
    137         this.lowerCase = lowerCase;
    138         introspect(resultSet);
    139
    140     }
    141
    142
    143     // ----------------------------------------------------- Instance Variables
    144
    145
    146     /***
    147      * <p>The <code>ResultSet</code> we are wrapping.</p>
    148      */
    149     protected ResultSet resultSet = null;
    150
    151
    152     // --------------------------------------------------------- Public Methods
    153
    154
    155     /***
    156      * <p>Return an <code>Iterator</code> of {@link DynaBean} instances for
    157      * each row of the wrapped <code>ResultSet</code>, in "forward" order.
    158      * Unless the underlying result set supports scrolling, this method
    159      * should be called only once.</p>
    160      * @return An <code>Iterator</code> of {@link DynaBean} instances
    161      */
    162     public Iterator iterator() {
    163
    164         return (new ResultSetIterator(this));
    165
    166     }
    167
    168
    169     /***
    170      * Get a value from the {@link ResultSet} for the specified
    171      * property name.
    172      *
    173      * @param name The property name
    174      * @return The value
    175      * @throws SQLException if an error occurs
    176      */
    177     public Object getObjectFromResultSet(String name) throws SQLException {
    178         return getObject(getResultSet(), name);
    179     }
    180
    181     // -------------------------------------------------------- Package Methods
    182
    183
    184     /***
    185      * <p>Return the result set we are wrapping.</p>
    186      */
    187     ResultSet getResultSet() {
    188
    189         return (this.resultSet);
    190
    191     }
    192
    193
    194     // ------------------------------------------------------ Protected Methods
    195
    196     /***
    197      * <p>Loads the class of the given name which by default uses the class loader used
    198      * to load this library.
    199      * Dervations of this class could implement alternative class loading policies such as
    200      * using custom ClassLoader or using the Threads's context class loader etc.
    201      * </p>
    202      * @param className The name of the class to load
    203      * @return The loaded class
    204      * @throws SQLException if the class cannot be loaded
    205      */
    206     protected Class loadClass(String className) throws SQLException {
    207
    208         try {
    209             return getClass().getClassLoader().loadClass(className);
    210         }
    211         catch (Exception e) {
    212             throw new SQLException("Cannot load column class '" +
    213                                    className + "': " + e);
    214         }
    215     }
    216 }