001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.jdbc.core; 018 019import java.sql.ResultSet; 020import java.sql.ResultSetMetaData; 021import java.sql.SQLException; 022import java.util.Map; 023 024import org.springframework.jdbc.support.JdbcUtils; 025import org.springframework.util.LinkedCaseInsensitiveMap; 026 027/** 028 * {@link RowMapper} implementation that creates a {@code java.util.Map} 029 * for each row, representing all columns as key-value pairs: one 030 * entry for each column, with the column name as key. 031 * 032 * <p>The Map implementation to use and the key to use for each column 033 * in the column Map can be customized through overriding 034 * {@link #createColumnMap} and {@link #getColumnKey}, respectively. 035 * 036 * <p><b>Note:</b> By default, ColumnMapRowMapper will try to build a linked Map 037 * with case-insensitive keys, to preserve column order as well as allow any 038 * casing to be used for column names. This requires Commons Collections on the 039 * classpath (which will be autodetected). Else, the fallback is a standard linked 040 * HashMap, which will still preserve column order but requires the application 041 * to specify the column names in the same casing as exposed by the driver. 042 * 043 * @author Juergen Hoeller 044 * @since 1.2 045 * @see JdbcTemplate#queryForList(String) 046 * @see JdbcTemplate#queryForMap(String) 047 */ 048public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> { 049 050 @Override 051 public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException { 052 ResultSetMetaData rsmd = rs.getMetaData(); 053 int columnCount = rsmd.getColumnCount(); 054 Map<String, Object> mapOfColumnValues = createColumnMap(columnCount); 055 for (int i = 1; i <= columnCount; i++) { 056 String column = JdbcUtils.lookupColumnName(rsmd, i); 057 mapOfColumnValues.put(getColumnKey(column), getColumnValue(rs, i)); 058 } 059 return mapOfColumnValues; 060 } 061 062 /** 063 * Create a Map instance to be used as column map. 064 * <p>By default, a linked case-insensitive Map will be created. 065 * @param columnCount the column count, to be used as initial 066 * capacity for the Map 067 * @return the new Map instance 068 * @see org.springframework.util.LinkedCaseInsensitiveMap 069 */ 070 protected Map<String, Object> createColumnMap(int columnCount) { 071 return new LinkedCaseInsensitiveMap<Object>(columnCount); 072 } 073 074 /** 075 * Determine the key to use for the given column in the column Map. 076 * @param columnName the column name as returned by the ResultSet 077 * @return the column key to use 078 * @see java.sql.ResultSetMetaData#getColumnName 079 */ 080 protected String getColumnKey(String columnName) { 081 return columnName; 082 } 083 084 /** 085 * Retrieve a JDBC object value for the specified column. 086 * <p>The default implementation uses the {@code getObject} method. 087 * Additionally, this implementation includes a "hack" to get around Oracle 088 * returning a non standard object for their TIMESTAMP datatype. 089 * @param rs is the ResultSet holding the data 090 * @param index is the column index 091 * @return the Object returned 092 * @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue 093 */ 094 protected Object getColumnValue(ResultSet rs, int index) throws SQLException { 095 return JdbcUtils.getResultSetValue(rs, index); 096 } 097 098}