Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BasicRowProcessor |
|
| 1.25;1.25 | ||||
BasicRowProcessor$1 |
|
| 1.25;1.25 | ||||
BasicRowProcessor$CaseInsensitiveHashMap |
|
| 1.25;1.25 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | package org.apache.commons.dbutils; | |
18 | ||
19 | import java.sql.ResultSet; | |
20 | import java.sql.ResultSetMetaData; | |
21 | import java.sql.SQLException; | |
22 | import java.util.HashMap; | |
23 | import java.util.Iterator; | |
24 | import java.util.List; | |
25 | import java.util.Map; | |
26 | ||
27 | /** | |
28 | * Basic implementation of the <code>RowProcessor</code> interface. | |
29 | * | |
30 | * <p> | |
31 | * This class is thread-safe. | |
32 | * </p> | |
33 | * | |
34 | * @see RowProcessor | |
35 | */ | |
36 | public class BasicRowProcessor implements RowProcessor { | |
37 | ||
38 | /** | |
39 | * The default BeanProcessor instance to use if not supplied in the | |
40 | * constructor. | |
41 | */ | |
42 | 0 | private static final BeanProcessor defaultConvert = new BeanProcessor(); |
43 | ||
44 | /** | |
45 | * The Singleton instance of this class. | |
46 | */ | |
47 | 0 | private static final BasicRowProcessor instance = new BasicRowProcessor(); |
48 | ||
49 | /** | |
50 | * Returns the Singleton instance of this class. | |
51 | * | |
52 | * @return The single instance of this class. | |
53 | * @deprecated Create instances with the constructors instead. This will | |
54 | * be removed after DbUtils 1.1. | |
55 | */ | |
56 | public static BasicRowProcessor instance() { | |
57 | 0 | return instance; |
58 | } | |
59 | ||
60 | /** | |
61 | * Use this to process beans. | |
62 | */ | |
63 | private final BeanProcessor convert; | |
64 | ||
65 | /** | |
66 | * BasicRowProcessor constructor. Bean processing defaults to a | |
67 | * BeanProcessor instance. | |
68 | */ | |
69 | public BasicRowProcessor() { | |
70 | 0 | this(defaultConvert); |
71 | 0 | } |
72 | ||
73 | /** | |
74 | * BasicRowProcessor constructor. | |
75 | * @param convert The BeanProcessor to use when converting columns to | |
76 | * bean properties. | |
77 | * @since DbUtils 1.1 | |
78 | */ | |
79 | public BasicRowProcessor(BeanProcessor convert) { | |
80 | 0 | super(); |
81 | 0 | this.convert = convert; |
82 | 0 | } |
83 | ||
84 | /** | |
85 | * Convert a <code>ResultSet</code> row into an <code>Object[]</code>. | |
86 | * This implementation copies column values into the array in the same | |
87 | * order they're returned from the <code>ResultSet</code>. Array elements | |
88 | * will be set to <code>null</code> if the column was SQL NULL. | |
89 | * | |
90 | * @see org.apache.commons.dbutils.RowProcessor#toArray(java.sql.ResultSet) | |
91 | */ | |
92 | public Object[] toArray(ResultSet rs) throws SQLException { | |
93 | 0 | ResultSetMetaData meta = rs.getMetaData(); |
94 | 0 | int cols = meta.getColumnCount(); |
95 | 0 | Object[] result = new Object[cols]; |
96 | ||
97 | 0 | for (int i = 0; i < cols; i++) { |
98 | 0 | result[i] = rs.getObject(i + 1); |
99 | } | |
100 | ||
101 | 0 | return result; |
102 | } | |
103 | ||
104 | /** | |
105 | * Convert a <code>ResultSet</code> row into a JavaBean. This | |
106 | * implementation delegates to a BeanProcessor instance. | |
107 | * @see org.apache.commons.dbutils.RowProcessor#toBean(java.sql.ResultSet, java.lang.Class) | |
108 | * @see org.apache.commons.dbutils.BeanProcessor#toBean(java.sql.ResultSet, java.lang.Class) | |
109 | */ | |
110 | public Object toBean(ResultSet rs, Class type) throws SQLException { | |
111 | 0 | return this.convert.toBean(rs, type); |
112 | } | |
113 | ||
114 | /** | |
115 | * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans. | |
116 | * This implementation delegates to a BeanProcessor instance. | |
117 | * @see org.apache.commons.dbutils.RowProcessor#toBeanList(java.sql.ResultSet, java.lang.Class) | |
118 | * @see org.apache.commons.dbutils.BeanProcessor#toBeanList(java.sql.ResultSet, java.lang.Class) | |
119 | */ | |
120 | public List toBeanList(ResultSet rs, Class type) throws SQLException { | |
121 | 0 | return this.convert.toBeanList(rs, type); |
122 | } | |
123 | ||
124 | /** | |
125 | * Convert a <code>ResultSet</code> row into a <code>Map</code>. This | |
126 | * implementation returns a <code>Map</code> with case insensitive column | |
127 | * names as keys. Calls to <code>map.get("COL")</code> and | |
128 | * <code>map.get("col")</code> return the same value. | |
129 | * @see org.apache.commons.dbutils.RowProcessor#toMap(java.sql.ResultSet) | |
130 | */ | |
131 | public Map toMap(ResultSet rs) throws SQLException { | |
132 | 0 | Map result = new CaseInsensitiveHashMap(); |
133 | 0 | ResultSetMetaData rsmd = rs.getMetaData(); |
134 | 0 | int cols = rsmd.getColumnCount(); |
135 | ||
136 | 0 | for (int i = 1; i <= cols; i++) { |
137 | 0 | result.put(rsmd.getColumnName(i), rs.getObject(i)); |
138 | } | |
139 | ||
140 | 0 | return result; |
141 | } | |
142 | ||
143 | /** | |
144 | * A Map that converts all keys to lowercase Strings for case insensitive | |
145 | * lookups. This is needed for the toMap() implementation because | |
146 | * databases don't consistenly handle the casing of column names. | |
147 | * | |
148 | * <p>The keys are stored as they are given [BUG #DBUTILS-34], so we maintain | |
149 | * an internal mapping from lowercase keys to the real keys in order to | |
150 | * achieve the case insensitive lookup. | |
151 | * | |
152 | * <p>Note: This implementation does not allow <tt>null</tt> | |
153 | * for key, whereas {@link HashMap} does, because of the code: | |
154 | * <pre> | |
155 | * key.toString().toLowerCase() | |
156 | * </pre> | |
157 | */ | |
158 | 0 | private static class CaseInsensitiveHashMap extends HashMap { |
159 | ||
160 | /** | |
161 | * The internal mapping from lowercase keys to the real keys. | |
162 | * | |
163 | * <p> | |
164 | * Any query operation using the key | |
165 | * ({@link #get(Object)}, {@link #containsKey(Object)}) | |
166 | * is done in three steps: | |
167 | * <ul> | |
168 | * <li>convert the parameter key to lower case</li> | |
169 | * <li>get the actual key that corresponds to the lower case key</li> | |
170 | * <li>query the map with the actual key</li> | |
171 | * </ul> | |
172 | * </p> | |
173 | */ | |
174 | 0 | private final Map lowerCaseMap = new HashMap(); |
175 | ||
176 | /** | |
177 | * Required for serialization support. | |
178 | * | |
179 | * @see java.io.Serializable | |
180 | */ | |
181 | private static final long serialVersionUID = 1841673097701957808L; | |
182 | ||
183 | /** | |
184 | * @see java.util.Map#containsKey(java.lang.Object) | |
185 | */ | |
186 | public boolean containsKey(Object key) { | |
187 | 0 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase()); |
188 | 0 | return super.containsKey(realKey); |
189 | // Possible optimisation here: | |
190 | // Since the lowerCaseMap contains a mapping for all the keys, | |
191 | // we could just do this: | |
192 | // return lowerCaseMap.containsKey(key.toString().toLowerCase()); | |
193 | } | |
194 | ||
195 | /** | |
196 | * @see java.util.Map#get(java.lang.Object) | |
197 | */ | |
198 | public Object get(Object key) { | |
199 | 0 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase()); |
200 | 0 | return super.get(realKey); |
201 | } | |
202 | ||
203 | /** | |
204 | * @see java.util.Map#put(java.lang.Object, java.lang.Object) | |
205 | */ | |
206 | public Object put(Object key, Object value) { | |
207 | /* | |
208 | * In order to keep the map and lowerCaseMap synchronized, | |
209 | * we have to remove the old mapping before putting the | |
210 | * new one. Indeed, oldKey and key are not necessaliry equals. | |
211 | * (That's why we call super.remove(oldKey) and not just | |
212 | * super.put(key, value)) | |
213 | */ | |
214 | 0 | Object oldKey = lowerCaseMap.put(key.toString().toLowerCase(), key); |
215 | 0 | Object oldValue = super.remove(oldKey); |
216 | 0 | super.put(key, value); |
217 | 0 | return oldValue; |
218 | } | |
219 | ||
220 | /** | |
221 | * @see java.util.Map#putAll(java.util.Map) | |
222 | */ | |
223 | public void putAll(Map m) { | |
224 | 0 | Iterator iter = m.entrySet().iterator(); |
225 | 0 | while (iter.hasNext()) { |
226 | 0 | Map.Entry entry = (Map.Entry) iter.next(); |
227 | 0 | Object key = entry.getKey(); |
228 | 0 | Object value = entry.getValue(); |
229 | 0 | this.put(key, value); |
230 | 0 | } |
231 | 0 | } |
232 | ||
233 | /** | |
234 | * @see java.util.Map#remove(java.lang.Object) | |
235 | */ | |
236 | public Object remove(Object key) { | |
237 | 0 | Object realKey = lowerCaseMap.remove(key.toString().toLowerCase()); |
238 | 0 | return super.remove(realKey); |
239 | } | |
240 | } | |
241 | ||
242 | } |