1 package org.apache.torque.om.mapper;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.InputStream;
23 import java.io.Reader;
24 import java.math.BigDecimal;
25 import java.net.URL;
26 import java.sql.Array;
27 import java.sql.Blob;
28 import java.sql.Clob;
29 import java.sql.Date;
30 import java.sql.Ref;
31 import java.sql.ResultSet;
32 import java.sql.SQLException;
33 import java.sql.Time;
34 import java.sql.Timestamp;
35 import java.util.ArrayList;
36 import java.util.List;
37
38 import org.apache.torque.TorqueException;
39
40 /**
41 * Maps a record to a list of objects.
42 * Either the database driver decides which object type is appropriate
43 * for each column, or a list of classes can be defined.
44 *
45 * @version $Id: ObjectListMapper.java 1380467 2012-09-04 07:33:05Z tfischer $
46 */
47 public class ObjectListMapper implements RecordMapper<List<Object>>
48 {
49 /** Serial Version UID. */
50 private static final long serialVersionUID = 1L;
51
52 /** Zero value for byte. */
53 private static final byte ZERO_BYTE = 0;
54
55 /** Zero value for short. */
56 private static final short ZERO_SHORT = 0;
57
58 /**
59 * Contains the classes to which the columns are mapped.
60 * The size of the list determines how many columns are read.
61 */
62 private List<Class<?>> convertClasses = null;
63
64 /**
65 * Constructor. Determines the number of columns to map from the
66 * result set's metadata (this may issue additional database queries).
67 * The classes the result columns are mapped to are determined by the
68 * database driver.
69 */
70 public ObjectListMapper()
71 {
72 // empty
73 }
74
75 /**
76 * Constructor which sets the number of columns to map.
77 * The classes the result columns are mapped to are determined by the
78 * database driver.
79 *
80 * @param numberOfColumnsToMap how many columns should be mapped,
81 * or -1 to determine the number of columns to map from the
82 * result set's metadata (this may issue
83 * additional database queries).
84 */
85 public ObjectListMapper(int numberOfColumnsToMap)
86 {
87 this.convertClasses = new ArrayList<Class<?>>(numberOfColumnsToMap);
88 if (numberOfColumnsToMap != -1)
89 {
90 for (int i = 0; i < numberOfColumnsToMap; ++i)
91 {
92 convertClasses.add(Object.class);
93 }
94 }
95 }
96
97 /**
98 * Constructor which determines the number of columns to map
99 * and the classes the result columns are mapped to.
100 *
101 * @param convertClasses the classes to which the columns should be mapped.
102 * The first column is mapped to the first class in the list and
103 * so on. May be null, in which case the number of columns to map
104 * and the mapped to classes are determined by the database driver.
105 * Known classes are: java.lang.reflect.Array, java.math.BigDecimal,
106 * java.io.InputStream, java.sql. Blob, Boolean, Byte, byte[],
107 * java.io.Reader, java.sql.Clob, java.sql.Date, Double, Float,
108 * Integer, Long, Object (i.e. let the database driver decide
109 * which class is returned), java.sql.Ref, Short, String,
110 * java.sql.Time, java.sql.Timestamp and java.net.URL.
111 */
112 public ObjectListMapper(List<Class<?>> convertClasses)
113 {
114 if (convertClasses != null)
115 {
116 this.convertClasses = new ArrayList<Class<?>>(convertClasses);
117 }
118 }
119
120 /**
121 * Maps the current row in the result set by reading all columns from
122 * offset on to the end of the row and store an object for each column
123 * in the result.
124 *
125 * @param resultSet the result set to map, not null.
126 * @param offset the offset of this mapper within the result set.
127 *
128 * @return a list of mapped objects in the same order as the mappers
129 * were ordered, not null.
130 *
131 * @throws TorqueException if retrieving column values from the result set
132 * fails or if the number of available columns cannot be determined
133 * from the result set.
134 */
135 public List<Object> processRow(ResultSet resultSet, int offset)
136 throws TorqueException
137 {
138 try
139 {
140 int currentNumberOfColumnsToMap;
141 if (convertClasses != null)
142 {
143 currentNumberOfColumnsToMap = convertClasses.size();
144 }
145 else
146 {
147 int resultSetLength = resultSet.getMetaData().getColumnCount();
148 currentNumberOfColumnsToMap = resultSetLength - offset;
149 }
150
151 List<Object> result
152 = new ArrayList<Object>(currentNumberOfColumnsToMap);
153 for (int i = 0; i < currentNumberOfColumnsToMap; ++i)
154 {
155 Class<?> mapClass;
156 if (convertClasses != null)
157 {
158 mapClass = convertClasses.get(i);
159 }
160 else
161 {
162 mapClass = Object.class;
163 }
164 Object columnValue;
165 int columnIndex = i + offset + 1;
166 if (mapClass.equals(Array.class))
167 {
168 columnValue = resultSet.getArray(columnIndex);
169 }
170 else if (mapClass.equals(BigDecimal.class))
171 {
172 columnValue = resultSet.getBigDecimal(columnIndex);
173 }
174 else if (mapClass.equals(InputStream.class))
175 {
176 columnValue = resultSet.getBinaryStream(columnIndex);
177 }
178 else if (mapClass.equals(Blob.class))
179 {
180 columnValue = resultSet.getBlob(columnIndex);
181 }
182 else if (mapClass.equals(Boolean.class))
183 {
184 columnValue = resultSet.getBoolean(columnIndex);
185 }
186 else if (mapClass.equals(Byte.class))
187 {
188 columnValue = resultSet.getByte(columnIndex);
189 if (Byte.valueOf(ZERO_BYTE).equals(columnValue)
190 && resultSet.wasNull())
191 {
192 columnValue = null;
193 }
194 }
195 else if (mapClass.equals(byte[].class))
196 {
197 columnValue = resultSet.getBytes(columnIndex);
198 }
199 else if (mapClass.equals(Reader.class))
200 {
201 columnValue = resultSet.getCharacterStream(columnIndex);
202 }
203 else if (mapClass.equals(Clob.class))
204 {
205 columnValue = resultSet.getClob(columnIndex);
206 }
207 else if (mapClass.equals(Date.class))
208 {
209 columnValue = resultSet.getDate(columnIndex);
210 }
211 else if (mapClass.equals(Double.class))
212 {
213 columnValue = resultSet.getDouble(columnIndex);
214 if (Double.valueOf(0d).equals(columnValue)
215 && resultSet.wasNull())
216 {
217 columnValue = null;
218 }
219 }
220 else if (mapClass.equals(Float.class))
221 {
222 columnValue = resultSet.getFloat(columnIndex);
223 if (Float.valueOf(0f).equals(columnValue)
224 && resultSet.wasNull())
225 {
226 columnValue = null;
227 }
228 }
229 else if (mapClass.equals(Integer.class))
230 {
231 columnValue = resultSet.getInt(columnIndex);
232 if (Integer.valueOf(0).equals(columnValue)
233 && resultSet.wasNull())
234 {
235 columnValue = null;
236 }
237 }
238 else if (mapClass.equals(Long.class))
239 {
240 columnValue = resultSet.getLong(columnIndex);
241 if (Long.valueOf(0L).equals(columnValue)
242 && resultSet.wasNull())
243 {
244 columnValue = null;
245 }
246 }
247 else if (mapClass.equals(Object.class))
248 {
249 columnValue = resultSet.getObject(columnIndex);
250 }
251 else if (mapClass.equals(Ref.class))
252 {
253 columnValue = resultSet.getRef(columnIndex);
254 }
255 else if (mapClass.equals(Short.class))
256 {
257 columnValue = resultSet.getShort(columnIndex);
258 if (Short.valueOf(ZERO_SHORT).equals(columnValue)
259 && resultSet.wasNull())
260 {
261 columnValue = null;
262 }
263 }
264 else if (mapClass.equals(String.class))
265 {
266 columnValue = resultSet.getString(columnIndex);
267 }
268 else if (mapClass.equals(Time.class))
269 {
270 columnValue = resultSet.getTime(columnIndex);
271 }
272 else if (mapClass.equals(Timestamp.class))
273 {
274 columnValue = resultSet.getTimestamp(columnIndex);
275 }
276 else if (mapClass.equals(URL.class))
277 {
278 columnValue = resultSet.getURL(columnIndex);
279 }
280 else
281 {
282 throw new IllegalArgumentException(
283 "Unknown convertClass " + mapClass.getName()
284 + " at position " + i);
285 }
286 result.add(columnValue);
287 }
288 return result;
289 }
290 catch (SQLException e)
291 {
292 throw new TorqueException(e);
293 }
294 }
295 }
296