BeanMapHandler.java

  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. import java.sql.ResultSet;
  19. import java.sql.SQLException;

  20. import org.apache.commons.dbutils.RowProcessor;

  21. /**
  22.  * <p>
  23.  * {@code ResultSetHandler} implementation that returns a Map of Beans.
  24.  * {@code ResultSet} rows are converted into Beans which are then stored in
  25.  * a Map under the given key.
  26.  * </p>
  27.  * <p>
  28.  * If you had a Person table with a primary key column called ID, you could
  29.  * retrieve rows from the table like this:
  30.  *
  31.  * <pre>
  32.  * ResultSetHandler&lt;Map&lt;Long, Person&gt;&gt; h = new BeanMapHandler&lt;Long, Person&gt;(Person.class, &quot;id&quot;);
  33.  * Map&lt;Long, Person&gt; found = queryRunner.query(&quot;select id, name, age from person&quot;, h);
  34.  * Person jane = found.get(1L); // jane's id is 1
  35.  * String janesName = jane.getName();
  36.  * Integer janesAge = jane.getAge();
  37.  * </pre>
  38.  *
  39.  * Note that the "id" passed to BeanMapHandler can be in any case. The data type
  40.  * returned for id is dependent upon how your JDBC driver converts SQL column
  41.  * types from the Person table into Java types. The "name" and "age" columns are
  42.  * converted according to their property descriptors by DbUtils.
  43.  * &lt;/p&gt;
  44.  * <p>
  45.  * This class is thread safe.
  46.  * &lt;/p&gt;
  47.  *
  48.  * @param <K>
  49.  *            the type of keys maintained by the returned map
  50.  * @param <V>
  51.  *            the type of the bean
  52.  * @see org.apache.commons.dbutils.ResultSetHandler
  53.  * @since 1.5
  54.  */
  55. public class BeanMapHandler<K, V> extends AbstractKeyedHandler<K, V> {

  56.     /**
  57.      * The Class of beans produced by this handler.
  58.      */
  59.     private final Class<V> type;

  60.     /**
  61.      * The RowProcessor implementation to use when converting rows into Objects.
  62.      */
  63.     private final RowProcessor convert;

  64.     /**
  65.      * The column index to retrieve key values from. Defaults to 1.
  66.      */
  67.     private final int columnIndex;

  68.     /**
  69.      * The column name to retrieve key values from. Either columnName or
  70.      * columnIndex will be used but never both.
  71.      */
  72.     private final String columnName;

  73.     /**
  74.      * Creates a new instance of BeanMapHandler. The value of the first column
  75.      * of each row will be a key in the Map.
  76.      *
  77.      * @param type
  78.      *            The Class that objects returned from {@code createRow()}
  79.      *            are created from.
  80.      */
  81.     public BeanMapHandler(final Class<V> type) {
  82.         this(type, ArrayHandler.ROW_PROCESSOR, 1, null);
  83.     }

  84.     /**
  85.      * Creates a new instance of BeanMapHandler.
  86.      *
  87.      * @param type
  88.      *            The Class that objects returned from {@code createRow()}
  89.      *            are created from.
  90.      * @param columnIndex
  91.      *            The values to use as keys in the Map are retrieved from the
  92.      *            column at this index.
  93.      */
  94.     public BeanMapHandler(final Class<V> type, final int columnIndex) {
  95.         this(type, ArrayHandler.ROW_PROCESSOR, columnIndex, null);
  96.     }

  97.     /**
  98.      * Creates a new instance of BeanMapHandler. The value of the first column
  99.      * of each row will be a key in the Map.
  100.      *
  101.      * @param type
  102.      *            The Class that objects returned from {@code createRow()}
  103.      *            are created from.
  104.      * @param convert
  105.      *            The {@code RowProcessor} implementation to use when
  106.      *            converting rows into Beans
  107.      */
  108.     public BeanMapHandler(final Class<V> type, final RowProcessor convert) {
  109.         this(type, convert, 1, null);
  110.     }

  111.     /**
  112.      * Private Helper
  113.      *
  114.      * @param convert
  115.      *            The {@code RowProcessor} implementation to use when
  116.      *            converting rows into Beans
  117.      * @param columnIndex
  118.      *            The values to use as keys in the Map are retrieved from the
  119.      *            column at this index.
  120.      * @param columnName
  121.      *            The values to use as keys in the Map are retrieved from the
  122.      *            column with this name.
  123.      */
  124.     private BeanMapHandler(final Class<V> type, final RowProcessor convert,
  125.             final int columnIndex, final String columnName) {
  126.         this.type = type;
  127.         this.convert = convert;
  128.         this.columnIndex = columnIndex;
  129.         this.columnName = columnName;
  130.     }

  131.     /**
  132.      * Creates a new instance of BeanMapHandler.
  133.      *
  134.      * @param type
  135.      *            The Class that objects returned from {@code createRow()}
  136.      *            are created from.
  137.      * @param columnName
  138.      *            The values to use as keys in the Map are retrieved from the
  139.      *            column with this name.
  140.      */
  141.     public BeanMapHandler(final Class<V> type, final String columnName) {
  142.         this(type, ArrayHandler.ROW_PROCESSOR, 1, columnName);
  143.     }

  144.     /**
  145.      * This factory method is called by {@code handle()} to retrieve the
  146.      * key value from the current {@code ResultSet} row.
  147.      * @param resultSet ResultSet to create a key from
  148.      *
  149.      * @return K from the configured key column name/index
  150.      *
  151.      * @throws SQLException if a database access error occurs
  152.      * @throws ClassCastException if the class datatype does not match the column type
  153.      *
  154.      * @see org.apache.commons.dbutils.handlers.AbstractKeyedHandler#createKey(ResultSet)
  155.      */
  156.     // We assume that the user has picked the correct type to match the column
  157.     // so getObject will return the appropriate type and the cast will succeed.
  158.     @SuppressWarnings("unchecked")
  159.     @Override
  160.     protected K createKey(final ResultSet resultSet) throws SQLException {
  161.         return columnName == null ?
  162.                (K) resultSet.getObject(columnIndex) :
  163.                (K) resultSet.getObject(columnName);
  164.     }

  165.     @Override
  166.     protected V createRow(final ResultSet resultSet) throws SQLException {
  167.         return this.convert.toBean(resultSet, type);
  168.     }

  169. }