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.object; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import javax.sql.DataSource; 023 024import org.springframework.dao.DataAccessException; 025import org.springframework.dao.InvalidDataAccessApiUsageException; 026import org.springframework.jdbc.core.JdbcTemplate; 027import org.springframework.jdbc.core.ParameterMapper; 028import org.springframework.jdbc.core.SqlParameter; 029 030/** 031 * Superclass for object abstractions of RDBMS stored procedures. 032 * This class is abstract and it is intended that subclasses will provide a typed 033 * method for invocation that delegates to the supplied {@link #execute} method. 034 * 035 * <p>The inherited {@link #setSql sql} property is the name of the stored procedure 036 * in the RDBMS. 037 * 038 * @author Rod Johnson 039 * @author Thomas Risberg 040 */ 041public abstract class StoredProcedure extends SqlCall { 042 043 /** 044 * Allow use as a bean. 045 */ 046 protected StoredProcedure() { 047 } 048 049 /** 050 * Create a new object wrapper for a stored procedure. 051 * @param ds the DataSource to use throughout the lifetime 052 * of this object to obtain connections 053 * @param name the name of the stored procedure in the database 054 */ 055 protected StoredProcedure(DataSource ds, String name) { 056 setDataSource(ds); 057 setSql(name); 058 } 059 060 /** 061 * Create a new object wrapper for a stored procedure. 062 * @param jdbcTemplate the JdbcTemplate which wraps DataSource 063 * @param name the name of the stored procedure in the database 064 */ 065 protected StoredProcedure(JdbcTemplate jdbcTemplate, String name) { 066 setJdbcTemplate(jdbcTemplate); 067 setSql(name); 068 } 069 070 071 /** 072 * StoredProcedure parameter Maps are by default allowed to contain 073 * additional entries that are not actually used as parameters. 074 */ 075 @Override 076 protected boolean allowsUnusedParameters() { 077 return true; 078 } 079 080 /** 081 * Declare a parameter. 082 * <p>Parameters declared as {@code SqlParameter} and {@code SqlInOutParameter} 083 * will always be used to provide input values. In addition to this, any parameter declared 084 * as {@code SqlOutParameter} where a non-null input value is provided will also be used 085 * as an input parameter. 086 * <b>Note: Calls to declareParameter must be made in the same order as 087 * they appear in the database's stored procedure parameter list.</b> 088 * <p>Names are purely used to help mapping. 089 * @param param the parameter object 090 */ 091 @Override 092 public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException { 093 if (param.getName() == null) { 094 throw new InvalidDataAccessApiUsageException("Parameters to stored procedures must have names as well as types"); 095 } 096 super.declareParameter(param); 097 } 098 099 /** 100 * Execute the stored procedure with the provided parameter values. This is 101 * a convenience method where the order of the passed in parameter values 102 * must match the order that the parameters where declared in. 103 * @param inParams variable number of input parameters. Output parameters should 104 * not be included in this map. It is legal for values to be {@code null}, and this 105 * will produce the correct behavior using a NULL argument to the stored procedure. 106 * @return map of output params, keyed by name as in parameter declarations. 107 * Output parameters will appear here, with their values after the stored procedure 108 * has been called. 109 */ 110 public Map<String, Object> execute(Object... inParams) { 111 Map<String, Object> paramsToUse = new HashMap<>(); 112 validateParameters(inParams); 113 int i = 0; 114 for (SqlParameter sqlParameter : getDeclaredParameters()) { 115 if (sqlParameter.isInputValueProvided() && i < inParams.length) { 116 paramsToUse.put(sqlParameter.getName(), inParams[i++]); 117 } 118 } 119 return getJdbcTemplate().call(newCallableStatementCreator(paramsToUse), getDeclaredParameters()); 120 } 121 122 /** 123 * Execute the stored procedure. Subclasses should define a strongly typed 124 * execute method (with a meaningful name) that invokes this method, populating 125 * the input map and extracting typed values from the output map. Subclass 126 * execute methods will often take domain objects as arguments and return values. 127 * Alternatively, they can return void. 128 * @param inParams map of input parameters, keyed by name as in parameter 129 * declarations. Output parameters need not (but can) be included in this map. 130 * It is legal for map entries to be {@code null}, and this will produce the 131 * correct behavior using a NULL argument to the stored procedure. 132 * @return map of output params, keyed by name as in parameter declarations. 133 * Output parameters will appear here, with their values after the 134 * stored procedure has been called. 135 */ 136 public Map<String, Object> execute(Map<String, ?> inParams) throws DataAccessException { 137 validateParameters(inParams.values().toArray()); 138 return getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters()); 139 } 140 141 /** 142 * Execute the stored procedure. Subclasses should define a strongly typed 143 * execute method (with a meaningful name) that invokes this method, passing in 144 * a ParameterMapper that will populate the input map. This allows mapping database 145 * specific features since the ParameterMapper has access to the Connection object. 146 * The execute method is also responsible for extracting typed values from the output map. 147 * Subclass execute methods will often take domain objects as arguments and return values. 148 * Alternatively, they can return void. 149 * @param inParamMapper map of input parameters, keyed by name as in parameter 150 * declarations. Output parameters need not (but can) be included in this map. 151 * It is legal for map entries to be {@code null}, and this will produce the correct 152 * behavior using a NULL argument to the stored procedure. 153 * @return map of output params, keyed by name as in parameter declarations. 154 * Output parameters will appear here, with their values after the 155 * stored procedure has been called. 156 */ 157 public Map<String, Object> execute(ParameterMapper inParamMapper) throws DataAccessException { 158 checkCompiled(); 159 return getJdbcTemplate().call(newCallableStatementCreator(inParamMapper), getDeclaredParameters()); 160 } 161 162}