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.lang.Nullable; 026import org.springframework.util.LinkedCaseInsensitiveMap; 027 028/** 029 * {@link RowMapper} implementation that creates a {@code java.util.Map} 030 * for each row, representing all columns as key-value pairs: one 031 * entry for each column, with the column name as key. 032 * 033 * <p>The Map implementation to use and the key to use for each column 034 * in the column Map can be customized through overriding 035 * {@link #createColumnMap} and {@link #getColumnKey}, respectively. 036 * 037 * <p><b>Note:</b> By default, ColumnMapRowMapper will try to build a linked Map 038 * with case-insensitive keys, to preserve column order as well as allow any 039 * casing to be used for column names. This requires Commons Collections on the 040 * classpath (which will be autodetected). Else, the fallback is a standard linked 041 * HashMap, which will still preserve column order but requires the application 042 * to specify the column names in the same casing as exposed by the driver. 043 * 044 * @author Juergen Hoeller 045 * @since 1.2 046 * @see JdbcTemplate#queryForList(String) 047 * @see JdbcTemplate#queryForMap(String) 048 */ 049public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> { 050 051 @Override 052 public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException { 053 ResultSetMetaData rsmd = rs.getMetaData(); 054 int columnCount = rsmd.getColumnCount(); 055 Map<String, Object> mapOfColumnValues = createColumnMap(columnCount); 056 for (int i = 1; i <= columnCount; i++) { 057 String column = JdbcUtils.lookupColumnName(rsmd, i); 058 mapOfColumnValues.putIfAbsent(getColumnKey(column), getColumnValue(rs, i)); 059 } 060 return mapOfColumnValues; 061 } 062 063 /** 064 * Create a Map instance to be used as column map. 065 * <p>By default, a linked case-insensitive Map will be created. 066 * @param columnCount the column count, to be used as initial 067 * capacity for the Map 068 * @return the new Map instance 069 * @see org.springframework.util.LinkedCaseInsensitiveMap 070 */ 071 protected Map<String, Object> createColumnMap(int columnCount) { 072 return new LinkedCaseInsensitiveMap<>(columnCount); 073 } 074 075 /** 076 * Determine the key to use for the given column in the column Map. 077 * @param columnName the column name as returned by the ResultSet 078 * @return the column key to use 079 * @see java.sql.ResultSetMetaData#getColumnName 080 */ 081 protected String getColumnKey(String columnName) { 082 return columnName; 083 } 084 085 /** 086 * Retrieve a JDBC object value for the specified column. 087 * <p>The default implementation uses the {@code getObject} method. 088 * Additionally, this implementation includes a "hack" to get around Oracle 089 * returning a non standard object for their TIMESTAMP datatype. 090 * @param rs is the ResultSet holding the data 091 * @param index is the column index 092 * @return the Object returned 093 * @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue 094 */ 095 @Nullable 096 protected Object getColumnValue(ResultSet rs, int index) throws SQLException { 097 return JdbcUtils.getResultSetValue(rs, index); 098 } 099 100}