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.handlers;
18
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.util.Map;
22
23 import org.apache.commons.dbutils.RowProcessor;
24
25 /**
26 * <p>
27 * <code>ResultSetHandler</code> implementation that returns a Map of Maps.
28 * <code>ResultSet</code> rows are converted into Maps which are then stored
29 * in a Map under the given key.
30 * </p>
31 * <p>
32 * If you had a Person table with a primary key column called ID, you could
33 * retrieve rows from the table like this:
34 * <pre>
35 * ResultSetHandler h = new KeyedHandler("id");
36 * Map found = (Map) queryRunner.query("select id, name, age from person", h);
37 * Map jane = (Map) found.get(new Long(1)); // jane's id is 1
38 * String janesName = (String) jane.get("name");
39 * Integer janesAge = (Integer) jane.get("age");
40 * </pre>
41 * Note that the "id" passed to KeyedHandler and "name" and "age" passed to the
42 * returned Map's get() method can be in any case. The data types returned for
43 * name and age are dependent upon how your JDBC driver converts SQL column
44 * types from the Person table into Java types.
45 * </p>
46 * <p>This class is thread safe.</p>
47 *
48 * @param <K> The type of the key
49 * @see org.apache.commons.dbutils.ResultSetHandler
50 * @since DbUtils 1.1
51 */
52 public class KeyedHandler<K> extends AbstractKeyedHandler<K, Map<String, Object>> {
53
54 /**
55 * The RowProcessor implementation to use when converting rows
56 * into Objects.
57 */
58 protected final RowProcessor convert;
59
60 /**
61 * The column index to retrieve key values from. Defaults to 1.
62 */
63 protected final int columnIndex;
64
65 /**
66 * The column name to retrieve key values from. Either columnName or
67 * columnIndex will be used but never both.
68 */
69 protected final String columnName;
70
71 /**
72 * Creates a new instance of KeyedHandler. The value of the first column
73 * of each row will be a key in the Map.
74 */
75 public KeyedHandler() {
76 this(ArrayHandler.ROW_PROCESSOR, 1, null);
77 }
78
79 /**
80 * Creates a new instance of KeyedHandler. The value of the first column
81 * of each row will be a key in the Map.
82 *
83 * @param convert The <code>RowProcessor</code> implementation
84 * to use when converting rows into Maps
85 */
86 public KeyedHandler(RowProcessor convert) {
87 this(convert, 1, null);
88 }
89
90 /**
91 * Creates a new instance of KeyedHandler.
92 *
93 * @param columnIndex The values to use as keys in the Map are
94 * retrieved from the column at this index.
95 */
96 public KeyedHandler(int columnIndex) {
97 this(ArrayHandler.ROW_PROCESSOR, columnIndex, null);
98 }
99
100 /**
101 * Creates a new instance of KeyedHandler.
102 *
103 * @param columnName The values to use as keys in the Map are
104 * retrieved from the column with this name.
105 */
106 public KeyedHandler(String columnName) {
107 this(ArrayHandler.ROW_PROCESSOR, 1, columnName);
108 }
109
110 /** Private Helper
111 * @param convert The <code>RowProcessor</code> implementation
112 * to use when converting rows into Maps
113 * @param columnIndex The values to use as keys in the Map are
114 * retrieved from the column at this index.
115 * @param columnName The values to use as keys in the Map are
116 * retrieved from the column with this name.
117 */
118 private KeyedHandler(RowProcessor convert, int columnIndex,
119 String columnName) {
120 super();
121 this.convert = convert;
122 this.columnIndex = columnIndex;
123 this.columnName = columnName;
124 }
125 /**
126 * This factory method is called by <code>handle()</code> to retrieve the
127 * key value from the current <code>ResultSet</code> row. This
128 * implementation returns <code>ResultSet.getObject()</code> for the
129 * configured key column name or index.
130 * @param rs ResultSet to create a key from
131 * @return Object from the configured key column name/index
132 *
133 * @throws SQLException if a database access error occurs
134 * @throws ClassCastException if the class datatype does not match the column type
135 */
136 // We assume that the user has picked the correct type to match the column
137 // so getObject will return the appropriate type and the cast will succeed.
138 @SuppressWarnings("unchecked")
139 @Override
140 protected K createKey(ResultSet rs) throws SQLException {
141 return (columnName == null) ?
142 (K) rs.getObject(columnIndex) :
143 (K) rs.getObject(columnName);
144 }
145
146 /**
147 * This factory method is called by <code>handle()</code> to store the
148 * current <code>ResultSet</code> row in some object. This
149 * implementation returns a <code>Map</code> with case insensitive column
150 * names as keys. Calls to <code>map.get("COL")</code> and
151 * <code>map.get("col")</code> return the same value.
152 * @param rs ResultSet to create a row from
153 * @return Object typed Map containing column names to values
154 * @throws SQLException if a database access error occurs
155 */
156 @Override
157 protected Map<String, Object> createRow(ResultSet rs) throws SQLException {
158 return this.convert.toMap(rs);
159 }
160
161 }