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