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