KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > system > jdbc > RowToObjectMapper


1 /*
2  * Copyright 2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18
19 package org.apache.beehive.controls.system.jdbc;
20
21 import org.apache.beehive.controls.api.ControlException;
22
23 import java.lang.reflect.AccessibleObject JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.InvocationTargetException JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.lang.reflect.Modifier JavaDoc;
28 import java.sql.ResultSet JavaDoc;
29 import java.sql.ResultSetMetaData JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.util.Calendar JavaDoc;
32 import java.util.HashMap JavaDoc;
33
34 /**
35  * Map a ResultSet row to an Object. This mapper uses Java reflection to perform the mapping. The Class being mapped
36  * to must have setter methods which match the ResultSet column names. For example, if a column in the ResultSet
37  * named USERID, the object must have a setter method named setUserid(). If a setter method cannot be class fields
38  * are also checked, the same naming conventions applies, USERID -> userid.
39  */

40 public class RowToObjectMapper extends RowMapper {
41
42     private final int _columnCount;
43
44     private AccessibleObject JavaDoc[] _fields;
45     private int[] _fieldTypes;
46
47     private final Object JavaDoc[] _args = new Object JavaDoc[1];
48
49     /**
50      * Create a new RowToObjectMapper.
51      *
52      * @param resultSet ResultSet to map
53      * @param returnTypeClass Class to map to.
54      * @param cal Calendar instance for date/time mappings.
55      */

56     RowToObjectMapper(ResultSet JavaDoc resultSet, Class JavaDoc returnTypeClass, Calendar JavaDoc cal) {
57         super(resultSet, returnTypeClass, cal);
58
59         _fields = null;
60
61         try {
62             _columnCount = resultSet.getMetaData().getColumnCount();
63         } catch (SQLException JavaDoc e) {
64             throw new ControlException("RowToObjectMapper: SQLException: " + e.getMessage(), e);
65         }
66     }
67
68     /**
69      * Do the mapping.
70      *
71      * @return An object instance.
72      */

73     public Object JavaDoc mapRowToReturnType() {
74
75         Object JavaDoc resultObject = null;
76
77         // if the ResultSet only contains a single column we may be able to map directly
78
// to the return type -- if so we don't need to build any structures to support
79
// mapping
80
if (_columnCount == 1) {
81
82             final int typeId = _tmf.getTypeId(_returnTypeClass);
83
84             try {
85                 if (typeId != TypeMappingsFactory.TYPE_UNKNOWN) {
86                     return extractColumnValue(1, typeId);
87                 } else {
88                     // we still might want a single value (i.e. java.util.Date)
89
Object JavaDoc val = extractColumnValue(1, typeId);
90                     if (_returnTypeClass.isAssignableFrom(val.getClass())) {
91                         return val;
92                     }
93                 }
94             } catch (SQLException JavaDoc e) {
95                 throw new ControlException(e.getMessage(), e);
96             }
97         }
98
99         if (_fields == null) {
100             try {
101                 getFieldMappings();
102             } catch (SQLException JavaDoc e) {
103                 throw new ControlException(e.getMessage(), e);
104             }
105         }
106
107         try {
108             resultObject = _returnTypeClass.newInstance();
109         } catch (InstantiationException JavaDoc e) {
110             throw new ControlException("InstantiationException when trying to create instance of : "
111                                        + _returnTypeClass.getName(), e);
112         } catch (IllegalAccessException JavaDoc e) {
113             throw new ControlException("IllegalAccessException when trying to create instance of : "
114                                        + _returnTypeClass.getName(), e);
115         }
116
117         for (int i = 1; i < _fields.length; i++) {
118             AccessibleObject JavaDoc f = _fields[i];
119             Object JavaDoc resultValue = null;
120
121             try {
122                 resultValue = extractColumnValue(i, _fieldTypes[i]);
123                 if (f instanceof Field JavaDoc) {
124                     ((Field JavaDoc) f).set(resultObject, resultValue);
125                 } else {
126                     _args[0] = resultValue;
127                     ((Method JavaDoc) f).invoke(resultObject, _args);
128                 }
129             } catch (SQLException JavaDoc e) {
130                 throw new ControlException(e.getMessage(), e);
131             } catch (IllegalArgumentException JavaDoc iae) {
132
133                 try {
134                     ResultSetMetaData JavaDoc md = _resultSet.getMetaData();
135                     if (f instanceof Field JavaDoc) {
136                         throw new ControlException("The declared Java type for field " + ((Field JavaDoc) f).getName()
137                                                    + ((Field JavaDoc) f).getType().toString()
138                                                    + " is incompatible with the SQL format of column " + md.getColumnName(i).toString()
139                                                    + md.getColumnTypeName(i).toString()
140                                                    + " which returns objects of type " + resultValue.getClass().getName());
141                     } else {
142                         throw new ControlException("The declared Java type for method " + ((Method JavaDoc) f).getName()
143                                                    + ((Method JavaDoc) f).getParameterTypes()[0].toString()
144                                                    + " is incompatible with the SQL format of column " + md.getColumnName(i).toString()
145                                                    + md.getColumnTypeName(i).toString()
146                                                    + " which returns objects of type " + resultValue.getClass().getName());
147                     }
148                 } catch (SQLException JavaDoc e) {
149                     throw new ControlException(e.getMessage(), e);
150                 }
151
152             } catch (IllegalAccessException JavaDoc e) {
153                 if (f instanceof Field JavaDoc) {
154                     throw new ControlException("IllegalAccessException when trying to access field " + ((Field JavaDoc) f).getName(), e);
155                 } else {
156                     throw new ControlException("IllegalAccessException when trying to access method " + ((Method JavaDoc) f).getName(), e);
157                 }
158             } catch (InvocationTargetException JavaDoc e) {
159                 if (f instanceof Field JavaDoc) {
160                     throw new ControlException("InvocationTargetException when trying to access field " + ((Field JavaDoc) f).getName(), e);
161                 } else {
162                     throw new ControlException("InvocationTargetException when trying to access method " + ((Method JavaDoc) f).getName(), e);
163                 }
164             }
165         }
166         return resultObject;
167     }
168
169     /**
170      * Build the structures necessary to do the mapping
171      *
172      * @throws SQLException on error.
173      */

174     protected void getFieldMappings()
175             throws SQLException JavaDoc {
176
177         final String JavaDoc[] keys = getKeysFromResultSet();
178
179         //
180
// find fields or setters for return class
181
//
182
HashMap JavaDoc<String JavaDoc, AccessibleObject JavaDoc> mapFields = new HashMap JavaDoc<String JavaDoc, AccessibleObject JavaDoc>(_columnCount * 2);
183         for (int i = 1; i <= _columnCount; i++) {
184             mapFields.put(keys[i], null);
185         }
186
187         // public methods
188
Method JavaDoc[] classMethods = _returnTypeClass.getMethods();
189         for (Method JavaDoc m : classMethods) {
190
191             if (isSetterMethod(m)) {
192                 final String JavaDoc fieldName = m.getName().substring(3).toUpperCase();
193                 if (mapFields.containsKey(fieldName)) {
194
195                     // check for overloads
196
Object JavaDoc field = mapFields.get(fieldName);
197                     if (field == null) {
198                         mapFields.put(fieldName, m);
199                     } else {
200                         throw new ControlException("Unable to choose between overloaded methods " + m.getName()
201                                                    + " on the " + _returnTypeClass.getName() + " class. Mapping is done using "
202                                                    + "a case insensitive comparision of SQL ResultSet columns to field "
203                                                    + "names and public setter methods on the return class.");
204                     }
205                 }
206             }
207         }
208
209         // fix for 8813: include inherited and non-public fields
210
for (Class JavaDoc clazz = _returnTypeClass; clazz != null && clazz != Object JavaDoc.class; clazz = clazz.getSuperclass()) {
211             Field JavaDoc[] classFields = clazz.getDeclaredFields();
212             for (Field JavaDoc f : classFields) {
213                 if (Modifier.isStatic(f.getModifiers())) continue;
214                 if (!Modifier.isPublic(f.getModifiers())) continue;
215                 String JavaDoc fieldName = f.getName().toUpperCase();
216                 if (!mapFields.containsKey(fieldName)) continue;
217
218                 Object JavaDoc field = mapFields.get(fieldName);
219                 if (field == null) {
220                     mapFields.put(fieldName, f);
221                 }
222             }
223         }
224
225         // finally actually init the fields array
226
_fields = new AccessibleObject JavaDoc[_columnCount + 1];
227         _fieldTypes = new int[_columnCount + 1];
228
229         for (int i = 1; i < _fields.length; i++) {
230             AccessibleObject JavaDoc f = mapFields.get(keys[i]);
231             if (f == null) {
232                 throw new ControlException("Unable to map the SQL column " + keys[i]
233                                            + " to a field on the " + _returnTypeClass.getName() +
234                                            " class. Mapping is done using a case insensitive comparision of SQL ResultSet "
235                                            + "columns to field names and public setter methods on the return class.");
236             }
237
238             _fields[i] = f;
239             if (f instanceof Field JavaDoc) {
240                 _fieldTypes[i] = _tmf.getTypeId(((Field JavaDoc) f).getType());
241             } else {
242                 _fieldTypes[i] = _tmf.getTypeId(((Method JavaDoc) f).getParameterTypes()[0]);
243             }
244         }
245     }
246 }
247
Popular Tags