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