001/* 002 * Copyright 2002-2012 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.object; 018 019import java.sql.ResultSet; 020import java.sql.SQLException; 021import java.util.Map; 022import javax.sql.DataSource; 023 024import org.springframework.jdbc.core.RowMapper; 025 026/** 027 * Reusable RDBMS query in which concrete subclasses must implement 028 * the abstract mapRow(ResultSet, int) method to map each row of 029 * the JDBC ResultSet into an object. 030 * 031 * <p>Such manual mapping is usually preferable to "automatic" 032 * mapping using reflection, which can become complex in non-trivial 033 * cases. For example, the present class allows different objects 034 * to be used for different rows (for example, if a subclass is indicated). 035 * It allows computed fields to be set. And there's no need for 036 * ResultSet columns to have the same names as bean properties. 037 * The Pareto Principle in action: going the extra mile to automate 038 * the extraction process makes the framework much more complex 039 * and delivers little real benefit. 040 * 041 * <p>Subclasses can be constructed providing SQL, parameter types 042 * and a DataSource. SQL will often vary between subclasses. 043 * 044 * @author Rod Johnson 045 * @author Thomas Risberg 046 * @author Jean-Pierre Pawlak 047 * @see org.springframework.jdbc.object.MappingSqlQuery 048 * @see org.springframework.jdbc.object.SqlQuery 049 */ 050public abstract class MappingSqlQueryWithParameters<T> extends SqlQuery<T> { 051 052 /** 053 * Constructor to allow use as a JavaBean 054 */ 055 public MappingSqlQueryWithParameters() { 056 } 057 058 /** 059 * Convenient constructor with DataSource and SQL string. 060 * @param ds DataSource to use to get connections 061 * @param sql SQL to run 062 */ 063 public MappingSqlQueryWithParameters(DataSource ds, String sql) { 064 super(ds, sql); 065 } 066 067 068 /** 069 * Implementation of protected abstract method. This invokes the subclass's 070 * implementation of the mapRow() method. 071 */ 072 @Override 073 protected RowMapper<T> newRowMapper(Object[] parameters, Map<?, ?> context) { 074 return new RowMapperImpl(parameters, context); 075 } 076 077 /** 078 * Subclasses must implement this method to convert each row 079 * of the ResultSet into an object of the result type. 080 * @param rs ResultSet we're working through 081 * @param rowNum row number (from 0) we're up to 082 * @param parameters to the query (passed to the execute() method). 083 * Subclasses are rarely interested in these. 084 * It can be {@code null} if there are no parameters. 085 * @param context passed to the execute() method. 086 * It can be {@code null} if no contextual information is need. 087 * @return an object of the result type 088 * @throws SQLException if there's an error extracting data. 089 * Subclasses can simply not catch SQLExceptions, relying on the 090 * framework to clean up. 091 */ 092 protected abstract T mapRow(ResultSet rs, int rowNum, Object[] parameters, Map<?, ?> context) 093 throws SQLException; 094 095 096 /** 097 * Implementation of RowMapper that calls the enclosing 098 * class's {@code mapRow} method for each row. 099 */ 100 protected class RowMapperImpl implements RowMapper<T> { 101 102 private final Object[] params; 103 104 private final Map<?, ?> context; 105 106 /** 107 * Use an array results. More efficient if we know how many results to expect. 108 */ 109 public RowMapperImpl(Object[] parameters, Map<?, ?> context) { 110 this.params = parameters; 111 this.context = context; 112 } 113 114 @Override 115 public T mapRow(ResultSet rs, int rowNum) throws SQLException { 116 return MappingSqlQueryWithParameters.this.mapRow(rs, rowNum, this.params, this.context); 117 } 118 } 119 120}