View Javadoc

1   /*   Copyright (C) 2004 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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              //nothing
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       //todo: implement this..?
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             //Perform an object conversion, if necessary..
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 //            //if no mapping has been found, throw the NotMappableException
243 //            NotMappableException nme = new NotMappableException();
244 //            nme.setDuringBind(false);
245 //            nme.setSourceName(sourceName);
246 //            nme.setSourceType(sourceType);
247 //            nme.setTargetType(targetType);
248 //            throw nme;
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             //throw new NotMappableException("No public getter/setter found in templateBean for column "+sourceName);
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 }