1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils;
19
20
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.util.HashMap;
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: 1.15 $ $Date: 2004/02/28 13:18:33 $
82 */
83
84 public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass {
85
86
87
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
144
145
146 /**
147 * <p>The <code>ResultSet</code> we are wrapping.</p>
148 */
149 protected ResultSet resultSet = null;
150
151
152
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 */
161 public Iterator iterator() {
162
163 return (new ResultSetIterator(this));
164
165 }
166
167
168
169
170
171 /**
172 * <p>Return the result set we are wrapping.</p>
173 */
174 ResultSet getResultSet() {
175
176 return (this.resultSet);
177
178 }
179
180
181
182
183 /**
184 * <p>Loads the class of the given name which by default uses the class loader used
185 * to load this library.
186 * Dervations of this class could implement alternative class loading policies such as
187 * using custom ClassLoader or using the Threads's context class loader etc.
188 * </p>
189 */
190 protected Class loadClass(String className) throws SQLException {
191
192 try {
193 return getClass().getClassLoader().loadClass(className);
194 }
195 catch (Exception e) {
196 throw new SQLException("Cannot load column class '" +
197 className + "': " + e);
198 }
199 }
200 }