KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jdbc > core > SingleColumnRowMapper


1 /*
2  * Copyright 2002-2006 the original author or authors.
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
17 package org.springframework.jdbc.core;
18
19 import java.math.BigDecimal JavaDoc;
20 import java.sql.Blob JavaDoc;
21 import java.sql.Clob JavaDoc;
22 import java.sql.ResultSet JavaDoc;
23 import java.sql.ResultSetMetaData JavaDoc;
24 import java.sql.SQLException JavaDoc;
25
26 import org.springframework.dao.TypeMismatchDataAccessException;
27 import org.springframework.jdbc.IncorrectResultSetColumnCountException;
28 import org.springframework.jdbc.support.JdbcUtils;
29 import org.springframework.util.NumberUtils;
30
31 /**
32  * RowMapper implementation that converts a single column into
33  * a single result value per row. Expects to work on a ResultSet
34  * that just contains a single column.
35  *
36  * <p>The type of the result value for each row can be specified.
37  * The value for the single column will be extracted from the ResultSet
38  * and converted into the specified target type.
39  *
40  * @author Juergen Hoeller
41  * @since 1.2
42  * @see JdbcTemplate#queryForList(String, Class)
43  * @see JdbcTemplate#queryForObject(String, Class)
44  */

45 public class SingleColumnRowMapper implements RowMapper {
46
47     private Class JavaDoc requiredType;
48
49
50     /**
51      * Create a new SingleColumnRowMapper.
52      * @see #setRequiredType
53      */

54     public SingleColumnRowMapper() {
55     }
56
57     /**
58      * Create a new SingleColumnRowMapper.
59      * @param requiredType the type that each result object is expected to match
60      */

61     public SingleColumnRowMapper(Class JavaDoc requiredType) {
62         this.requiredType = requiredType;
63     }
64
65     /**
66      * Set the type that each result object is expected to match.
67      * <p>If not specified, the column value will be exposed as
68      * returned by the JDBC driver.
69      */

70     public void setRequiredType(Class JavaDoc requiredType) {
71         this.requiredType = requiredType;
72     }
73
74
75     /**
76      * Extract a value for the single column in the current row.
77      * <p>Validates that there is only one column selected,
78      * then delegates to <code>getColumnValue()</code> and also
79      * <code>convertValueToRequiredType</code>, if necessary.
80      * @see java.sql.ResultSetMetaData#getColumnCount()
81      * @see #getColumnValue(java.sql.ResultSet, int, Class)
82      * @see #convertValueToRequiredType(Object, Class)
83      */

84     public Object JavaDoc mapRow(ResultSet JavaDoc rs, int rowNum) throws SQLException JavaDoc {
85         // Validate column count.
86
ResultSetMetaData JavaDoc rsmd = rs.getMetaData();
87         int nrOfColumns = rsmd.getColumnCount();
88         if (nrOfColumns != 1) {
89             throw new IncorrectResultSetColumnCountException(1, nrOfColumns);
90         }
91
92         // Extract column value from JDBC ResultSet
93
Object JavaDoc result = getColumnValue(rs, 1, this.requiredType);
94         if (result != null && this.requiredType != null && !this.requiredType.isInstance(result)) {
95             // Extracted value does not match already: try to convert it.
96
try {
97                 return convertValueToRequiredType(result, this.requiredType);
98             }
99             catch (IllegalArgumentException JavaDoc ex) {
100                 throw new TypeMismatchDataAccessException(
101                         "Type mismatch affecting row number " + rowNum + " and column type '" +
102                         rsmd.getColumnTypeName(1) + "': " + ex.getMessage());
103             }
104         }
105         return result;
106     }
107
108     /**
109      * Retrieve a JDBC object value for the specified column.
110      * <p>The default implementation calls <code>ResultSet.getString(index)</code> etc
111      * for all standard value types (String, Boolean, number types, date types, etc).
112      * It calls <code>ResultSet.getObject(index)</code> else.
113      * <p>If no required type has been specified, this method delegates to
114      * <code>getColumnValue(rs, index)</code>, which basically calls
115      * <code>ResultSet.getObject(index)</code> but applies some additional
116      * default conversion to appropriate value types.
117      * <p>Explicit extraction of a String is necessary to properly extract an Oracle
118      * RAW value as a String, for example. For the other given types, it is also
119      * recommendable to extract the desired types explicitly, to let the JDBC driver
120      * perform appropriate (potentially database-specific) conversion.
121      * @param rs is the ResultSet holding the data
122      * @param index is the column index
123      * @param requiredType the type that each result object is expected to match
124      * (or <code>null</code> if none specified)
125      * @return the Object value
126      * @see java.sql.ResultSet#getString(int)
127      * @see java.sql.ResultSet#getObject(int)
128      * @see #getColumnValue(java.sql.ResultSet, int)
129      */

130     protected Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int index, Class JavaDoc requiredType) throws SQLException JavaDoc {
131         if (requiredType != null) {
132             Object JavaDoc value = null;
133             boolean wasNullCheck = false;
134
135             // Explicitly extract typed value, as far as possible.
136
if (String JavaDoc.class.equals(requiredType)) {
137                 value = rs.getString(index);
138             }
139             else if (Boolean JavaDoc.class.equals(requiredType)) {
140                 value = (rs.getBoolean(index) ? Boolean.TRUE : Boolean.FALSE);
141                 wasNullCheck = true;
142             }
143             else if (Byte JavaDoc.class.equals(requiredType)) {
144                 value = new Byte JavaDoc(rs.getByte(index));
145                 wasNullCheck = true;
146             }
147             else if (Short JavaDoc.class.equals(requiredType)) {
148                 value = new Short JavaDoc(rs.getShort(index));
149                 wasNullCheck = true;
150             }
151             else if (Integer JavaDoc.class.equals(requiredType)) {
152                 value = new Integer JavaDoc(rs.getInt(index));
153                 wasNullCheck = true;
154             }
155             else if (Long JavaDoc.class.equals(requiredType)) {
156                 value = new Long JavaDoc(rs.getLong(index));
157                 wasNullCheck = true;
158             }
159             else if (Float JavaDoc.class.equals(requiredType)) {
160                 value = new Float JavaDoc(rs.getFloat(index));
161                 wasNullCheck = true;
162             }
163             else if (Double JavaDoc.class.equals(requiredType) || Number JavaDoc.class.equals(requiredType)) {
164                 value = new Double JavaDoc(rs.getDouble(index));
165                 wasNullCheck = true;
166             }
167             else if (byte[].class.equals(requiredType)) {
168                 value = rs.getBytes(index);
169             }
170             else if (java.sql.Date JavaDoc.class.equals(requiredType)) {
171                 value = rs.getDate(index);
172             }
173             else if (java.sql.Time JavaDoc.class.equals(requiredType)) {
174                 value = rs.getTime(index);
175             }
176             else if (java.sql.Timestamp JavaDoc.class.equals(requiredType) || java.util.Date JavaDoc.class.equals(requiredType)) {
177                 value = rs.getTimestamp(index);
178             }
179             else if (BigDecimal JavaDoc.class.equals(requiredType)) {
180                 value = rs.getBigDecimal(index);
181             }
182             else if (Blob JavaDoc.class.equals(requiredType)) {
183                 value = rs.getBlob(index);
184             }
185             else if (Clob JavaDoc.class.equals(requiredType)) {
186                 value = rs.getClob(index);
187             }
188             else {
189                 // Some unknown type desired -> rely on getObject.
190
value = rs.getObject(index);
191             }
192
193             // Perform was-null check if demanded (for results that the
194
// JDBC driver returns as primitives).
195
if (wasNullCheck && value != null && rs.wasNull()) {
196                 value = null;
197             }
198             return value;
199         }
200
201         else {
202             // No required type specified -> perform default extraction.
203
return getColumnValue(rs, index);
204         }
205     }
206
207     /**
208      * Retrieve a JDBC object value for the specified column, using the most
209      * appropriate value type. Called if no required type has been specified.
210      * <p>The default implementation delegates to <code>JdbcUtils.getResultSetValue()</code>,
211      * which uses the <code>ResultSet.getObject(index)</code> method. Additionally,
212      * it includes a "hack" to get around Oracle returning a non-standard object for
213      * their TIMESTAMP datatype. See the <code>JdbcUtils#getResultSetValue()</code>
214      * javadoc for details.
215      * @param rs is the ResultSet holding the data
216      * @param index is the column index
217      * @return the Object value
218      * @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int)
219      */

