View Javadoc

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