1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.scripting.freemarker;
17
18 import java.io.CharArrayWriter;
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.apache.ibatis.builder.SqlSourceBuilder;
26 import org.apache.ibatis.mapping.BoundSql;
27 import org.apache.ibatis.mapping.SqlSource;
28 import org.apache.ibatis.session.Configuration;
29
30 import freemarker.template.SimpleScalar;
31 import freemarker.template.Template;
32 import freemarker.template.TemplateException;
33 import freemarker.template.Version;
34
35
36
37
38
39
40
41 public class FreeMarkerSqlSource implements SqlSource {
42 private final Template template;
43 private final Configuration configuration;
44 private final Version incompatibleImprovementsVersion;
45 private final String databaseId;
46
47 public static final String GENERATED_PARAMS_KEY = "__GENERATED__";
48
49 public FreeMarkerSqlSource(Template template, Configuration configuration, Version incompatibleImprovementsVersion) {
50 this.template = template;
51 this.configuration = configuration;
52 this.incompatibleImprovementsVersion = incompatibleImprovementsVersion;
53 this.databaseId = configuration.getDatabaseId();
54 }
55
56
57
58
59
60 protected Object preProcessDataContext(Object dataContext, boolean isMap) {
61 if (isMap) {
62 ((Map<String, Object>) dataContext).put(MyBatisParamDirective.DEFAULT_KEY, new MyBatisParamDirective());
63 ((Map<String, Object>) dataContext).put(MyBatisParamDirective.DATABASE_ID_KEY, new SimpleScalar(this.databaseId));
64 } else {
65 ((ParamObjectAdapter) dataContext).putAdditionalParam(MyBatisParamDirective.DEFAULT_KEY,
66 new MyBatisParamDirective());
67 ((ParamObjectAdapter) dataContext).putAdditionalParam(MyBatisParamDirective.DATABASE_ID_KEY,
68 new SimpleScalar(this.databaseId));
69 }
70 return dataContext;
71 }
72
73 @Override
74 public BoundSql getBoundSql(Object parameterObject) {
75
76
77 Object dataContext;
78 List generatedParams = new ArrayList<>();
79 if (parameterObject != null) {
80 if (parameterObject instanceof Map) {
81 HashMap<String, Object> map = new HashMap<>((Map<String, Object>) parameterObject);
82 map.put(GENERATED_PARAMS_KEY, generatedParams);
83 dataContext = preProcessDataContext(map, true);
84 } else {
85 ParamObjectAdapter adapter = new ParamObjectAdapter(parameterObject, generatedParams,
86 incompatibleImprovementsVersion);
87 dataContext = preProcessDataContext(adapter, false);
88 }
89 } else {
90 HashMap<Object, Object> map = new HashMap<>();
91 map.put(GENERATED_PARAMS_KEY, generatedParams);
92 dataContext = preProcessDataContext(map, true);
93 }
94
95 CharArrayWriter writer = new CharArrayWriter();
96 try {
97 template.process(dataContext, writer);
98 } catch (TemplateException | IOException e) {
99 throw new RuntimeException(e);
100 }
101
102
103
104
105 String sql = writer.toString();
106
107 if (!generatedParams.isEmpty()) {
108 if (!(parameterObject instanceof Map)) {
109 throw new UnsupportedOperationException("Auto-generated prepared statements parameters"
110 + " are not available if using parameters object. Use @Param-annotated parameters" + " instead.");
111 }
112
113 Map<String, Object> parametersMap = (Map<String, Object>) parameterObject;
114 for (int i = 0; i < generatedParams.size(); i++) {
115 parametersMap.put("_p" + i, generatedParams.get(i));
116 }
117 }
118
119
120 SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
121 Class<?> parameterType1 = parameterObject == null ? Object.class : parameterObject.getClass();
122 SqlSource sqlSource = sqlSourceParser.parse(sql, parameterType1, new HashMap<>());
123 return sqlSource.getBoundSql(parameterObject);
124 }
125 }