Source Code Cross Referenced for BeanProcessor.java in  » Database-JDBC-Connection-Pool » Database-Utilities » org » apache » commons » dbutils » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » Database Utilities » org.apache.commons.dbutils 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.commons.dbutils;
018:
019:        import java.beans.BeanInfo;
020:        import java.beans.IntrospectionException;
021:        import java.beans.Introspector;
022:        import java.beans.PropertyDescriptor;
023:        import java.lang.reflect.InvocationTargetException;
024:        import java.lang.reflect.Method;
025:        import java.sql.ResultSet;
026:        import java.sql.ResultSetMetaData;
027:        import java.sql.SQLException;
028:        import java.sql.Timestamp;
029:        import java.util.ArrayList;
030:        import java.util.Arrays;
031:        import java.util.HashMap;
032:        import java.util.List;
033:        import java.util.Map;
034:
035:        /**
036:         * <p>
037:         * <code>BeanProcessor</code> matches column names to bean property names 
038:         * and converts <code>ResultSet</code> columns into objects for those bean 
039:         * properties.  Subclasses should override the methods in the processing chain
040:         * to customize behavior.
041:         * </p>
042:         * 
043:         * <p>
044:         * This class is thread-safe.
045:         * </p>
046:         * 
047:         * @see BasicRowProcessor
048:         * 
049:         * @since DbUtils 1.1
050:         */
051:        public class BeanProcessor {
052:
053:            /**
054:             * Special array value used by <code>mapColumnsToProperties</code> that 
055:             * indicates there is no bean property that matches a column from a 
056:             * <code>ResultSet</code>.
057:             */
058:            protected static final int PROPERTY_NOT_FOUND = -1;
059:
060:            /**
061:             * Set a bean's primitive properties to these defaults when SQL NULL 
062:             * is returned.  These are the same as the defaults that ResultSet get* 
063:             * methods return in the event of a NULL column.
064:             */
065:            private static final Map primitiveDefaults = new HashMap();
066:
067:            static {
068:                primitiveDefaults.put(Integer.TYPE, new Integer(0));
069:                primitiveDefaults.put(Short.TYPE, new Short((short) 0));
070:                primitiveDefaults.put(Byte.TYPE, new Byte((byte) 0));
071:                primitiveDefaults.put(Float.TYPE, new Float(0));
072:                primitiveDefaults.put(Double.TYPE, new Double(0));
073:                primitiveDefaults.put(Long.TYPE, new Long(0));
074:                primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
075:                primitiveDefaults.put(Character.TYPE, new Character('\u0000'));
076:            }
077:
078:            /**
079:             * Constructor for BeanProcessor.
080:             */
081:            public BeanProcessor() {
082:                super ();
083:            }
084:
085:            /**
086:             * Convert a <code>ResultSet</code> row into a JavaBean.  This 
087:             * implementation uses reflection and <code>BeanInfo</code> classes to 
088:             * match column names to bean property names.  Properties are matched to 
089:             * columns based on several factors:
090:             * <br/>
091:             * <ol>
092:             *     <li>
093:             *     The class has a writable property with the same name as a column.
094:             *     The name comparison is case insensitive.
095:             *     </li>
096:             * 
097:             *     <li>
098:             *     The column type can be converted to the property's set method 
099:             *     parameter type with a ResultSet.get* method.  If the conversion fails
100:             *     (ie. the property was an int and the column was a Timestamp) an
101:             *     SQLException is thrown.
102:             *     </li>
103:             * </ol>
104:             * 
105:             * <p>
106:             * Primitive bean properties are set to their defaults when SQL NULL is
107:             * returned from the <code>ResultSet</code>.  Numeric fields are set to 0
108:             * and booleans are set to false.  Object bean properties are set to 
109:             * <code>null</code> when SQL NULL is returned.  This is the same behavior
110:             * as the <code>ResultSet</code> get* methods.
111:             * </p>
112:             *
113:             * @param rs ResultSet that supplies the bean data
114:             * @param type Class from which to create the bean instance
115:             * @throws SQLException if a database access error occurs
116:             * @return the newly created bean
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,
124:                        props);
125:
126:                return this .createBean(rs, type, props, columnToProperty);
127:            }
128:
129:            /**
130:             * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans.  
131:             * This implementation uses reflection and <code>BeanInfo</code> classes to 
132:             * match column names to bean property names. Properties are matched to 
133:             * columns based on several factors:
134:             * <br/>
135:             * <ol>
136:             *     <li>
137:             *     The class has a writable property with the same name as a column.
138:             *     The name comparison is case insensitive.
139:             *     </li>
140:             * 
141:             *     <li>
142:             *     The column type can be converted to the property's set method 
143:             *     parameter type with a ResultSet.get* method.  If the conversion fails
144:             *     (ie. the property was an int and the column was a Timestamp) an
145:             *     SQLException is thrown.
146:             *     </li>
147:             * </ol>
148:             * 
149:             * <p>
150:             * Primitive bean properties are set to their defaults when SQL NULL is
151:             * returned from the <code>ResultSet</code>.  Numeric fields are set to 0
152:             * and booleans are set to false.  Object bean properties are set to 
153:             * <code>null</code> when SQL NULL is returned.  This is the same behavior
154:             * as the <code>ResultSet</code> get* methods.
155:             * </p>
156:             *
157:             * @param rs ResultSet that supplies the bean data
158:             * @param type Class from which to create the bean instance
159:             * @throws SQLException if a database access error occurs
160:             * @return the newly created List of beans
161:             */
162:            public List toBeanList(ResultSet rs, Class type)
163:                    throws SQLException {
164:                List results = new ArrayList();
165:
166:                if (!rs.next()) {
167:                    return results;
168:                }
169:
170:                PropertyDescriptor[] props = this .propertyDescriptors(type);
171:                ResultSetMetaData rsmd = rs.getMetaData();
172:                int[] columnToProperty = this .mapColumnsToProperties(rsmd,
173:                        props);
174:
175:                do {
176:                    results.add(this .createBean(rs, type, props,
177:                            columnToProperty));
178:                } while (rs.next());
179:
180:                return results;
181:            }
182:
183:            /**
184:             * Creates a new object and initializes its fields from the ResultSet.
185:             *
186:             * @param rs The result set.
187:             * @param type The bean type (the return type of the object).
188:             * @param props The property descriptors.
189:             * @param columnToProperty The column indices in the result set.
190:             * @return An initialized object.
191:             * @throws SQLException if a database error occurs.
192:             */
193:            private Object createBean(ResultSet rs, Class type,
194:                    PropertyDescriptor[] props, int[] columnToProperty)
195:                    throws SQLException {
196:
197:                Object bean = this .newInstance(type);
198:
199:                for (int i = 1; i < columnToProperty.length; i++) {
200:
201:                    if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
202:                        continue;
203:                    }
204:
205:                    PropertyDescriptor prop = props[columnToProperty[i]];
206:                    Class propType = prop.getPropertyType();
207:
208:                    Object value = this .processColumn(rs, i, propType);
209:
210:                    if (propType != null && value == null
211:                            && propType.isPrimitive()) {
212:                        value = primitiveDefaults.get(propType);
213:                    }
214:
215:                    this .callSetter(bean, prop, value);
216:                }
217:
218:                return bean;
219:            }
220:
221:            /**
222:             * Calls the setter method on the target object for the given property.
223:             * If no setter method exists for the property, this method does nothing.
224:             * @param target The object to set the property on.
225:             * @param prop The property to set.
226:             * @param value The value to pass into the setter.
227:             * @throws SQLException if an error occurs setting the property.
228:             */
229:            private void callSetter(Object target, PropertyDescriptor prop,
230:                    Object value) throws SQLException {
231:
232:                Method setter = prop.getWriteMethod();
233:
234:                if (setter == null) {
235:                    return;
236:                }
237:
238:                Class[] params = setter.getParameterTypes();
239:                try {
240:                    // convert types for some popular ones
241:                    if (value != null) {
242:                        if (value instanceof  java.util.Date) {
243:                            if (params[0].getName().equals("java.sql.Date")) {
244:                                value = new java.sql.Date(
245:                                        ((java.util.Date) value).getTime());
246:                            } else if (params[0].getName().equals(
247:                                    "java.sql.Time")) {
248:                                value = new java.sql.Time(
249:                                        ((java.util.Date) value).getTime());
250:                            } else if (params[0].getName().equals(
251:                                    "java.sql.Timestamp")) {
252:                                value = new java.sql.Timestamp(
253:                                        ((java.util.Date) value).getTime());
254:                            }
255:                        }
256:                    }
257:
258:                    // Don't call setter if the value object isn't the right type 
259:                    if (this .isCompatibleType(value, params[0])) {
260:                        setter.invoke(target, new Object[] { value });
261:                    } else {
262:                        throw new SQLException("Cannot set " + prop.getName()
263:                                + ": incompatible types.");
264:                    }
265:
266:                } catch (IllegalArgumentException e) {
267:                    throw new SQLException("Cannot set " + prop.getName()
268:                            + ": " + e.getMessage());
269:
270:                } catch (IllegalAccessException e) {
271:                    throw new SQLException("Cannot set " + prop.getName()
272:                            + ": " + e.getMessage());
273:
274:                } catch (InvocationTargetException e) {
275:                    throw new SQLException("Cannot set " + prop.getName()
276:                            + ": " + e.getMessage());
277:                }
278:            }
279:
280:            /**
281:             * ResultSet.getObject() returns an Integer object for an INT column.  The
282:             * setter method for the property might take an Integer or a primitive int.
283:             * This method returns true if the value can be successfully passed into
284:             * the setter method.  Remember, Method.invoke() handles the unwrapping
285:             * of Integer into an int.
286:             * 
287:             * @param value The value to be passed into the setter method.
288:             * @param type The setter's parameter type.
289:             * @return boolean True if the value is compatible.
290:             */
291:            private boolean isCompatibleType(Object value, Class type) {
292:                // Do object check first, then primitives
293:                if (value == null || type.isInstance(value)) {
294:                    return true;
295:
296:                } else if (type.equals(Integer.TYPE)
297:                        && Integer.class.isInstance(value)) {
298:                    return true;
299:
300:                } else if (type.equals(Long.TYPE)
301:                        && Long.class.isInstance(value)) {
302:                    return true;
303:
304:                } else if (type.equals(Double.TYPE)
305:                        && Double.class.isInstance(value)) {
306:                    return true;
307:
308:                } else if (type.equals(Float.TYPE)
309:                        && Float.class.isInstance(value)) {
310:                    return true;
311:
312:                } else if (type.equals(Short.TYPE)
313:                        && Short.class.isInstance(value)) {
314:                    return true;
315:
316:                } else if (type.equals(Byte.TYPE)
317:                        && Byte.class.isInstance(value)) {
318:                    return true;
319:
320:                } else if (type.equals(Character.TYPE)
321:                        && Character.class.isInstance(value)) {
322:                    return true;
323:
324:                } else if (type.equals(Boolean.TYPE)
325:                        && Boolean.class.isInstance(value)) {
326:                    return true;
327:
328:                } else {
329:                    return false;
330:                }
331:
332:            }
333:
334:            /**
335:             * Factory method that returns a new instance of the given Class.  This
336:             * is called at the start of the bean creation process and may be 
337:             * overridden to provide custom behavior like returning a cached bean
338:             * instance.
339:             *
340:             * @param c The Class to create an object from.
341:             * @return A newly created object of the Class.
342:             * @throws SQLException if creation failed.
343:             */
344:            protected Object newInstance(Class c) throws SQLException {
345:                try {
346:                    return c.newInstance();
347:
348:                } catch (InstantiationException e) {
349:                    throw new SQLException("Cannot create " + c.getName()
350:                            + ": " + e.getMessage());
351:
352:                } catch (IllegalAccessException e) {
353:                    throw new SQLException("Cannot create " + c.getName()
354:                            + ": " + e.getMessage());
355:                }
356:            }
357:
358:            /**
359:             * Returns a PropertyDescriptor[] for the given Class.
360:             *
361:             * @param c The Class to retrieve PropertyDescriptors for.
362:             * @return A PropertyDescriptor[] describing the Class.
363:             * @throws SQLException if introspection failed.
364:             */
365:            private PropertyDescriptor[] propertyDescriptors(Class c)
366:                    throws SQLException {
367:                // Introspector caches BeanInfo classes for better performance
368:                BeanInfo beanInfo = null;
369:                try {
370:                    beanInfo = Introspector.getBeanInfo(c);
371:
372:                } catch (IntrospectionException e) {
373:                    throw new SQLException("Bean introspection failed: "
374:                            + e.getMessage());
375:                }
376:
377:                return beanInfo.getPropertyDescriptors();
378:            }
379:
380:            /**
381:             * The positions in the returned array represent column numbers.  The 
382:             * values stored at each position represent the index in the 
383:             * <code>PropertyDescriptor[]</code> for the bean property that matches 
384:             * the column name.  If no bean property was found for a column, the 
385:             * position is set to <code>PROPERTY_NOT_FOUND</code>.
386:             * 
387:             * @param rsmd The <code>ResultSetMetaData</code> containing column 
388:             * information.
389:             * 
390:             * @param props The bean property descriptors.
391:             * 
392:             * @throws SQLException if a database access error occurs
393:             *
394:             * @return An int[] with column index to property index mappings.  The 0th 
395:             * element is meaningless because JDBC column indexing starts at 1.
396:             */
397:            protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
398:                    PropertyDescriptor[] props) throws SQLException {
399:
400:                int cols = rsmd.getColumnCount();
401:                int columnToProperty[] = new int[cols + 1];
402:                Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
403:
404:                for (int col = 1; col <= cols; col++) {
405:                    String columnName = rsmd.getColumnName(col);
406:                    for (int i = 0; i < props.length; i++) {
407:
408:                        if (columnName.equalsIgnoreCase(props[i].getName())) {
409:                            columnToProperty[col] = i;
410:                            break;
411:                        }
412:                    }
413:                }
414:
415:                return columnToProperty;
416:            }
417:
418:            /**
419:             * Convert a <code>ResultSet</code> column into an object.  Simple 
420:             * implementations could just call <code>rs.getObject(index)</code> while
421:             * more complex implementations could perform type manipulation to match 
422:             * the column's type to the bean property type.
423:             * 
424:             * <p>
425:             * This implementation calls the appropriate <code>ResultSet</code> getter 
426:             * method for the given property type to perform the type conversion.  If 
427:             * the property type doesn't match one of the supported 
428:             * <code>ResultSet</code> types, <code>getObject</code> is called.
429:             * </p>
430:             * 
431:             * @param rs The <code>ResultSet</code> currently being processed.  It is
432:             * positioned on a valid row before being passed into this method.
433:             * 
434:             * @param index The current column index being processed.
435:             * 
436:             * @param propType The bean property type that this column needs to be
437:             * converted into.
438:             * 
439:             * @throws SQLException if a database access error occurs
440:             * 
441:             * @return The object from the <code>ResultSet</code> at the given column
442:             * index after optional type processing or <code>null</code> if the column
443:             * value was SQL NULL.
444:             */
445:            protected Object processColumn(ResultSet rs, int index,
446:                    Class propType) throws SQLException {
447:
448:                if (propType.equals(String.class)) {
449:                    return rs.getString(index);
450:
451:                } else if (propType.equals(Integer.TYPE)
452:                        || propType.equals(Integer.class)) {
453:                    return new Integer(rs.getInt(index));
454:
455:                } else if (propType.equals(Boolean.TYPE)
456:                        || propType.equals(Boolean.class)) {
457:                    return new Boolean(rs.getBoolean(index));
458:
459:                } else if (propType.equals(Long.TYPE)
460:                        || propType.equals(Long.class)) {
461:                    return new Long(rs.getLong(index));
462:
463:                } else if (propType.equals(Double.TYPE)
464:                        || propType.equals(Double.class)) {
465:                    return new Double(rs.getDouble(index));
466:
467:                } else if (propType.equals(Float.TYPE)
468:                        || propType.equals(Float.class)) {
469:                    return new Float(rs.getFloat(index));
470:
471:                } else if (propType.equals(Short.TYPE)
472:                        || propType.equals(Short.class)) {
473:                    return new Short(rs.getShort(index));
474:
475:                } else if (propType.equals(Byte.TYPE)
476:                        || propType.equals(Byte.class)) {
477:                    return new Byte(rs.getByte(index));
478:
479:                } else if (propType.equals(Timestamp.class)) {
480:                    return rs.getTimestamp(index);
481:
482:                } else {
483:                    return rs.getObject(index);
484:                }
485:
486:            }
487:
488:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.