1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.builder;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Map;
21
22 import org.apache.ibatis.mapping.ParameterMapping;
23 import org.apache.ibatis.mapping.SqlSource;
24 import org.apache.ibatis.parsing.GenericTokenParser;
25 import org.apache.ibatis.parsing.TokenHandler;
26 import org.apache.ibatis.reflection.MetaClass;
27 import org.apache.ibatis.reflection.MetaObject;
28 import org.apache.ibatis.session.Configuration;
29 import org.apache.ibatis.type.JdbcType;
30
31
32
33
34 public class SqlSourceBuilder extends BaseBuilder {
35
36 private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";
37
38 public SqlSourceBuilder(Configuration configuration) {
39 super(configuration);
40 }
41
42 public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
43 ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
44 GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
45 String sql = parser.parse(originalSql);
46 return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
47 }
48
49 private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
50
51 private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
52 private Class<?> parameterType;
53 private MetaObject metaParameters;
54
55 public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
56 super(configuration);
57 this.parameterType = parameterType;
58 this.metaParameters = configuration.newMetaObject(additionalParameters);
59 }
60
61 public List<ParameterMapping> getParameterMappings() {
62 return parameterMappings;
63 }
64
65 @Override
66 public String handleToken(String content) {
67 parameterMappings.add(buildParameterMapping(content));
68 return "?";
69 }
70
71 private ParameterMapping buildParameterMapping(String content) {
72 Map<String, String> propertiesMap = parseParameterMapping(content);
73 String property = propertiesMap.get("property");
74 Class<?> propertyType;
75 if (metaParameters.hasGetter(property)) {
76 propertyType = metaParameters.getGetterType(property);
77 } else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
78 propertyType = parameterType;
79 } else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
80 propertyType = java.sql.ResultSet.class;
81 } else if (property != null) {
82 MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
83 if (metaClass.hasGetter(property)) {
84 propertyType = metaClass.getGetterType(property);
85 } else {
86 propertyType = Object.class;
87 }
88 } else {
89 propertyType = Object.class;
90 }
91 ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
92 Class<?> javaType = propertyType;
93 String typeHandlerAlias = null;
94 for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
95 String name = entry.getKey();
96 String value = entry.getValue();
97 if ("javaType".equals(name)) {
98 javaType = resolveClass(value);
99 builder.javaType(javaType);
100 } else if ("jdbcType".equals(name)) {
101 builder.jdbcType(resolveJdbcType(value));
102 } else if ("mode".equals(name)) {
103 builder.mode(resolveParameterMode(value));
104 } else if ("numericScale".equals(name)) {
105 builder.numericScale(Integer.valueOf(value));
106 } else if ("resultMap".equals(name)) {
107 builder.resultMapId(value);
108 } else if ("typeHandler".equals(name)) {
109 typeHandlerAlias = value;
110 } else if ("jdbcTypeName".equals(name)) {
111 builder.jdbcTypeName(value);
112 } else if ("property".equals(name)) {
113
114 } else if ("expression".equals(name)) {
115 throw new BuilderException("Expression based parameters are not supported yet");
116 } else {
117 throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties);
118 }
119 }
120 if (typeHandlerAlias != null) {
121 builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
122 }
123 return builder.build();
124 }
125
126 private Map<String, String> parseParameterMapping(String content) {
127 try {
128 return new ParameterExpression(content);
129 } catch (BuilderException ex) {
130 throw ex;
131 } catch (Exception ex) {
132 throw new BuilderException("Parsing error was found in mapping #{" + content + "}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
133 }
134 }
135 }
136
137 }