001/* 002 * Copyright 2002-2019 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.namedparam; 018 019import java.util.Collections; 020import java.util.LinkedHashMap; 021import java.util.Map; 022 023import org.springframework.jdbc.core.SqlParameterValue; 024import org.springframework.lang.NonNull; 025import org.springframework.lang.Nullable; 026import org.springframework.util.Assert; 027import org.springframework.util.StringUtils; 028 029/** 030 * {@link SqlParameterSource} implementation that holds a given Map of parameters. 031 * 032 * <p>This class is intended for passing in a simple Map of parameter values 033 * to the methods of the {@link NamedParameterJdbcTemplate} class. 034 * 035 * <p>The {@code addValue} methods on this class will make adding several values 036 * easier. The methods return a reference to the {@link MapSqlParameterSource} 037 * itself, so you can chain several method calls together within a single statement. 038 * 039 * @author Thomas Risberg 040 * @author Juergen Hoeller 041 * @since 2.0 042 * @see #addValue(String, Object) 043 * @see #addValue(String, Object, int) 044 * @see #registerSqlType 045 * @see NamedParameterJdbcTemplate 046 */ 047public class MapSqlParameterSource extends AbstractSqlParameterSource { 048 049 private final Map<String, Object> values = new LinkedHashMap<>(); 050 051 052 /** 053 * Create an empty MapSqlParameterSource, 054 * with values to be added via {@code addValue}. 055 * @see #addValue(String, Object) 056 */ 057 public MapSqlParameterSource() { 058 } 059 060 /** 061 * Create a new MapSqlParameterSource, with one value 062 * comprised of the supplied arguments. 063 * @param paramName the name of the parameter 064 * @param value the value of the parameter 065 * @see #addValue(String, Object) 066 */ 067 public MapSqlParameterSource(String paramName, @Nullable Object value) { 068 addValue(paramName, value); 069 } 070 071 /** 072 * Create a new MapSqlParameterSource based on a Map. 073 * @param values a Map holding existing parameter values (can be {@code null}) 074 */ 075 public MapSqlParameterSource(@Nullable Map<String, ?> values) { 076 addValues(values); 077 } 078 079 080 /** 081 * Add a parameter to this parameter source. 082 * @param paramName the name of the parameter 083 * @param value the value of the parameter 084 * @return a reference to this parameter source, 085 * so it's possible to chain several calls together 086 */ 087 public MapSqlParameterSource addValue(String paramName, @Nullable Object value) { 088 Assert.notNull(paramName, "Parameter name must not be null"); 089 this.values.put(paramName, value); 090 if (value instanceof SqlParameterValue) { 091 registerSqlType(paramName, ((SqlParameterValue) value).getSqlType()); 092 } 093 return this; 094 } 095 096 /** 097 * Add a parameter to this parameter source. 098 * @param paramName the name of the parameter 099 * @param value the value of the parameter 100 * @param sqlType the SQL type of the parameter 101 * @return a reference to this parameter source, 102 * so it's possible to chain several calls together 103 */ 104 public MapSqlParameterSource addValue(String paramName, @Nullable Object value, int sqlType) { 105 Assert.notNull(paramName, "Parameter name must not be null"); 106 this.values.put(paramName, value); 107 registerSqlType(paramName, sqlType); 108 return this; 109 } 110 111 /** 112 * Add a parameter to this parameter source. 113 * @param paramName the name of the parameter 114 * @param value the value of the parameter 115 * @param sqlType the SQL type of the parameter 116 * @param typeName the type name of the parameter 117 * @return a reference to this parameter source, 118 * so it's possible to chain several calls together 119 */ 120 public MapSqlParameterSource addValue(String paramName, @Nullable Object value, int sqlType, String typeName) { 121 Assert.notNull(paramName, "Parameter name must not be null"); 122 this.values.put(paramName, value); 123 registerSqlType(paramName, sqlType); 124 registerTypeName(paramName, typeName); 125 return this; 126 } 127 128 /** 129 * Add a Map of parameters to this parameter source. 130 * @param values a Map holding existing parameter values (can be {@code null}) 131 * @return a reference to this parameter source, 132 * so it's possible to chain several calls together 133 */ 134 public MapSqlParameterSource addValues(@Nullable Map<String, ?> values) { 135 if (values != null) { 136 values.forEach((key, value) -> { 137 this.values.put(key, value); 138 if (value instanceof SqlParameterValue) { 139 registerSqlType(key, ((SqlParameterValue) value).getSqlType()); 140 } 141 }); 142 } 143 return this; 144 } 145 146 /** 147 * Expose the current parameter values as read-only Map. 148 */ 149 public Map<String, Object> getValues() { 150 return Collections.unmodifiableMap(this.values); 151 } 152 153 154 @Override 155 public boolean hasValue(String paramName) { 156 return this.values.containsKey(paramName); 157 } 158 159 @Override 160 @Nullable 161 public Object getValue(String paramName) { 162 if (!hasValue(paramName)) { 163 throw new IllegalArgumentException("No value registered for key '" + paramName + "'"); 164 } 165 return this.values.get(paramName); 166 } 167 168 @Override 169 @NonNull 170 public String[] getParameterNames() { 171 return StringUtils.toStringArray(this.values.keySet()); 172 } 173 174}