Source Code Cross Referenced for DefaultResultSetMapper.java in  » Development » jodd » jodd » db » orm » mapper » 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 » Development » jodd » jodd.db.orm.mapper 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003:        package jodd.db.orm.mapper;
004:
005:        import jodd.bean.BeanUtil;
006:        import jodd.db.orm.DbOrm;
007:        import jodd.db.orm.DbOrmException;
008:        import jodd.db.orm.DbEntityDescriptor;
009:        import jodd.util.Wildcard;
010:        import jodd.util.ReflectUtil;
011:
012:        import java.sql.ResultSet;
013:        import java.sql.ResultSetMetaData;
014:        import java.sql.SQLException;
015:        import java.util.Map;
016:        import java.util.Set;
017:        import java.util.HashSet;
018:
019:        /**
020:         * Maps all columns of database result set (RS) row to objects.
021:         * It does it in two steps: preparation (reading table and column names)
022:         * and parsing (parsing one result set row to resulting objects).
023:         *
024:         * <p>
025:         * <b>Preparation</b><br>
026:         * Default mapper reads RS column and table names from RS meta-data and external maps, if provided.
027:         * Since column name is always availiable in RS meta-data, it may be used to hold table name information.
028:         * Column names may contain table code separator ({@link jodd.db.orm.DbOrm#getColumnAliasSeparator()} that
029:         * divides column name to table reference and column name. Here, table reference may be either table name or
030:         * table alias. When it is table alias, external alias-to-name map must be provided.
031:         * Hence, this defines the table name, and there is no need to read it from RS meta-data.
032:         *
033:         * <p>
034:         * When column name doesn't contain a separator, it may be either an actual column name, or a column code.
035:         * For column codes, both table and colum name is lookuped from external map. If column name is an actual column name,
036:         * table information is read from the RS meta data. Unfortunately, some DBs (such Oracle) doesn't implements
037:         * this simple JDBC feature. Therefore, it must be expected that column table name is not availiable.
038:         *
039:         * <p>
040:         * Table name is also not availiable for columns which are not directly table columns:
041:         * e.g. some calculations, counts etc.
042:         *
043:         * <p>
044:         * <b>Parsing</b><br>
045:         * Parser takes types array and tries to populate their instances in best possible way. It assumes that provided
046:         * types list matches selected columns. That is very important, and yet very easy and natural to follow.
047:         * So, parser will try to inject columns value into the one result instance. Now, there are two types of instances:
048:         * simple types (numbers and strings) and entities (pojo objects). Simple types are always mapped to
049:         * one and only one column. Entities will be mapped to all possible columns that can be matched starting from
050:         * current column. So, simple types are not column-hungry, entity types are column-hungry:)
051:         *
052:         * <p>
053:         * A column can be injected in one entities property only once. If one column is already mapped to current result,
054:         * RS mapper will assume that current result is finished with mapping and will proceed to the next one.
055:         * Similarly, if property name is not found for a column, RS mapper will proceed to the next result.
056:         * Therefore, entity types are column precize and hungry;) - all listed columns must be mapped somewhere. 
057:         *
058:         * <p>
059:         * Results that are not used during parsing will be set to <code>null</code>.
060:         */
061:        public class DefaultResultSetMapper implements  ResultSetMapper {
062:
063:            protected DbOrm dbOrm;
064:            protected ResultSet rs;
065:
066:            protected int totalColumns; // total number of columns
067:            protected String[] columnNames; // list of all column names
068:            protected String[] tableNames; // list of table names for each column, table name may be null
069:
070:            private Set<String> resultColums; // internal columns per entity cache
071:
072:            // ---------------------------------------------------------------- ctor
073:
074:            public DefaultResultSetMapper(ResultSet rs) {
075:                this (rs, null, DbOrm.getInstance());
076:            }
077:
078:            public DefaultResultSetMapper(ResultSet rs, DbOrm orm) {
079:                this (rs, null, orm);
080:            }
081:
082:            public DefaultResultSetMapper(ResultSet rs,
083:                    Map<String, String[]> columnAliases) {
084:                this (rs, columnAliases, DbOrm.getInstance());
085:            }
086:
087:            /**
088:             * Reads RS meta-data for column and table names.
089:             */
090:            public DefaultResultSetMapper(ResultSet rs,
091:                    Map<String, String[]> columnAliases, DbOrm orm) {
092:                this .dbOrm = orm;
093:                this .rs = rs;
094:                this .resultColums = new HashSet<String>();
095:                try {
096:                    ResultSetMetaData rsMetaData = rs.getMetaData();
097:                    if (rsMetaData == null) {
098:                        throw new DbOrmException(
099:                                "JDBC driver doesn't provide meta-data.");
100:                    }
101:                    totalColumns = rsMetaData.getColumnCount();
102:                    columnNames = new String[totalColumns];
103:                    tableNames = new String[totalColumns];
104:
105:                    for (int i = 0; i < totalColumns; i++) {
106:                        String columnName = rsMetaData.getColumnName(i + 1);
107:                        String tableName = null;
108:
109:                        // resolve column and table name
110:                        int sepNdx = columnName.indexOf(dbOrm
111:                                .getColumnAliasSeparator());
112:                        if (sepNdx != -1) {
113:                            // column alias exist, result set is ignored and columnAliases contains table data.
114:                            tableName = columnName.substring(0, sepNdx);
115:                            if (columnAliases != null) {
116:                                String[] tableData = columnAliases
117:                                        .get(tableName);
118:                                if (tableData != null) {
119:                                    tableName = tableData[0];
120:                                }
121:                            }
122:                            columnName = columnName.substring(sepNdx + 1);
123:                        } else {
124:                            // column alias doesn't exist, table name is readed from columnAliases and result set (if availiable).
125:                            if (columnAliases != null) {
126:                                String[] columnData = columnAliases
127:                                        .get(columnName.toLowerCase());
128:                                if (columnData != null) {
129:                                    tableName = columnData[0];
130:                                    columnName = columnData[1];
131:                                }
132:                            }
133:                            if (tableName == null) {
134:                                try {
135:                                    tableName = rsMetaData.getTableName(i + 1);
136:                                } catch (SQLException sex) {
137:                                    // ignore
138:                                }
139:                                if ((tableName != null)
140:                                        && (tableName.length() == 0)) {
141:                                    tableName = null;
142:                                }
143:                            }
144:                        }
145:
146:                        columnName = columnName.trim();
147:                        if (columnName.length() == 0) {
148:                            columnName = null;
149:                        }
150:                        columnNames[i] = columnName;
151:                        if (tableName != null) {
152:                            tableName = tableName.trim();
153:                        }
154:                        tableNames[i] = tableName;
155:                    }
156:                } catch (SQLException sex) {
157:                    throw new DbOrmException(
158:                            "Unable to read ResultSet meta-data.", sex);
159:                }
160:            }
161:
162:            // ---------------------------------------------------------------- delegates
163:
164:            /**
165:             * Moves the cursor down one row from its current position.
166:             */
167:            public boolean next() {
168:                try {
169:                    return rs.next();
170:                } catch (SQLException sex) {
171:                    throw new DbOrmException(
172:                            "Unable to move ResultSet cursor to next position.",
173:                            sex);
174:                }
175:            }
176:
177:            /**
178:             * Releases this ResultSet object's database and JDBC resources immediately instead of
179:             * waiting for this to happen when it is automatically closed.
180:             */
181:            public void close() {
182:                try {
183:                    rs.close();
184:                } catch (SQLException sex) {
185:                    // ignore
186:                }
187:            }
188:
189:            /**
190:             * Return JDBC result set.
191:             */
192:            public ResultSet getResultSet() {
193:                return rs;
194:            }
195:
196:            // ---------------------------------------------------------------- parse objects
197:
198:            /**
199:             * Creates new instances of a types.
200:             */
201:            protected Object newInstance(Class types) {
202:                try {
203:                    return types.newInstance();
204:                } catch (Exception ex) {
205:                    throw new DbOrmException(
206:                            "Unable to create new entity instance for type '"
207:                                    + types + "'.", ex);
208:                }
209:            }
210:
211:            protected Class[] cachedUsedTypes;
212:            protected String[] cachedTypesTableNames;
213:
214:            /**
215:             * Creates table names for all specified types.
216:             * Since this is usually done once per result set, these names are cached.
217:             * Type name will be <code>null</code> for simple names, i.e. for all those
218:             * types that returns <code>null</code> when used by {@link DbOrm#lookup(Class)}.
219:             */
220:            protected String[] createTypesTableNames(Class[] types) {
221:                if (types != cachedUsedTypes) {
222:                    cachedTypesTableNames = new String[types.length];
223:                    for (int i = 0; i < types.length; i++) {
224:                        if (types[i] == null) {
225:                            cachedTypesTableNames[i] = null;
226:                            continue;
227:                        }
228:                        DbEntityDescriptor ded = dbOrm.lookup(types[i]);
229:                        if (ded != null) {
230:                            cachedTypesTableNames[i] = ded.getTableName();
231:                        }
232:                    }
233:                    cachedUsedTypes = types;
234:                }
235:                return cachedTypesTableNames;
236:            }
237:
238:            protected int cachedColumnNdx;
239:            protected Object cachedColumnValue;
240:
241:            /**
242:             * Reads column value from result set. Since this method may be called more then once for
243:             * the same column, it caches column value.
244:             */
245:            protected Object readColumnValue(int colNdx) {
246:                if (colNdx != cachedColumnNdx) {
247:                    try {
248:                        cachedColumnValue = rs.getObject(colNdx + 1);
249:                    } catch (SQLException sex) {
250:                        throw new DbOrmException(
251:                                "Unable to read value for column #"
252:                                        + (colNdx + 1) + '.');
253:                    }
254:                    cachedColumnNdx = colNdx;
255:                }
256:                return cachedColumnValue;
257:            }
258:
259:            public Object[] parseObjects(Class... types) {
260:                int totalTypes = types.length;
261:                Object[] result = new Object[totalTypes];
262:                boolean[] resultUsage = new boolean[totalTypes];
263:                String[] typesTableNames = createTypesTableNames(types);
264:
265:                int currentResult = 0;
266:                cachedColumnNdx = -1;
267:                int colNdx = 0;
268:                while (colNdx < totalColumns) {
269:
270:                    // no more types for mapping?
271:                    if (currentResult >= totalTypes) {
272:                        break;
273:                    }
274:
275:                    // skip columns that doesn't map
276:                    Class currentType = types[currentResult];
277:                    if (currentType == null) {
278:                        colNdx++;
279:                        currentResult++;
280:                        resultColums.clear();
281:                        continue;
282:                    }
283:
284:                    Object value = readColumnValue(colNdx);
285:                    String columnName = columnNames[colNdx];
286:                    String tableName = tableNames[colNdx];
287:                    String resultTableName = typesTableNames[currentResult];
288:
289:                    if (resultTableName == null) {
290:                        // match: simple type
291:                        result[currentResult] = ReflectUtil.castType(value,
292:                                currentType);
293:                        resultUsage[currentResult] = true;
294:                        colNdx++;
295:                        currentResult++;
296:                        resultColums.clear();
297:                        continue;
298:                    }
299:                    //if ((tableName == null) || (resultTableName.equals(tableName) == true)) {
300:                    if ((tableName == null)
301:                            || (Wildcard.equalsOrMatch(tableName,
302:                                    resultTableName) == true)) {
303:                        if (resultColums.contains(columnName) == false) {
304:                            String propertyName = dbOrm.lookup(currentType)
305:                                    .getPropertyName(columnName);
306:                            if (propertyName != null) {
307:                                if (result[currentResult] == null) {
308:                                    result[currentResult] = newInstance(currentType);
309:                                }
310:                                /*
311:                                 boolean success =
312:                                 value != null ?
313:                                 BeanUtil.setDeclaredPropertySilent(result[currentResult], propertyName, value)
314:                                 :
315:                                 BeanUtil.hasDeclaredProperty(result[currentResult], propertyName);
316:                                 */
317:                                if (BeanUtil.hasDeclaredProperty(
318:                                        result[currentResult], propertyName) == true) {
319:                                    // match: entity
320:                                    if (value != null) {
321:                                        BeanUtil.setDeclaredProperty(
322:                                                result[currentResult],
323:                                                propertyName, value);
324:                                        resultUsage[currentResult] = true;
325:                                    }
326:                                    colNdx++;
327:                                    resultColums.add(columnName);
328:                                    continue;
329:                                }
330:                            }
331:                        }
332:                    }
333:                    // got to next type, i.e. result
334:                    currentResult++;
335:                    resultColums.clear();
336:                }
337:
338:                resultColums.clear();
339:                for (int i = 0; i < resultUsage.length; i++) {
340:                    if (resultUsage[i] == false) {
341:                        result[i] = null;
342:                    }
343:                }
344:                return result;
345:            }
346:
347:            public Object parseOneObject(Class... types) {
348:                return parseObjects(types)[0];
349:            }
350:
351:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.