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 */ 017package org.apache.commons.dbutils.handlers; 018 019import java.sql.ResultSet; 020import java.sql.SQLException; 021 022import org.apache.commons.dbutils.RowProcessor; 023 024/** 025 * <p> 026 * {@code ResultSetHandler} implementation that returns a Map of Beans. 027 * {@code ResultSet} 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 BeanMapHandler<Long, Person>(Person.class, "id"); 036 * Map<Long, 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 */ 058public 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()} 087 * are created from. 088 */ 089 public BeanMapHandler(final 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()} 099 * are created from. 100 * @param convert 101 * The {@code RowProcessor} implementation to use when 102 * converting rows into Beans 103 */ 104 public BeanMapHandler(final Class<V> type, final 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()} 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(final Class<V> type, final 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()} 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(final Class<V> type, final String columnName) { 133 this(type, ArrayHandler.ROW_PROCESSOR, 1, columnName); 134 } 135 136 /** 137 * Private Helper 138 * 139 * @param convert 140 * The {@code RowProcessor} 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(final Class<V> type, final RowProcessor convert, 150 final int columnIndex, final 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()} to retrieve the 160 * key value from the current {@code ResultSet} 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(final 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(final ResultSet rs) throws SQLException { 182 return this.convert.toBean(rs, type); 183 } 184 185}