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