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.beans.BeanInfo;
20 import java.beans.IntrospectionException;
21 import java.beans.Introspector;
22 import java.beans.PropertyDescriptor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.sql.ResultSet;
26 import java.sql.ResultSetMetaData;
27 import java.sql.SQLException;
28 import java.sql.Timestamp;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class BeanProcessor {
52
53
54
55
56
57
58 protected static final int PROPERTY_NOT_FOUND = -1;
59
60
61
62
63
64
65 private static final Map primitiveDefaults = new HashMap();
66
67 static {
68 primitiveDefaults.put(Integer.TYPE, new Integer(0));
69 primitiveDefaults.put(Short.TYPE, new Short((short) 0));
70 primitiveDefaults.put(Byte.TYPE, new Byte((byte) 0));
71 primitiveDefaults.put(Float.TYPE, new Float(0));
72 primitiveDefaults.put(Double.TYPE, new Double(0));
73 primitiveDefaults.put(Long.TYPE, new Long(0));
74 primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
75 primitiveDefaults.put(Character.TYPE, new Character('\u0000'));
76 }
77
78
79
80
81 public BeanProcessor() {
82 super();
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public Object toBean(ResultSet rs, Class type) throws SQLException {
119
120 PropertyDescriptor[] props = this.propertyDescriptors(type);
121
122 ResultSetMetaData rsmd = rs.getMetaData();
123 int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
124
125 return this.createBean(rs, type, props, columnToProperty);
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 public List toBeanList(ResultSet rs, Class type) throws SQLException {
162 List results = new ArrayList();
163
164 if (!rs.next()) {
165 return results;
166 }
167
168 PropertyDescriptor[] props = this.propertyDescriptors(type);
169 ResultSetMetaData rsmd = rs.getMetaData();
170 int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
171
172 do {
173 results.add(this.createBean(rs, type, props, columnToProperty));
174 } while (rs.next());
175
176 return results;
177 }
178
179
180
181
182
183
184
185
186
187
188
189 private Object createBean(ResultSet rs, Class type,
190 PropertyDescriptor[] props, int[] columnToProperty)
191 throws SQLException {
192
193 Object bean = this.newInstance(type);
194
195 for (int i = 1; i < columnToProperty.length; i++) {
196
197 if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
198 continue;
199 }
200
201 PropertyDescriptor prop = props[columnToProperty[i]];
202 Class propType = prop.getPropertyType();
203
204 Object value = this.processColumn(rs, i, propType);
205
206 if (propType != null && value == null && propType.isPrimitive()) {
207 value = primitiveDefaults.get(propType);
208 }
209
210 this.callSetter(bean, prop, value);
211 }
212
213 return bean;
214 }
215
216
217
218
219
220
221
222
223
224 private void callSetter(Object target, PropertyDescriptor prop, Object value)
225 throws SQLException {
226
227 Method setter = prop.getWriteMethod();
228
229 if (setter == null) {
230 return;
231 }
232
233 Class[] params = setter.getParameterTypes();
234 try {
235
236 if (value != null) {
237 if (value instanceof java.util.Date) {
238 if (params[0].getName().equals("java.sql.Date")) {
239 value = new java.sql.Date(((java.util.Date) value).getTime());
240 } else
241 if (params[0].getName().equals("java.sql.Time")) {
242 value = new java.sql.Time(((java.util.Date) value).getTime());
243 } else
244 if (params[0].getName().equals("java.sql.Timestamp")) {
245 value = new java.sql.Timestamp(((java.util.Date) value).getTime());
246 }
247 }
248 }
249
250
251 if (this.isCompatibleType(value, params[0])) {
252 setter.invoke(target, new Object[] { value });
253 } else {
254 throw new SQLException(
255 "Cannot set " + prop.getName() + ": incompatible types.");
256 }
257
258 } catch (IllegalArgumentException e) {
259 throw new SQLException(
260 "Cannot set " + prop.getName() + ": " + e.getMessage());
261
262 } catch (IllegalAccessException e) {
263 throw new SQLException(
264 "Cannot set " + prop.getName() + ": " + e.getMessage());
265
266 } catch (InvocationTargetException e) {
267 throw new SQLException(
268 "Cannot set " + prop.getName() + ": " + e.getMessage());
269 }
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283 private boolean isCompatibleType(Object value, Class type) {
284
285 if (value == null || type.isInstance(value)) {
286 return true;
287
288 } else if (
289 type.equals(Integer.TYPE) && Integer.class.isInstance(value)) {
290 return true;
291
292 } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) {
293 return true;
294
295 } else if (
296 type.equals(Double.TYPE) && Double.class.isInstance(value)) {
297 return true;
298
299 } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) {
300 return true;
301
302 } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) {
303 return true;
304
305 } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) {
306 return true;
307
308 } else if (
309 type.equals(Character.TYPE) && Character.class.isInstance(value)) {
310 return true;
311
312 } else if (
313 type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) {
314 return true;
315
316 } else {
317 return false;
318 }
319
320 }
321
322
323
324
325
326
327
328
329
330
331
332 protected Object newInstance(Class c) throws SQLException {
333 try {
334 return c.newInstance();
335
336 } catch (InstantiationException e) {
337 throw new SQLException(
338 "Cannot create " + c.getName() + ": " + e.getMessage());
339
340 } catch (IllegalAccessException e) {
341 throw new SQLException(
342 "Cannot create " + c.getName() + ": " + e.getMessage());
343 }
344 }
345
346
347
348
349
350
351
352
353 private PropertyDescriptor[] propertyDescriptors(Class c)
354 throws SQLException {
355
356 BeanInfo beanInfo = null;
357 try {
358 beanInfo = Introspector.getBeanInfo(c);
359
360 } catch (IntrospectionException e) {
361 throw new SQLException(
362 "Bean introspection failed: " + e.getMessage());
363 }
364
365 return beanInfo.getPropertyDescriptors();
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
386 PropertyDescriptor[] props) throws SQLException {
387
388 int cols = rsmd.getColumnCount();
389 int columnToProperty[] = new int[cols + 1];
390 Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
391
392 for (int col = 1; col <= cols; col++) {
393 String columnName = rsmd.getColumnName(col);
394 for (int i = 0; i < props.length; i++) {
395
396 if (columnName.equalsIgnoreCase(props[i].getName())) {
397 columnToProperty[col] = i;
398 break;
399 }
400 }
401 }
402
403 return columnToProperty;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433 protected Object processColumn(ResultSet rs, int index, Class propType)
434 throws SQLException {
435
436 if ( !propType.isPrimitive() && rs.getObject(index) == null ) {
437 return null;
438 }
439
440 if (propType.equals(String.class)) {
441 return rs.getString(index);
442
443 } else if (
444 propType.equals(Integer.TYPE) || propType.equals(Integer.class)) {
445 return new Integer(rs.getInt(index));
446
447 } else if (
448 propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) {
449 return new Boolean(rs.getBoolean(index));
450
451 } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) {
452 return new Long(rs.getLong(index));
453
454 } else if (
455 propType.equals(Double.TYPE) || propType.equals(Double.class)) {
456 return new Double(rs.getDouble(index));
457
458 } else if (
459 propType.equals(Float.TYPE) || propType.equals(Float.class)) {
460 return new Float(rs.getFloat(index));
461
462 } else if (
463 propType.equals(Short.TYPE) || propType.equals(Short.class)) {
464 return new Short(rs.getShort(index));
465
466 } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) {
467 return new Byte(rs.getByte(index));
468
469 } else if (propType.equals(Timestamp.class)) {
470 return rs.getTimestamp(index);
471
472 } else {
473 return rs.getObject(index);
474 }
475
476 }
477
478 }