001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.beanutils;
019:
020: import java.sql.ResultSet;
021: import java.sql.SQLException;
022: import java.util.Iterator;
023:
024: /**
025: * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the
026: * <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>.
027: * The normal usage pattern is something like:</p>
028: * <pre>
029: * ResultSet rs = ...;
030: * ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
031: * Iterator rows = rsdc.iterator();
032: * while (rows.hasNext()) {
033: * DynaBean row = (DynaBean) rows.next();
034: * ... process this row ...
035: * }
036: * rs.close();
037: * </pre>
038: *
039: * <p>Each column in the result set will be represented as a DynaBean
040: * property of the corresponding name (optionally forced to lower case
041: * for portability).</p>
042: *
043: * <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by
044: * this class, or from the <code>Iterator</code> returned by the
045: * <code>iterator()</code> method, is directly linked to the row that the
046: * underlying result set is currently positioned at. This has the following
047: * implications:</p>
048: * <ul>
049: * <li>Once you retrieve a different {@link DynaBean} instance, you should
050: * no longer use any previous instance.</li>
051: * <li>Changing the position of the underlying result set will change the
052: * data that the {@link DynaBean} references.</li>
053: * <li>Once the underlying result set is closed, the {@link DynaBean}
054: * instance may no longer be used.</li>
055: * </ul>
056: *
057: * <p>Any database data that you wish to utilize outside the context of the
058: * current row of an open result set must be copied. For example, you could
059: * use the following code to create standalone copies of the information in
060: * a result set:</p>
061: * <pre>
062: * ArrayList results = new ArrayList(); // To hold copied list
063: * ResultSetDynaClass rsdc = ...;
064: * DynaProperty[] properties = rsdc.getDynaProperties();
065: * BasicDynaClass bdc =
066: * new BasicDynaClass("foo", BasicDynaBean.class,
067: * rsdc.getDynaProperties());
068: * Iterator rows = rsdc.iterator();
069: * while (rows.hasNext()) {
070: * DynaBean oldRow = (DynaBean) rows.next();
071: * DynaBean newRow = bdc.newInstance();
072: * PropertyUtils.copyProperties(newRow, oldRow);
073: * results.add(newRow);
074: * }
075: * </pre>
076: *
077: * @author Craig R. McClanahan
078: * @version $Revision: 556229 $ $Date: 2007-07-14 07:11:19 +0100 (Sat, 14 Jul 2007) $
079: */
080:
081: public class ResultSetDynaClass extends JDBCDynaClass implements
082: DynaClass {
083:
084: // ----------------------------------------------------------- Constructors
085:
086: /**
087: * <p>Construct a new ResultSetDynaClass for the specified
088: * <code>ResultSet</code>. The property names corresponding
089: * to column names in the result set will be lower cased.</p>
090: *
091: * @param resultSet The result set to be wrapped
092: *
093: * @exception NullPointerException if <code>resultSet</code>
094: * is <code>null</code>
095: * @exception SQLException if the metadata for this result set
096: * cannot be introspected
097: */
098: public ResultSetDynaClass(ResultSet resultSet) throws SQLException {
099:
100: this (resultSet, true);
101:
102: }
103:
104: /**
105: * <p>Construct a new ResultSetDynaClass for the specified
106: * <code>ResultSet</code>. The property names corresponding
107: * to the column names in the result set will be lower cased or not,
108: * depending on the specified <code>lowerCase</code> value.</p>
109: *
110: * <p><strong>WARNING</strong> - If you specify <code>false</code>
111: * for <code>lowerCase</code>, the returned property names will
112: * exactly match the column names returned by your JDBC driver.
113: * Because different drivers might return column names in different
114: * cases, the property names seen by your application will vary
115: * depending on which JDBC driver you are using.</p>
116: *
117: * @param resultSet The result set to be wrapped
118: * @param lowerCase Should property names be lower cased?
119: *
120: * @exception NullPointerException if <code>resultSet</code>
121: * is <code>null</code>
122: * @exception SQLException if the metadata for this result set
123: * cannot be introspected
124: */
125: public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase)
126: throws SQLException {
127:
128: if (resultSet == null) {
129: throw new NullPointerException();
130: }
131: this .resultSet = resultSet;
132: this .lowerCase = lowerCase;
133: introspect(resultSet);
134:
135: }
136:
137: // ----------------------------------------------------- Instance Variables
138:
139: /**
140: * <p>The <code>ResultSet</code> we are wrapping.</p>
141: */
142: protected ResultSet resultSet = null;
143:
144: // --------------------------------------------------------- Public Methods
145:
146: /**
147: * <p>Return an <code>Iterator</code> of {@link DynaBean} instances for
148: * each row of the wrapped <code>ResultSet</code>, in "forward" order.
149: * Unless the underlying result set supports scrolling, this method
150: * should be called only once.</p>
151: * @return An <code>Iterator</code> of {@link DynaBean} instances
152: */
153: public Iterator iterator() {
154:
155: return (new ResultSetIterator(this ));
156:
157: }
158:
159: /**
160: * Get a value from the {@link ResultSet} for the specified
161: * property name.
162: *
163: * @param name The property name
164: * @return The value
165: * @throws SQLException if an error occurs
166: */
167: public Object getObjectFromResultSet(String name)
168: throws SQLException {
169: return getObject(getResultSet(), name);
170: }
171:
172: // -------------------------------------------------------- Package Methods
173:
174: /**
175: * <p>Return the result set we are wrapping.</p>
176: */
177: ResultSet getResultSet() {
178:
179: return (this .resultSet);
180:
181: }
182:
183: // ------------------------------------------------------ Protected Methods
184:
185: /**
186: * <p>Loads the class of the given name which by default uses the class loader used
187: * to load this library.
188: * Dervations of this class could implement alternative class loading policies such as
189: * using custom ClassLoader or using the Threads's context class loader etc.
190: * </p>
191: * @param className The name of the class to load
192: * @return The loaded class
193: * @throws SQLException if the class cannot be loaded
194: */
195: protected Class loadClass(String className) throws SQLException {
196:
197: try {
198: return getClass().getClassLoader().loadClass(className);
199: } catch (Exception e) {
200: throw new SQLException("Cannot load column class '"
201: + className + "': " + e);
202: }
203: }
204: }
|