1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.ibatis.sqlmap.engine.mapping.parameter;
17
18 import com.ibatis.common.beans.Probe;
19 import com.ibatis.common.beans.ProbeFactory;
20 import com.ibatis.common.resources.Resources;
21 import com.ibatis.sqlmap.client.SqlMapException;
22 import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
23 import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
24 import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
25 import com.ibatis.sqlmap.engine.type.DomTypeMarker;
26 import com.ibatis.sqlmap.engine.type.TypeHandler;
27 import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
28
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.StringTokenizer;
32
33
34
35
36 public class InlineParameterMapParser {
37
38
39 private static final Probe PROBE = ProbeFactory.getProbe();
40
41
42 private static final String PARAMETER_TOKEN = "#";
43
44
45 private static final String PARAM_DELIM = ":";
46
47
48
49
50
51
52
53
54
55
56
57 public SqlText parseInlineParameterMap(TypeHandlerFactory typeHandlerFactory, String sqlStatement) {
58 return parseInlineParameterMap(typeHandlerFactory, sqlStatement, null);
59 }
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public SqlText parseInlineParameterMap(TypeHandlerFactory typeHandlerFactory, String sqlStatement,
74 Class parameterClass) {
75
76 String newSql = sqlStatement;
77
78 List mappingList = new ArrayList();
79
80 StringTokenizer parser = new StringTokenizer(sqlStatement, PARAMETER_TOKEN, true);
81 StringBuilder newSqlBuffer = new StringBuilder();
82
83 String token = null;
84 String lastToken = null;
85 while (parser.hasMoreTokens()) {
86 token = parser.nextToken();
87 if (PARAMETER_TOKEN.equals(lastToken)) {
88 if (PARAMETER_TOKEN.equals(token)) {
89 newSqlBuffer.append(PARAMETER_TOKEN);
90 token = null;
91 } else {
92 ParameterMapping mapping = null;
93 if (token.indexOf(PARAM_DELIM) > -1) {
94 mapping = oldParseMapping(token, parameterClass, typeHandlerFactory);
95 } else {
96 mapping = newParseMapping(token, parameterClass, typeHandlerFactory);
97 }
98
99 mappingList.add(mapping);
100 newSqlBuffer.append("?");
101 boolean hasMoreTokens = parser.hasMoreTokens();
102 if (hasMoreTokens)
103 token = parser.nextToken();
104 if (!hasMoreTokens || !PARAMETER_TOKEN.equals(token)) {
105 throw new SqlMapException(
106 "Unterminated inline parameter in mapped statement near '" + newSqlBuffer.toString() + "'");
107 }
108 token = null;
109 }
110 } else {
111 if (!PARAMETER_TOKEN.equals(token)) {
112 newSqlBuffer.append(token);
113 }
114 }
115
116 lastToken = token;
117 }
118
119 newSql = newSqlBuffer.toString();
120
121 ParameterMapping[] mappingArray = (ParameterMapping[]) mappingList
122 .toArray(new ParameterMapping[mappingList.size()]);
123
124 SqlText sqlText = new SqlText();
125 sqlText.setText(newSql);
126 sqlText.setParameterMappings(mappingArray);
127 return sqlText;
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142 private ParameterMapping newParseMapping(String token, Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
143 ParameterMapping mapping = new ParameterMapping();
144
145
146
147 StringTokenizer paramParser = new StringTokenizer(token, "=,", false);
148 mapping.setPropertyName(paramParser.nextToken());
149
150 while (paramParser.hasMoreTokens()) {
151 String field = paramParser.nextToken();
152 if (paramParser.hasMoreTokens()) {
153 String value = paramParser.nextToken();
154 if ("javaType".equals(field)) {
155 value = typeHandlerFactory.resolveAlias(value);
156 mapping.setJavaTypeName(value);
157 } else if ("jdbcType".equals(field)) {
158 mapping.setJdbcTypeName(value);
159 } else if ("mode".equals(field)) {
160 mapping.setMode(value);
161 } else if ("nullValue".equals(field)) {
162 mapping.setNullValue(value);
163 } else if ("handler".equals(field)) {
164 try {
165 value = typeHandlerFactory.resolveAlias(value);
166 Object impl = Resources.instantiate(value);
167 if (impl instanceof TypeHandlerCallback) {
168 mapping.setTypeHandler(new CustomTypeHandler((TypeHandlerCallback) impl));
169 } else if (impl instanceof TypeHandler) {
170 mapping.setTypeHandler((TypeHandler) impl);
171 } else {
172 throw new SqlMapException(
173 "The class " + value + " is not a valid implementation of TypeHandler or TypeHandlerCallback");
174 }
175 } catch (Exception e) {
176 throw new SqlMapException("Error loading class specified by handler field in " + token + ". Cause: " + e,
177 e);
178 }
179 } else if ("numericScale".equals(field)) {
180 try {
181 Integer numericScale = Integer.valueOf(value);
182 if (numericScale.intValue() < 0) {
183 throw new SqlMapException("Value specified for numericScale must be greater than or equal to zero");
184 }
185 mapping.setNumericScale(numericScale);
186 } catch (NumberFormatException e) {
187 throw new SqlMapException("Value specified for numericScale is not a valid Integer");
188 }
189 } else {
190 throw new SqlMapException("Unrecognized parameter mapping field: '" + field + "' in " + token);
191 }
192 } else {
193 throw new SqlMapException("Incorrect inline parameter map format (missmatched name=value pairs): " + token);
194 }
195 }
196
197 if (mapping.getTypeHandler() == null) {
198 TypeHandler handler;
199 if (parameterClass == null) {
200 handler = typeHandlerFactory.getUnkownTypeHandler();
201 } else {
202 handler = resolveTypeHandler(typeHandlerFactory, parameterClass, mapping.getPropertyName(),
203 mapping.getJavaTypeName(), mapping.getJdbcTypeName());
204 }
205 mapping.setTypeHandler(handler);
206 }
207
208 return mapping;
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223 private ParameterMapping oldParseMapping(String token, Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
224 ParameterMapping mapping = new ParameterMapping();
225 if (token.indexOf(PARAM_DELIM) > -1) {
226 StringTokenizer paramParser = new StringTokenizer(token, PARAM_DELIM, true);
227 int n1 = paramParser.countTokens();
228 if (n1 == 3) {
229 String name = paramParser.nextToken();
230 paramParser.nextToken();
231 String type = paramParser.nextToken();
232 mapping.setPropertyName(name);
233 mapping.setJdbcTypeName(type);
234 TypeHandler handler;
235 if (parameterClass == null) {
236 handler = typeHandlerFactory.getUnkownTypeHandler();
237 } else {
238 handler = resolveTypeHandler(typeHandlerFactory, parameterClass, name, null, type);
239 }
240 mapping.setTypeHandler(handler);
241 return mapping;
242 } else if (n1 >= 5) {
243 String name = paramParser.nextToken();
244 paramParser.nextToken();
245 String type = paramParser.nextToken();
246 paramParser.nextToken();
247 String nullValue = paramParser.nextToken();
248 while (paramParser.hasMoreTokens()) {
249 nullValue = nullValue + paramParser.nextToken();
250 }
251 mapping.setPropertyName(name);
252 mapping.setJdbcTypeName(type);
253 mapping.setNullValue(nullValue);
254 TypeHandler handler;
255 if (parameterClass == null) {
256 handler = typeHandlerFactory.getUnkownTypeHandler();
257 } else {
258 handler = resolveTypeHandler(typeHandlerFactory, parameterClass, name, null, type);
259 }
260 mapping.setTypeHandler(handler);
261 return mapping;
262 } else {
263 throw new SqlMapException("Incorrect inline parameter map format: " + token);
264 }
265 } else {
266 mapping.setPropertyName(token);
267 TypeHandler handler;
268 if (parameterClass == null) {
269 handler = typeHandlerFactory.getUnkownTypeHandler();
270 } else {
271 handler = resolveTypeHandler(typeHandlerFactory, parameterClass, token, null, null);
272 }
273 mapping.setTypeHandler(handler);
274 return mapping;
275 }
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 private TypeHandler resolveTypeHandler(TypeHandlerFactory typeHandlerFactory, Class clazz, String propertyName,
295 String javaType, String jdbcType) {
296 TypeHandler handler = null;
297 if (clazz == null) {
298
299 handler = typeHandlerFactory.getUnkownTypeHandler();
300 } else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
301
302 handler = typeHandlerFactory.getTypeHandler(String.class, jdbcType);
303 } else if (java.util.Map.class.isAssignableFrom(clazz)) {
304
305 if (javaType == null) {
306 handler = typeHandlerFactory.getUnkownTypeHandler();
307
308
309 } else {
310 try {
311 javaType = typeHandlerFactory.resolveAlias(javaType);
312 Class javaClass = Resources.classForName(javaType);
313 handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
314 } catch (Exception e) {
315 throw new SqlMapException("Error. Could not set TypeHandler. Cause: " + e, e);
316 }
317 }
318 } else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
319
320 handler = typeHandlerFactory.getTypeHandler(clazz, jdbcType);
321 } else {
322
323 if (javaType == null) {
324
325 Class type = PROBE.getPropertyTypeForGetter(clazz, propertyName);
326 handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
327
328 } else {
329 try {
330 javaType = typeHandlerFactory.resolveAlias(javaType);
331 Class javaClass = Resources.classForName(javaType);
332 handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
333 } catch (Exception e) {
334 throw new SqlMapException("Error. Could not set TypeHandler. Cause: " + e, e);
335 }
336 }
337 }
338 return handler;
339 }
340
341 }