Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
RowSetDynaClass |
|
| 1.6666666666666667;1.667 |
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.io.Serializable; | |
23 | import java.sql.ResultSet; | |
24 | import java.sql.SQLException; | |
25 | import java.util.ArrayList; | |
26 | import java.util.List; | |
27 | ||
28 | ||
29 | /** | |
30 | * <p>Implementation of {@link DynaClass} that creates an in-memory collection | |
31 | * of {@link DynaBean}s representing the results of an SQL query. Once the | |
32 | * {@link DynaClass} instance has been created, the JDBC <code>ResultSet</code> | |
33 | * and <code>Statement</code> on which it is based can be closed, and the | |
34 | * underlying <code>Connection</code> can be returned to its connection pool | |
35 | * (if you are using one).</p> | |
36 | * | |
37 | * <p>The normal usage pattern is something like:</p> | |
38 | * <pre> | |
39 | * Connection conn = ...; // Acquire connection from pool | |
40 | * Statement stmt = conn.createStatement(); | |
41 | * ResultSet rs = stmt.executeQuery("SELECT ..."); | |
42 | * RowSetDynaClass rsdc = new RowSetDynaClass(rs); | |
43 | * rs.close(); | |
44 | * stmt.close(); | |
45 | * ...; // Return connection to pool | |
46 | * List rows = rsdc.getRows(); | |
47 | * ...; // Process the rows as desired | |
48 | * </pre> | |
49 | * | |
50 | * <p>Each column in the result set will be represented as a {@link DynaBean} | |
51 | * property of the corresponding name (optionally forced to lower case | |
52 | * for portability). There will be one {@link DynaBean} in the | |
53 | * <code>List</code> returned by <code>getRows()</code> for each | |
54 | * row in the original <code>ResultSet</code>.</p> | |
55 | * | |
56 | * <p>In general, instances of {@link RowSetDynaClass} can be serialized | |
57 | * and deserialized, which will automatically include the list of | |
58 | * {@link DynaBean}s representing the data content. The only exception | |
59 | * to this rule would be when the underlying property values that were | |
60 | * copied from the <code>ResultSet</code> originally cannot themselves | |
61 | * be serialized. Therefore, a {@link RowSetDynaClass} makes a very | |
62 | * convenient mechanism for transporting data sets to remote Java-based | |
63 | * application components.</p> | |
64 | * | |
65 | * @author Craig R. McClanahan | |
66 | * @version $Revision: 926685 $ $Date: 2010-03-23 13:59:08 -0400 (Tue, 23 Mar 2010) $ | |
67 | */ | |
68 | ||
69 | 1532 | public class RowSetDynaClass extends JDBCDynaClass implements DynaClass, Serializable { |
70 | ||
71 | ||
72 | // ----------------------------------------------------- Instance variables | |
73 | ||
74 | /** | |
75 | * <p>Limits the size of the returned list. The call to | |
76 | * <code>getRows()</code> will return at most limit number of rows. | |
77 | * If less than or equal to 0, does not limit the size of the result. | |
78 | */ | |
79 | 12 | protected int limit = -1; |
80 | ||
81 | /** | |
82 | * <p>The list of {@link DynaBean}s representing the contents of | |
83 | * the original <code>ResultSet</code> on which this | |
84 | * {@link RowSetDynaClass} was based.</p> | |
85 | */ | |
86 | 12 | protected List rows = new ArrayList(); |
87 | ||
88 | // ----------------------------------------------------------- Constructors | |
89 | ||
90 | ||
91 | /** | |
92 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
93 | * <code>ResultSet</code>. The property names corresponding | |
94 | * to column names in the result set will be lower cased.</p> | |
95 | * | |
96 | * @param resultSet The result set to be wrapped | |
97 | * | |
98 | * @exception NullPointerException if <code>resultSet</code> | |
99 | * is <code>null</code> | |
100 | * @exception SQLException if the metadata for this result set | |
101 | * cannot be introspected | |
102 | */ | |
103 | public RowSetDynaClass(ResultSet resultSet) throws SQLException { | |
104 | ||
105 | 10 | this(resultSet, true, -1); |
106 | ||
107 | 10 | } |
108 | ||
109 | /** | |
110 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
111 | * <code>ResultSet</code>. The property names corresponding | |
112 | * to column names in the result set will be lower cased.</p> | |
113 | * | |
114 | * If <code>limit</code> is not less than 0, max <code>limit</code> | |
115 | * number of rows will be copied into the list. | |
116 | * | |
117 | * @param resultSet The result set to be wrapped | |
118 | * @param limit The maximum for the size of the result. | |
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 RowSetDynaClass(ResultSet resultSet, int limit) throws SQLException { | |
126 | ||
127 | 1 | this(resultSet, true, limit); |
128 | ||
129 | 1 | } |
130 | ||
131 | ||
132 | /** | |
133 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
134 | * <code>ResultSet</code>. The property names corresponding | |
135 | * to the column names in the result set will be lower cased or not, | |
136 | * depending on the specified <code>lowerCase</code> value.</p> | |
137 | * | |
138 | * If <code>limit</code> is not less than 0, max <code>limit</code> | |
139 | * number of rows will be copied into the resultset. | |
140 | * | |
141 | * | |
142 | * @param resultSet The result set to be wrapped | |
143 | * @param lowerCase Should property names be lower cased? | |
144 | * | |
145 | * @exception NullPointerException if <code>resultSet</code> | |
146 | * is <code>null</code> | |
147 | * @exception SQLException if the metadata for this result set | |
148 | * cannot be introspected | |
149 | */ | |
150 | public RowSetDynaClass(ResultSet resultSet, boolean lowerCase) | |
151 | throws SQLException { | |
152 | 1 | this(resultSet, lowerCase, -1); |
153 | ||
154 | 1 | } |
155 | ||
156 | /** | |
157 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
158 | * <code>ResultSet</code>. The property names corresponding | |
159 | * to the column names in the result set will be lower cased or not, | |
160 | * depending on the specified <code>lowerCase</code> value.</p> | |
161 | * | |
162 | * <p><strong>WARNING</strong> - If you specify <code>false</code> | |
163 | * for <code>lowerCase</code>, the returned property names will | |
164 | * exactly match the column names returned by your JDBC driver. | |
165 | * Because different drivers might return column names in different | |
166 | * cases, the property names seen by your application will vary | |
167 | * depending on which JDBC driver you are using.</p> | |
168 | * | |
169 | * @param resultSet The result set to be wrapped | |
170 | * @param lowerCase Should property names be lower cased? | |
171 | * @param limit Maximum limit for the <code>List</code> of {@link DynaBean} | |
172 | * | |
173 | * @exception NullPointerException if <code>resultSet</code> | |
174 | * is <code>null</code> | |
175 | * @exception SQLException if the metadata for this result set | |
176 | * cannot be introspected | |
177 | */ | |
178 | public RowSetDynaClass(ResultSet resultSet, boolean lowerCase, int limit) | |
179 | throws SQLException { | |
180 | ||
181 | 12 | this(resultSet, lowerCase, limit, false); |
182 | ||
183 | 12 | } |
184 | ||
185 | /** | |
186 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
187 | * <code>ResultSet</code>. The property names corresponding | |
188 | * to the column names in the result set will be lower cased or not, | |
189 | * depending on the specified <code>lowerCase</code> value.</p> | |
190 | * | |
191 | * <p><strong>WARNING</strong> - If you specify <code>false</code> | |
192 | * for <code>lowerCase</code>, the returned property names will | |
193 | * exactly match the column names returned by your JDBC driver. | |
194 | * Because different drivers might return column names in different | |
195 | * cases, the property names seen by your application will vary | |
196 | * depending on which JDBC driver you are using.</p> | |
197 | * | |
198 | * @param resultSet The result set to be wrapped | |
199 | * @param lowerCase Should property names be lower cased? | |
200 | * @param useColumnLabel true if the column label should be used, otherwise false | |
201 | * | |
202 | * @exception NullPointerException if <code>resultSet</code> | |
203 | * is <code>null</code> | |
204 | * @exception SQLException if the metadata for this result set | |
205 | * cannot be introspected | |
206 | * @since 1.8.3 | |
207 | */ | |
208 | public RowSetDynaClass(ResultSet resultSet, boolean lowerCase, boolean useColumnLabel) | |
209 | throws SQLException { | |
210 | 0 | this(resultSet, lowerCase, -1, useColumnLabel); |
211 | ||
212 | 0 | } |
213 | ||
214 | /** | |
215 | * <p>Construct a new {@link RowSetDynaClass} for the specified | |
216 | * <code>ResultSet</code>. The property names corresponding | |
217 | * to the column names in the result set will be lower cased or not, | |
218 | * depending on the specified <code>lowerCase</code> value.</p> | |
219 | * | |
220 | * <p><strong>WARNING</strong> - If you specify <code>false</code> | |
221 | * for <code>lowerCase</code>, the returned property names will | |
222 | * exactly match the column names returned by your JDBC driver. | |
223 | * Because different drivers might return column names in different | |
224 | * cases, the property names seen by your application will vary | |
225 | * depending on which JDBC driver you are using.</p> | |
226 | * | |
227 | * @param resultSet The result set to be wrapped | |
228 | * @param lowerCase Should property names be lower cased? | |
229 | * @param limit Maximum limit for the <code>List</code> of {@link DynaBean} | |
230 | * @param useColumnLabel true if the column label should be used, otherwise false | |
231 | * | |
232 | * @exception NullPointerException if <code>resultSet</code> | |
233 | * is <code>null</code> | |
234 | * @exception SQLException if the metadata for this result set | |
235 | * cannot be introspected | |
236 | * @since 1.8.3 | |
237 | */ | |
238 | public RowSetDynaClass(ResultSet resultSet, boolean lowerCase, int limit, boolean useColumnLabel) | |
239 | 12 | throws SQLException { |
240 | ||
241 | 12 | if (resultSet == null) { |
242 | 0 | throw new NullPointerException(); |
243 | } | |
244 | 12 | this.lowerCase = lowerCase; |
245 | 12 | this.limit = limit; |
246 | 12 | setUseColumnLabel(useColumnLabel); |
247 | 12 | introspect(resultSet); |
248 | 12 | copy(resultSet); |
249 | ||
250 | 12 | } |
251 | ||
252 | /** | |
253 | * <p>Return a <code>List</code> containing the {@link DynaBean}s that | |
254 | * represent the contents of each <code>Row</code> from the | |
255 | * <code>ResultSet</code> that was the basis of this | |
256 | * {@link RowSetDynaClass} instance. These {@link DynaBean}s are | |
257 | * disconnected from the database itself, so there is no problem with | |
258 | * modifying the contents of the list, or the values of the properties | |
259 | * of these {@link DynaBean}s. However, it is the application's | |
260 | * responsibility to persist any such changes back to the database, | |
261 | * if it so desires.</p> | |
262 | * | |
263 | * @return A <code>List</code> of {@link DynaBean} instances | |
264 | */ | |
265 | public List getRows() { | |
266 | ||
267 | 5 | return (this.rows); |
268 | ||
269 | } | |
270 | ||
271 | ||
272 | // ------------------------------------------------------ Protected Methods | |
273 | ||
274 | ||
275 | /** | |
276 | * <p>Copy the column values for each row in the specified | |
277 | * <code>ResultSet</code> into a newly created {@link DynaBean}, and add | |
278 | * this bean to the list of {@link DynaBean}s that will later by | |
279 | * returned by a call to <code>getRows()</code>.</p> | |
280 | * | |
281 | * @param resultSet The <code>ResultSet</code> whose data is to be | |
282 | * copied | |
283 | * | |
284 | * @exception SQLException if an error is encountered copying the data | |
285 | */ | |
286 | protected void copy(ResultSet resultSet) throws SQLException { | |
287 | ||
288 | 12 | int cnt = 0; |
289 | 70 | while (resultSet.next() && (limit < 0 || cnt++ < limit) ) { |
290 | 58 | DynaBean bean = createDynaBean(); |
291 | 812 | for (int i = 0; i < properties.length; i++) { |
292 | 754 | String name = properties[i].getName(); |
293 | 754 | Object value = getObject(resultSet, name); |
294 | 754 | bean.set(name, value); |
295 | } | |
296 | 58 | rows.add(bean); |
297 | 58 | } |
298 | ||
299 | 12 | } |
300 | ||
301 | ||
302 | /** | |
303 | * <p>Create and return a new {@link DynaBean} instance to be used for | |
304 | * representing a row in the underlying result set.</p> | |
305 | * | |
306 | * @return A new <code>DynaBean</code> instance | |
307 | */ | |
308 | protected DynaBean createDynaBean() { | |
309 | ||
310 | 58 | return (new BasicDynaBean(this)); |
311 | ||
312 | } | |
313 | ||
314 | ||
315 | } |