1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbutils.wrappers;
18
19 import java.io.InputStream;
20 import java.io.Reader;
21 import java.lang.reflect.InvocationHandler;
22 import java.lang.reflect.Method;
23 import java.math.BigDecimal;
24 import java.net.URL;
25 import java.sql.Blob;
26 import java.sql.Clob;
27 import java.sql.Date;
28 import java.sql.Ref;
29 import java.sql.ResultSet;
30 import java.sql.Time;
31 import java.sql.Timestamp;
32 import java.util.HashMap;
33 import java.util.Map;
34
35 import org.apache.commons.dbutils.ProxyFactory;
36
37 /**
38 * Decorates a <code>ResultSet</code> with checks for a SQL NULL value on each
39 * <code>getXXX</code> method. If a column value obtained by a
40 * <code>getXXX</code> method is not SQL NULL, the column value is returned. If
41 * the column value is SQL null, an alternate value is returned. The alternate
42 * value defaults to the Java <code>null</code> value, which can be overridden
43 * for instances of the class.
44 *
45 * <p>
46 * Usage example:
47 * <blockquote>
48 * <pre>
49 * Connection conn = // somehow get a connection
50 * Statement stmt = conn.createStatement();
51 * ResultSet rs = stmt.executeQuery("SELECT col1, col2 FROM table1");
52 *
53 * // Wrap the result set for SQL NULL checking
54 * SqlNullCheckedResultSet wrapper = new SqlNullCheckedResultSet(rs);
55 * wrapper.setNullString("---N/A---"); // Set null string
56 * wrapper.setNullInt(-999); // Set null integer
57 * rs = ProxyFactory.instance().createResultSet(wrapper);
58 *
59 * while (rs.next()) {
60 * // If col1 is SQL NULL, value returned will be "---N/A---"
61 * String col1 = rs.getString("col1");
62 * // If col2 is SQL NULL, value returned will be -999
63 * int col2 = rs.getInt("col2");
64 * }
65 * rs.close();
66 * </pre>
67 * </blockquote>
68 * </p>
69 */
70 public class SqlNullCheckedResultSet implements InvocationHandler {
71
72 /**
73 * Maps normal method names (ie. "getBigDecimal") to the corresponding null
74 * Method object (ie. getNullBigDecimal).
75 */
76 private static final Map nullMethods = new HashMap();
77
78 static {
79 Method[] methods = SqlNullCheckedResultSet.class.getMethods();
80 for (int i = 0; i < methods.length; i++) {
81 String methodName = methods[i].getName();
82
83 if (methodName.startsWith("getNull")) {
84 String normalName = "get" + methodName.substring(7);
85 nullMethods.put(normalName, methods[i]);
86 }
87 }
88 }
89
90 /**
91 * The factory to create proxies with.
92 */
93 private static final ProxyFactory factory = ProxyFactory.instance();
94
95 /**
96 * Wraps the <code>ResultSet</code> in an instance of this class. This is
97 * equivalent to:
98 * <pre>
99 * ProxyFactory.instance().createResultSet(new SqlNullCheckedResultSet(rs));
100 * </pre>
101 *
102 * @param rs The <code>ResultSet</code> to wrap.
103 * @return wrapped ResultSet
104 */
105 public static ResultSet wrap(ResultSet rs) {
106 return factory.createResultSet(new SqlNullCheckedResultSet(rs));
107 }
108
109 private InputStream nullAsciiStream = null;
110 private BigDecimal nullBigDecimal = null;
111 private InputStream nullBinaryStream = null;
112 private Blob nullBlob = null;
113 private boolean nullBoolean = false;
114 private byte nullByte = 0;
115 private byte[] nullBytes = null;
116 private Reader nullCharacterStream = null;
117 private Clob nullClob = null;
118 private Date nullDate = null;
119 private double nullDouble = 0.0;
120 private float nullFloat = 0.0f;
121 private int nullInt = 0;
122 private long nullLong = 0;
123 private Object nullObject = null;
124 private Ref nullRef = null;
125 private short nullShort = 0;
126 private String nullString = null;
127 private Time nullTime = null;
128 private Timestamp nullTimestamp = null;
129 private URL nullURL = null;
130
131 /**
132 * The wrapped result.
133 */
134 private final ResultSet rs;
135
136 /**
137 * Constructs a new instance of
138 * <code>SqlNullCheckedResultSet</code>
139 * to wrap the specified <code>ResultSet</code>.
140 * @param rs ResultSet to wrap
141 */
142 public SqlNullCheckedResultSet(ResultSet rs) {
143 super();
144 this.rs = rs;
145 }
146
147 /**
148 * Returns the value when a SQL null is encountered as the result of
149 * invoking a <code>getAsciiStream</code> method.
150 *
151 * @return the value
152 */
153 public InputStream getNullAsciiStream() {
154 return this.nullAsciiStream;
155 }
156
157 /**
158 * Returns the value when a SQL null is encountered as the result of
159 * invoking a <code>getBigDecimal</code> method.
160 *
161 * @return the value
162 */
163 public BigDecimal getNullBigDecimal() {
164 return this.nullBigDecimal;
165 }
166
167 /**
168 * Returns the value when a SQL null is encountered as the result of
169 * invoking a <code>getBinaryStream</code> method.
170 *
171 * @return the value
172 */
173 public InputStream getNullBinaryStream() {
174 return this.nullBinaryStream;
175 }
176
177 /**
178 * Returns the value when a SQL null is encountered as the result of
179 * invoking a <code>getBlob</code> method.
180 *
181 * @return the value
182 */
183 public Blob getNullBlob() {
184 return this.nullBlob;
185 }
186
187 /**
188 * Returns the value when a SQL null is encountered as the result of
189 * invoking a <code>getBoolean</code> method.
190 *
191 * @return the value
192 */
193 public boolean getNullBoolean() {
194 return this.nullBoolean;
195 }
196
197 /**
198 * Returns the value when a SQL null is encountered as the result of
199 * invoking a <code>getByte</code> method.
200 *
201 * @return the value
202 */
203 public byte getNullByte() {
204 return this.nullByte;
205 }
206
207 /**
208 * Returns the value when a SQL null is encountered as the result of
209 * invoking a <code>getBytes</code> method.
210 *
211 * @return the value
212 */
213 public byte[] getNullBytes() {
214 return this.nullBytes;
215 }
216
217 /**
218 * Returns the value when a SQL null is encountered as the result of
219 * invoking a <code>getCharacterStream</code> method.
220 *
221 * @return the value
222 */
223 public Reader getNullCharacterStream() {
224 return this.nullCharacterStream;
225 }
226
227 /**
228 * Returns the value when a SQL null is encountered as the result of
229 * invoking a <code>getClob</code> method.
230 *
231 * @return the value
232 */
233 public Clob getNullClob() {
234 return this.nullClob;
235 }
236
237 /**
238 * Returns the value when a SQL null is encountered as the result of
239 * invoking a <code>getDate</code> method.
240 *
241 * @return the value
242 */
243 public Date getNullDate() {
244 return this.nullDate;
245 }
246
247 /**
248 * Returns the value when a SQL null is encountered as the result of
249 * invoking a <code>getDouble</code> method.
250 *
251 * @return the value
252 */
253 public double getNullDouble() {
254 return this.nullDouble;
255 }
256
257 /**
258 * Returns the value when a SQL null is encountered as the result of
259 * invoking a <code>getFloat</code> method.
260 *
261 * @return the value
262 */
263 public float getNullFloat() {
264 return this.nullFloat;
265 }
266
267 /**
268 * Returns the value when a SQL null is encountered as the result of
269 * invoking a <code>getInt</code> method.
270 *
271 * @return the value
272 */
273 public int getNullInt() {
274 return this.nullInt;
275 }
276
277 /**
278 * Returns the value when a SQL null is encountered as the result of
279 * invoking a <code>getLong</code> method.
280 *
281 * @return the value
282 */
283 public long getNullLong() {
284 return this.nullLong;
285 }
286
287 /**
288 * Returns the value when a SQL null is encountered as the result of
289 * invoking a <code>getObject</code> method.
290 *
291 * @return the value
292 */
293 public Object getNullObject() {
294 return this.nullObject;
295 }
296
297 /**
298 * Returns the value when a SQL null is encountered as the result of
299 * invoking a <code>getRef</code> method.
300 *
301 * @return the value
302 */
303 public Ref getNullRef() {
304 return this.nullRef;
305 }
306
307 /**
308 * Returns the value when a SQL null is encountered as the result of
309 * invoking a <code>getShort</code> method.
310 *
311 * @return the value
312 */
313 public short getNullShort() {
314 return this.nullShort;
315 }
316
317 /**
318 * Returns the value when a SQL null is encountered as the result of
319 * invoking a <code>getString</code> method.
320 *
321 * @return the value
322 */
323 public String getNullString() {
324 return this.nullString;
325 }
326
327 /**
328 * Returns the value when a SQL null is encountered as the result of
329 * invoking a <code>getTime</code> method.
330 *
331 * @return the value
332 */
333 public Time getNullTime() {
334 return this.nullTime;
335 }
336
337 /**
338 * Returns the value when a SQL null is encountered as the result of
339 * invoking a <code>getTimestamp</code> method.
340 *
341 * @return the value
342 */
343 public Timestamp getNullTimestamp() {
344 return this.nullTimestamp;
345 }
346
347 /**
348 * Returns the value when a SQL null is encountered as the result of
349 * invoking a <code>getURL</code> method.
350 *
351 * @return the value
352 */
353 public URL getNullURL() {
354 return this.nullURL;
355 }
356
357 /**
358 * Intercepts calls to <code>get*</code> methods and calls the appropriate
359 * <code>getNull*</code> method if the <code>ResultSet</code> returned
360 * <code>null</code>.
361 *
362 * @throws Throwable
363 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
364 */
365 public Object invoke(Object proxy, Method method, Object[] args)
366 throws Throwable {
367
368 Object result = method.invoke(this.rs, args);
369
370 Method nullMethod = (Method) nullMethods.get(method.getName());
371
372
373
374 return (nullMethod != null && this.rs.wasNull())
375 ? nullMethod.invoke(this, (Object[]) null)
376 : result;
377 }
378
379 /**
380 * Sets the value to return when a SQL null is encountered as the result of
381 * invoking a <code>getAsciiStream</code> method.
382 *
383 * @param nullAsciiStream the value
384 */
385 public void setNullAsciiStream(InputStream nullAsciiStream) {
386 this.nullAsciiStream = nullAsciiStream;
387 }
388
389 /**
390 * Sets the value to return when a SQL null is encountered as the result of
391 * invoking a <code>getBigDecimal</code> method.
392 *
393 * @param nullBigDecimal the value
394 */
395 public void setNullBigDecimal(BigDecimal nullBigDecimal) {
396 this.nullBigDecimal = nullBigDecimal;
397 }
398
399 /**
400 * Sets the value to return when a SQL null is encountered as the result of
401 * invoking a <code>getBinaryStream</code> method.
402 *
403 * @param nullBinaryStream the value
404 */
405 public void setNullBinaryStream(InputStream nullBinaryStream) {
406 this.nullBinaryStream = nullBinaryStream;
407 }
408
409 /**
410 * Sets the value to return when a SQL null is encountered as the result of
411 * invoking a <code>getBlob</code> method.
412 *
413 * @param nullBlob the value
414 */
415 public void setNullBlob(Blob nullBlob) {
416 this.nullBlob = nullBlob;
417 }
418
419 /**
420 * Sets the value to return when a SQL null is encountered as the result of
421 * invoking a <code>getBoolean</code> method.
422 *
423 * @param nullBoolean the value
424 */
425 public void setNullBoolean(boolean nullBoolean) {
426 this.nullBoolean = nullBoolean;
427 }
428
429 /**
430 * Sets the value to return when a SQL null is encountered as the result of
431 * invoking a <code>getByte</code> method.
432 *
433 * @param nullByte the value
434 */
435 public void setNullByte(byte nullByte) {
436 this.nullByte = nullByte;
437 }
438
439 /**
440 * Sets the value to return when a SQL null is encountered as the result of
441 * invoking a <code>getBytes</code> method.
442 *
443 * @param nullBytes the value
444 */
445 public void setNullBytes(byte[] nullBytes) {
446 this.nullBytes = nullBytes;
447 }
448
449 /**
450 * Sets the value to return when a SQL null is encountered as the result of
451 * invoking a <code>getCharacterStream</code> method.
452 *
453 * @param nullCharacterStream the value
454 */
455 public void setNullCharacterStream(Reader nullCharacterStream) {
456 this.nullCharacterStream = nullCharacterStream;
457 }
458
459 /**
460 * Sets the value to return when a SQL null is encountered as the result of
461 * invoking a <code>getClob</code> method.
462 *
463 * @param nullClob the value
464 */
465 public void setNullClob(Clob nullClob) {
466 this.nullClob = nullClob;
467 }
468
469 /**
470 * Sets the value to return when a SQL null is encountered as the result of
471 * invoking a <code>getDate</code> method.
472 *
473 * @param nullDate the value
474 */
475 public void setNullDate(Date nullDate) {
476 this.nullDate = nullDate;
477 }
478
479 /**
480 * Sets the value to return when a SQL null is encountered as the result of
481 * invoking a <code>getDouble</code> method.
482 *
483 * @param nullDouble the value
484 */
485 public void setNullDouble(double nullDouble) {
486 this.nullDouble = nullDouble;
487 }
488
489 /**
490 * Sets the value to return when a SQL null is encountered as the result of
491 * invoking a <code>getFloat</code> method.
492 *
493 * @param nullFloat the value
494 */
495 public void setNullFloat(float nullFloat) {
496 this.nullFloat = nullFloat;
497 }
498
499 /**
500 * Sets the value to return when a SQL null is encountered as the result of
501 * invoking a <code>getInt</code> method.
502 *
503 * @param nullInt the value
504 */
505 public void setNullInt(int nullInt) {
506 this.nullInt = nullInt;
507 }
508
509 /**
510 * Sets the value to return when a SQL null is encountered as the result of
511 * invoking a <code>getLong</code> method.
512 *
513 * @param nullLong the value
514 */
515 public void setNullLong(long nullLong) {
516 this.nullLong = nullLong;
517 }
518
519 /**
520 * Sets the value to return when a SQL null is encountered as the result of
521 * invoking a <code>getObject</code> method.
522 *
523 * @param nullObject the value
524 */
525 public void setNullObject(Object nullObject) {
526 this.nullObject = nullObject;
527 }
528
529 /**
530 * Sets the value to return when a SQL null is encountered as the result of
531 * invoking a <code>getRef</code> method.
532 *
533 * @param nullRef the value
534 */
535 public void setNullRef(Ref nullRef) {
536 this.nullRef = nullRef;
537 }
538
539 /**
540 * Sets the value to return when a SQL null is encountered as the result of
541 * invoking a <code>getShort</code> method.
542 *
543 * @param nullShort the value
544 */
545 public void setNullShort(short nullShort) {
546 this.nullShort = nullShort;
547 }
548
549 /**
550 * Sets the value to return when a SQL null is encountered as the result of
551 * invoking a <code>getString</code> method.
552 *
553 * @param nullString the value
554 */
555 public void setNullString(String nullString) {
556 this.nullString = nullString;
557 }
558
559 /**
560 * Sets the value to return when a SQL null is encountered as the result of
561 * invoking a <code>getTime</code> method.
562 *
563 * @param nullTime the value
564 */
565 public void setNullTime(Time nullTime) {
566 this.nullTime = nullTime;
567 }
568
569 /**
570 * Sets the value to return when a SQL null is encountered as the result of
571 * invoking a <code>getTimestamp</code> method.
572 *
573 * @param nullTimestamp the value
574 */
575 public void setNullTimestamp(Timestamp nullTimestamp) {
576 this.nullTimestamp = nullTimestamp;
577 }
578
579 /**
580 * Sets the value to return when a SQL null is encountered as the result of
581 * invoking a <code>getURL</code> method.
582 *
583 * @param nullURL the value
584 */
585 public void setNullURL(URL nullURL) {
586 this.nullURL = nullURL;
587 }
588
589 }