220     protected Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int index) throws SQLException JavaDoc {
221         return JdbcUtils.getResultSetValue(rs, index);
222     }
223
224     /**
225      * Convert the given column value to the specified required type.
226      * Only called if the extracted column value does not match already.
227      * <p>If the required type is String, the value will simply get stringified
228      * via <code>toString()</code>. In case of a Number, the value will be
229      * converted into a Number, either through number conversion or through
230      * String parsing (depending on the value type).
231      * @param value the column value as extracted from <code>getColumnValue()</code>
232      * (never <code>null</code>)
233      * @param requiredType the type that each result object is expected to match
234      * (never <code>null</code>)
235      * @return the converted value
236      * @see #getColumnValue(java.sql.ResultSet, int, Class)
237      */

238     protected Object JavaDoc convertValueToRequiredType(Object JavaDoc value, Class JavaDoc requiredType) {
239         if (String JavaDoc.class.equals(this.requiredType)) {
240             return value.toString();
241         }
242         else if (Number JavaDoc.class.isAssignableFrom(this.requiredType)) {
243             if (value instanceof Number JavaDoc) {
244                 // Convert original Number to target Number class.
245
return NumberUtils.convertNumberToTargetClass(((Number JavaDoc) value), this.requiredType);
246             }
247             else {
248                 // Convert stringified value to target Number class.
249
return NumberUtils.parseNumber(value.toString(), this.requiredType);
250             }
251         }
252         else {
253             throw new IllegalArgumentException JavaDoc(
254                     "Value [" + value + "] is of type [" + value.getClass().getName() +
255                     "] and cannot be converted to required type [" + this.requiredType.getName() + "]");
256         }
257     }
258
259 }
260
Popular Tags