1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package com.finalist.tools.database;
19
20 import java.sql.*;
21 import java.util.HashMap;
22 import java.util.Calendar;
23 import java.math.BigDecimal;
24 import java.lang.reflect.InvocationTargetException;
25
26 /***
27 * This RowMapper attempts to break away from the database-dependent row mappers by providing
28 * a generic JDBC-to-Java Object mapping.
29 *
30 * @author Michael O'Connor - Finalist IT Group
31 */
32 public class GenericRowMapper extends RowMapper {
33 private static final HashMap JDBC_TYPES = new HashMap();
34 private static final String INT = "int";
35
36
37 static {
38 java.lang.reflect.Field[] fields = java.sql.Types.class.getDeclaredFields();
39 for (int i = 0; i < fields.length; i++) {
40 try {
41 Object key = fields[i].get(null);
42 JDBC_TYPES.put(key, fields[i].getName());
43 }
44 catch (Exception e) {
45
46 }
47 }
48 }
49
50
51 /*** @see {@link RowMapper#bind}. */
52 public PreparedStatement bind(PreparedStatement pstmt, Object bindVar, String bindVarClassType, int pos)
53 throws SQLException, NotMappableException {
54 if (bindVarClassType.endsWith("String")) {
55 if (bindVar == null) {
56 pstmt.setNull(pos, Types.VARCHAR);
57 }
58 else {
59 pstmt.setString(pos, (String) bindVar);
60 }
61
62 }
63 else if (bindVarClassType.endsWith("int")) {
64 if (bindVar == null) {
65 pstmt.setNull(pos, Types.NUMERIC);
66 }
67 else {
68 pstmt.setInt(pos, ((Integer) bindVar).intValue());
69 }
70
71 }
72 else if (bindVarClassType.endsWith("Integer")) {
73 if (bindVar == null) {
74 pstmt.setNull(pos, Types.NUMERIC);
75 }
76 else {
77 pstmt.setInt(pos, ((Integer) bindVar).intValue());
78 }
79
80 }
81 else if (bindVarClassType.toLowerCase().endsWith("byte")) {
82 if (bindVar == null) {
83 pstmt.setNull(pos, Types.NUMERIC);
84 }
85 else {
86 pstmt.setByte(pos, ((Byte) bindVar).byteValue());
87 }
88
89 }
90 else if (bindVarClassType.toLowerCase().endsWith("short")) {
91 if (bindVar == null) {
92 pstmt.setNull(pos, Types.NUMERIC);
93 }
94 else {
95 pstmt.setShort(pos, ((Short) bindVar).shortValue());
96 }
97
98 }
99 else if (bindVarClassType.toLowerCase().endsWith("float")) {
100 if (bindVar == null) {
101 pstmt.setNull(pos, Types.NUMERIC);
102 }
103 else {
104 pstmt.setFloat(pos, ((Float) bindVar).floatValue());
105 }
106
107 }
108 else if (bindVarClassType.toLowerCase().endsWith("long")) {
109 if (bindVar == null) {
110 pstmt.setNull(pos, Types.NUMERIC);
111 }
112 else {
113 pstmt.setLong(pos, ((Long) bindVar).longValue());
114 }
115
116 }
117 else if (bindVarClassType.toLowerCase().endsWith("double")) {
118 if (bindVar == null) {
119 pstmt.setNull(pos, Types.NUMERIC);
120 }
121 else {
122 pstmt.setDouble(pos, ((Double) bindVar).doubleValue());
123 }
124
125 }
126 else if (bindVarClassType.toLowerCase().endsWith("math.bigdecimal")) {
127 if (bindVar == null) {
128 pstmt.setNull(pos, Types.NUMERIC);
129 }
130 else {
131 pstmt.setDouble(pos, ((BigDecimal) bindVar).doubleValue());
132 }
133
134 }
135 else if (bindVarClassType.endsWith("util.Date")) {
136 if (bindVar == null) {
137 pstmt.setNull(pos, Types.DATE);
138 }
139 else {
140 pstmt.setTimestamp(pos, new Timestamp(((java.util.Date) bindVar).getTime()));
141 }
142
143 }
144 else if (bindVarClassType.endsWith("sql.Date")) {
145 if (bindVar == null) {
146 pstmt.setNull(pos, Types.DATE);
147 }
148 else {
149 pstmt.setTimestamp(pos, new Timestamp(((java.sql.Date) bindVar).getTime()));
150 }
151
152 }
153 else if (bindVarClassType.endsWith("sql.Timestamp")) {
154 if (bindVar == null) {
155 pstmt.setNull(pos, Types.TIMESTAMP);
156 }
157 else {
158 pstmt.setTimestamp(pos, (Timestamp) bindVar);
159 }
160
161 }
162 else if (bindVarClassType.endsWith("Calendar")) {
163 if (bindVar == null) {
164 pstmt.setNull(pos, Types.TIMESTAMP);
165 }
166 else {
167 pstmt.setTimestamp(pos, new Timestamp(((Calendar) bindVar).getTime().getTime()));
168 }
169
170 }
171 else if ((bindVar == null) && (bindVarClassType.equals("undetermined"))) {
172 pstmt.setNull(pos, Types.VARCHAR);
173
174 }
175 else {
176 NotMappableException nme = new NotMappableException();
177 nme.setDuringBind(true);
178 nme.setSourceType(bindVarClassType);
179 if (bindVar == null) bindVar = "null";
180 nme.setSourceValue(bindVar.toString());
181 nme.setTargetName("position " + pos);
182 throw nme;
183 }
184
185 return pstmt;
186 }
187
188
189 /*** @see {@link RowMapper#unBindIntoHashMap}. */
190 public HashMap unBindIntoHashMap(ResultSet rset, HashMap target) throws SQLException, NotMappableException {
191
192 throw new RuntimeException("unBindIntoHashMap not supported by GenericRowMapper!");
193 }
194
195
196 /*** @see {@link RowMapper#unBindIntoBean}. */
197 public Object unBindIntoBean(ResultSet rset, Object target) throws SQLException, NotMappableException {
198 ResultSetMetaData rsmd = rset.getMetaData();
199 String dbSpecificColumnType = null;
200 String sourceName = null;
201 String targetType = null;
202 String valueClass = null;
203 String columnType = null;
204 for (int i = 1; i < rsmd.getColumnCount() + 1; i++) {
205 try {
206 targetType = MethodInvoker.getReturnType(target, rsmd.getColumnName(i));
207 columnType = (String) JDBC_TYPES.get(new Integer(rsmd.getColumnType(i)));
208 dbSpecificColumnType = rsmd.getColumnTypeName(i);
209 sourceName = rsmd.getColumnName(i);
210
211 Object value = rset.getObject(i);
212 valueClass = value == null ? "null" : value.getClass().getName();
213
214
215 if (Integer.class.getName().equals(valueClass) && Byte.class.getName().equals(targetType)) {
216 value = new Byte((byte) ((Integer) value).intValue());
217 }
218 if (Integer.class.getName().equals(valueClass) && Short.class.getName().equals(targetType)) {
219 value = new Short((short) ((Integer) value).intValue());
220 }
221 if (BigDecimal.class.getName().equals(valueClass) && !BigDecimal.class.getName().equals(targetType)) {
222 if (isInteger(targetType)) {
223 value = new Integer(((BigDecimal) value).intValue());
224 }
225 else if (Double.class.getName().equals(targetType)) {
226 value = new Double(((BigDecimal) value).doubleValue());
227 }
228 else if (Long.class.getName().equals(targetType)) {
229 value = new Long(((BigDecimal) value).longValue());
230 }
231 }
232 if (Timestamp.class.getName().equals(valueClass) && java.sql.Date.class.getName().equals(targetType)) {
233 value = new java.sql.Date(((java.util.Date) value).getTime());
234 }
235
236 if (Blob.class.getName().equals(targetType)) {
237 value = rset.getBlob(i);
238 }
239
240 MethodInvoker.setProperty(target, sourceName, value);
241
242
243
244
245
246
247
248
249
250 }
251 catch (IllegalAccessException iae) {
252 System.out.println("!!No public getter/setter found in templateBean for column " + sourceName);
253 logTypeInformation(sourceName, targetType, columnType, dbSpecificColumnType, valueClass);
254
255
256 }
257 catch (InvocationTargetException ite) {
258 logTypeInformation(sourceName, targetType, columnType, dbSpecificColumnType, valueClass);
259 throw new NotMappableException("An InvocationTargetException ocurred");
260 }
261 catch (NoSuchMethodException nsme) {
262 System.out.println("!!No getter/setter found in templateBean for column " + sourceName);
263 logTypeInformation(sourceName, targetType, columnType, dbSpecificColumnType, valueClass);
264 }
265 catch (Exception e) {
266 System.out.println("Unexpected mapping error: " + e);
267 logTypeInformation(sourceName, targetType, columnType, dbSpecificColumnType, valueClass);
268 }
269
270 }
271
272 return target;
273
274 }
275
276
277 private void logTypeInformation(String sourceName, String targetType, String columnType, String dbSpecificColumnType, String valueClass) {
278 System.out.println("------ mapper error! ------");
279 System.out.println("column name =" + sourceName);
280 System.out.println("bean field type =" + targetType);
281 System.out.println("column type =" + columnType);
282 System.out.println("db specific column type=" + dbSpecificColumnType);
283 System.out.println("value class =" + valueClass);
284 System.out.println("---------------------------");
285 }
286
287
288 private boolean isInteger(String targetType) {
289 return targetType.toLowerCase().indexOf(INT) > -1;
290 }
291
292 }