001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.dbutils.handlers;
018
019 import java.sql.ResultSet;
020 import java.sql.SQLException;
021
022 import org.apache.commons.dbutils.RowProcessor;
023
024 /**
025 * <p>
026 * <code>ResultSetHandler</code> implementation that returns a Map of Beans.
027 * <code>ResultSet</code> rows are converted into Beans which are then stored in
028 * a Map under the given key.
029 * </p>
030 * <p>
031 * If you had a Person table with a primary key column called ID, you could
032 * retrieve rows from the table like this:
033 *
034 * <pre>
035 * ResultSetHandler<Map<Long, Person>> h = new BeanMapdHandler<Long, Person>(Person.class, "id");
036 * Map&ltLong, Person> found = queryRunner.query("select id, name, age from person", h);
037 * Person jane = found.get(1L); // jane's id is 1
038 * String janesName = jane.getName();
039 * Integer janesAge = jane.getAge();
040 * </pre>
041 *
042 * Note that the "id" passed to BeanMapHandler can be in any case. The data type
043 * returned for id is dependent upon how your JDBC driver converts SQL column
044 * types from the Person table into Java types. The "name" and "age" columns are
045 * converted according to their property descriptors by DbUtils.
046 * </p>
047 * <p>
048 * This class is thread safe.
049 * </p>
050 *
051 * @param <K>
052 * the type of keys maintained by the returned map
053 * @param <V>
054 * the type of the bean
055 * @see org.apache.commons.dbutils.ResultSetHandler
056 * @since DbUtils 1.5
057 */
058 public class BeanMapHandler<K, V> extends AbstractKeyedHandler<K, V> {
059
060 /**
061 * The Class of beans produced by this handler.
062 */
063 private final Class<V> type;
064
065 /**
066 * The RowProcessor implementation to use when converting rows into Objects.
067 */
068 private final RowProcessor convert;
069
070 /**
071 * The column index to retrieve key values from. Defaults to 1.
072 */
073 private final int columnIndex;
074
075 /**
076 * The column name to retrieve key values from. Either columnName or
077 * columnIndex will be used but never both.
078 */
079 private final String columnName;
080
081 /**
082 * Creates a new instance of BeanMapHandler. The value of the first column
083 * of each row will be a key in the Map.
084 *
085 * @param type
086 * The Class that objects returned from <code>createRow()</code>
087 * are created from.
088 */
089 public BeanMapHandler(Class<V> type) {
090 this(type, ArrayHandler.ROW_PROCESSOR, 1, null);
091 }
092
093 /**
094 * Creates a new instance of BeanMapHandler. The value of the first column
095 * of each row will be a key in the Map.
096 *
097 * @param type
098 * The Class that objects returned from <code>createRow()</code>
099 * are created from.
100 * @param convert
101 * The <code>RowProcessor</code> implementation to use when
102 * converting rows into Beans
103 */
104 public BeanMapHandler(Class<V> type, RowProcessor convert) {
105 this(type, convert, 1, null);
106 }
107
108 /**
109 * Creates a new instance of BeanMapHandler.
110 *
111 * @param type
112 * The Class that objects returned from <code>createRow()</code>
113 * are created from.
114 * @param columnIndex
115 * The values to use as keys in the Map are retrieved from the
116 * column at this index.
117 */
118 public BeanMapHandler(Class<V> type, int columnIndex) {
119 this(type, ArrayHandler.ROW_PROCESSOR, columnIndex, null);
120 }
121
122 /**
123 * Creates a new instance of BeanMapHandler.
124 *
125 * @param type
126 * The Class that objects returned from <code>createRow()</code>
127 * are created from.
128 * @param columnName
129 * The values to use as keys in the Map are retrieved from the
130 * column with this name.
131 */
132 public BeanMapHandler(Class<V> type, String columnName) {
133 this(type, ArrayHandler.ROW_PROCESSOR, 1, columnName);
134 }
135
136 /**
137 * Private Helper
138 *
139 * @param convert
140 * The <code>RowProcessor</code> implementation to use when
141 * converting rows into Beans
142 * @param columnIndex
143 * The values to use as keys in the Map are retrieved from the
144 * column at this index.
145 * @param columnName
146 * The values to use as keys in the Map are retrieved from the
147 * column with this name.
148 */
149 private BeanMapHandler(Class<V> type, RowProcessor convert,
150 int columnIndex, String columnName) {
151 super();
152 this.type = type;
153 this.convert = convert;
154 this.columnIndex = columnIndex;
155 this.columnName = columnName;
156 }
157
158 /**
159 * This factory method is called by <code>handle()</code> to retrieve the
160 * key value from the current <code>ResultSet</code> row.
161 * @param rs ResultSet to create a key from
162 *
163 * @return K from the configured key column name/index
164 *
165 * @throws SQLException if a database access error occurs
166 * @throws ClassCastException if the class datatype does not match the column type
167 *
168 * @see org.apache.commons.dbutils.handlers.AbstractKeyedHandler#createKey(ResultSet)
169 */
170 // We assume that the user has picked the correct type to match the column
171 // so getObject will return the appropriate type and the cast will succeed.
172 @SuppressWarnings("unchecked")
173 @Override
174 protected K createKey(ResultSet rs) throws SQLException {
175 return (columnName == null) ?
176 (K) rs.getObject(columnIndex) :
177 (K) rs.getObject(columnName);
178 }
179
180 @Override
181 protected V createRow(ResultSet rs) throws SQLException {
182 return this.convert.toBean(rs, type);
183 }
184
185 }