1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbutils;
18
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.Method;
21 import java.sql.ResultSet;
22 import java.sql.ResultSetMetaData;
23 import java.sql.SQLException;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.Iterator;
27
28 /**
29 * MockResultSet dynamically implements the ResultSet interface.
30 */
31 public class MockResultSet implements InvocationHandler {
32
33 /**
34 * Create a <code>MockResultSet</code> proxy object. This is equivalent to:
35 * <pre>
36 * ProxyFactory.instance().createResultSet(new MockResultSet(metaData, rows));
37 * </pre>
38 *
39 * @param metaData
40 * @param rows A null value indicates an empty <code>ResultSet</code>.
41 */
42 public static ResultSet create(ResultSetMetaData metaData,
43 Object[][] rows) {
44 return ProxyFactory.instance().createResultSet(
45 new MockResultSet(metaData, rows));
46 }
47
48 private Object[] currentRow = null;
49
50 private Iterator iter = null;
51
52 private ResultSetMetaData metaData = null;
53
54 private Boolean wasNull = Boolean.FALSE;
55
56 /**
57 * MockResultSet constructor.
58 * @param metaData
59 * @param rows A null value indicates an empty <code>ResultSet</code>.
60 */
61 public MockResultSet(ResultSetMetaData metaData, Object[][] rows) {
62 super();
63 this.metaData = metaData;
64 this.iter = (rows == null)
65 ? Collections.EMPTY_LIST.iterator()
66 : Arrays.asList(rows).iterator();
67 }
68
69 /**
70 * The get* methods can have an int column index or a String column name as
71 * the parameter. This method handles both cases and returns the column
72 * index that the client is trying to get at.
73 * @param args
74 * @return A column index.
75 * @throws SQLException if a database access error occurs
76 */
77 private int columnIndex(Object[] args) throws SQLException {
78
79 if (args[0] instanceof Integer) {
80 return ((Integer) args[0]).intValue();
81
82 } else if (args[0] instanceof String) {
83 return this.columnNameToIndex((String) args[0]);
84
85 } else {
86 throw new SQLException(args[0] + " must be Integer or String");
87 }
88 }
89
90 /**
91 * Returns the column index for the given column name.
92 * @return A 1 based index
93 * @throws SQLException if the column name is invalid
94 */
95 private int columnNameToIndex(String columnName) throws SQLException {
96 for (int i = 0; i < this.currentRow.length; i++) {
97 int c = i + 1;
98 if (this.metaData.getColumnName(c).equalsIgnoreCase(columnName)) {
99 return c;
100 }
101 }
102
103 throw new SQLException(columnName + " is not a valid column name.");
104 }
105
106 /**
107 * Gets the boolean value at the given column index.
108 * @param columnIndex A 1 based index.
109 * @throws SQLException if a database access error occurs
110 */
111 protected Object getBoolean(int columnIndex) throws SQLException {
112 Object obj = this.currentRow[columnIndex - 1];
113 this.setWasNull(obj);
114
115 try {
116 return (obj == null)
117 ? Boolean.FALSE
118 : Boolean.valueOf(obj.toString());
119
120 } catch (NumberFormatException e) {
121 throw new SQLException(e.getMessage());
122 }
123 }
124
125 /**
126 * Gets the byte value at the given column index.
127 * @param columnIndex A 1 based index.
128 * @throws SQLException if a database access error occurs
129 */
130 protected Object getByte(int columnIndex) throws SQLException {
131 Object obj = this.currentRow[columnIndex - 1];
132 this.setWasNull(obj);
133
134 try {
135 return (obj == null)
136 ? new Byte((byte) 0)
137 : Byte.valueOf(obj.toString());
138
139 } catch (NumberFormatException e) {
140 throw new SQLException(e.getMessage());
141 }
142 }
143
144 /**
145 * Gets the double value at the given column index.
146 * @param columnIndex A 1 based index.
147 * @throws SQLException if a database access error occurs
148 */
149 protected Object getDouble(int columnIndex) throws SQLException {
150 Object obj = this.currentRow[columnIndex - 1];
151 this.setWasNull(obj);
152
153 try {
154 return (obj == null)
155 ? new Double(0)
156 : Double.valueOf(obj.toString());
157
158 } catch (NumberFormatException e) {
159 throw new SQLException(e.getMessage());
160 }
161 }
162
163 /**
164 * Gets the float value at the given column index.
165 * @param columnIndex A 1 based index.
166 * @throws SQLException if a database access error occurs
167 */
168 protected Object getFloat(int columnIndex) throws SQLException {
169 Object obj = this.currentRow[columnIndex - 1];
170 this.setWasNull(obj);
171
172 try {
173 return (obj == null) ? new Float(0) : Float.valueOf(obj.toString());
174
175 } catch (NumberFormatException e) {
176 throw new SQLException(e.getMessage());
177 }
178 }
179
180 /**
181 * Gets the int value at the given column index.
182 * @param columnIndex A 1 based index.
183 * @throws SQLException if a database access error occurs
184 */
185 protected Object getInt(int columnIndex) throws SQLException {
186 Object obj = this.currentRow[columnIndex - 1];
187 this.setWasNull(obj);
188
189 try {
190 return (obj == null)
191 ? new Integer(0)
192 : Integer.valueOf(obj.toString());
193
194 } catch (NumberFormatException e) {
195 throw new SQLException(e.getMessage());
196 }
197 }
198
199 /**
200 * Gets the long value at the given column index.
201 * @param columnIndex A 1 based index.
202 * @throws SQLException if a database access error occurs
203 */
204 protected Object getLong(int columnIndex) throws SQLException {
205 Object obj = this.currentRow[columnIndex - 1];
206 this.setWasNull(obj);
207
208 try {
209 return (obj == null) ? new Long(0) : Long.valueOf(obj.toString());
210
211 } catch (NumberFormatException e) {
212 throw new SQLException(e.getMessage());
213 }
214 }
215
216 protected ResultSetMetaData getMetaData() throws SQLException {
217 return this.metaData;
218 }
219
220 /**
221 * Gets the object at the given column index.
222 * @param columnIndex A 1 based index.
223 * @throws SQLException if a database access error occurs
224 */
225 protected Object getObject(int columnIndex) throws SQLException {
226 Object obj = this.currentRow[columnIndex - 1];
227 this.setWasNull(obj);
228 return obj;
229 }
230
231 /**
232 * Gets the short value at the given column index.
233 * @param columnIndex A 1 based index.
234 * @throws SQLException if a database access error occurs
235 */
236 protected Object getShort(int columnIndex) throws SQLException {
237 Object obj = this.currentRow[columnIndex - 1];
238 this.setWasNull(obj);
239
240 try {
241 return (obj == null)
242 ? new Short((short) 0)
243 : Short.valueOf(obj.toString());
244
245 } catch (NumberFormatException e) {
246 throw new SQLException(e.getMessage());
247 }
248 }
249
250 /**
251 * Gets the String at the given column index.
252 * @param columnIndex A 1 based index.
253 * @throws SQLException if a database access error occurs
254 */
255 protected String getString(int columnIndex) throws SQLException {
256 Object obj = this.getObject(columnIndex);
257 this.setWasNull(obj);
258 return (obj == null) ? null : obj.toString();
259 }
260
261 public Object invoke(Object proxy, Method method, Object[] args)
262 throws Throwable {
263
264 String methodName = method.getName();
265
266 if (methodName.equals("getMetaData")) {
267 return this.getMetaData();
268
269 } else if (methodName.equals("next")) {
270 return this.next();
271
272 } else if (methodName.equals("previous")) {
273
274 } else if (methodName.equals("close")) {
275
276 } else if (methodName.equals("getBoolean")) {
277 return this.getBoolean(columnIndex(args));
278
279 } else if (methodName.equals("getByte")) {
280 return this.getByte(columnIndex(args));
281
282 } else if (methodName.equals("getDouble")) {
283 return this.getDouble(columnIndex(args));
284
285 } else if (methodName.equals("getFloat")) {
286 return this.getFloat(columnIndex(args));
287
288 } else if (methodName.equals("getInt")) {
289 return this.getInt(columnIndex(args));
290
291 } else if (methodName.equals("getLong")) {
292 return this.getLong(columnIndex(args));
293
294 } else if (methodName.equals("getObject")) {
295 return this.getObject(columnIndex(args));
296
297 } else if (methodName.equals("getShort")) {
298 return this.getShort(columnIndex(args));
299
300 } else if (methodName.equals("getString")) {
301 return this.getString(columnIndex(args));
302
303 } else if (methodName.equals("wasNull")) {
304 return this.wasNull();
305
306 } else if (methodName.equals("isLast")) {
307 return this.isLast();
308
309 } else if (methodName.equals("hashCode")) {
310 return new Integer(System.identityHashCode(proxy));
311
312 } else if (methodName.equals("toString")) {
313 return "MockResultSet " + System.identityHashCode(proxy);
314
315 } else if (methodName.equals("equals")) {
316 return new Boolean(proxy == args[0]);
317 }
318
319 throw new UnsupportedOperationException("Unsupported method: " + methodName);
320 }
321
322 protected Boolean isLast() throws SQLException {
323 return this.iter.hasNext() ? Boolean.FALSE : Boolean.TRUE;
324 }
325
326 protected Boolean next() throws SQLException {
327 if (!this.iter.hasNext()) {
328 return Boolean.FALSE;
329 } else {
330 this.currentRow = (Object[]) iter.next();
331 return Boolean.TRUE;
332 }
333 }
334
335 /**
336 * Assigns this.wasNull a Boolean value based on the object passed in.
337 * @param isNull
338 */
339 private void setWasNull(Object isNull) {
340 this.wasNull = (isNull == null) ? Boolean.TRUE : Boolean.FALSE;
341 }
342
343 protected Boolean wasNull() throws SQLException {
344 return this.wasNull;
345 }
346 }