• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / freemarker-scripting / #281

pending completion
#281

Pull #150

github

web-flow
Merge 3411c6de0 into 9185d6a44
Pull Request #150: Update dependency org.mybatis:mybatis-parent to v38

243 of 260 relevant lines covered (93.46%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/src/main/java/org/mybatis/scripting/freemarker/FreeMarkerSqlSource.java
1
/*
2
 *    Copyright 2015-2022 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
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.Template;
30
import freemarker.template.TemplateException;
31
import freemarker.template.Version;
32

33
/**
34
 * Applies provided parameter(s) to FreeMarker template. Then passes the result into default MyBatis engine (and it
35
 * finally replaces #{}-params to '?'-params). So, FreeMarker is used as preprocessor for MyBatis engine.
36
 *
37
 * @author elwood
38
 */
39
public class FreeMarkerSqlSource implements SqlSource {
40
  private final Template template;
41
  private final Configuration configuration;
42
  private final Version incompatibleImprovementsVersion;
43

44
  public static final String GENERATED_PARAMS_KEY = "__GENERATED__";
45

46
  public FreeMarkerSqlSource(Template template, Configuration configuration, Version incompatibleImprovementsVersion) {
47
    this.template = template;
48
    this.configuration = configuration;
49
    this.incompatibleImprovementsVersion = incompatibleImprovementsVersion;
50
  }
51

52
  /**
53
   * Populates additional parameters to data context. Data context can be {@link java.util.Map} or
54
   * {@link org.mybatis.scripting.freemarker.ParamObjectAdapter} instance.
55
   */
56
  protected Object preProcessDataContext(Object dataContext, boolean isMap) {
57
    if (isMap) {
58
      ((Map<String, Object>) dataContext).put(MyBatisParamDirective.DEFAULT_KEY, new MyBatisParamDirective());
59
    } else {
60
      ((ParamObjectAdapter) dataContext).putAdditionalParam(MyBatisParamDirective.DEFAULT_KEY,
61
          new MyBatisParamDirective());
62
    }
63
    return dataContext;
64
  }
65

66
  @Override
67
  public BoundSql getBoundSql(Object parameterObject) {
68
    // Add to passed parameterObject our predefined directive - MyBatisParamDirective
69
    // It will be available as "p" inside templates
70
    Object dataContext;
71
    ArrayList generatedParams = new ArrayList<>();
72
    if (parameterObject != null) {
73
      if (parameterObject instanceof Map) {
74
        HashMap<String, Object> map = new HashMap<>((Map<String, Object>) parameterObject);
75
        map.put(GENERATED_PARAMS_KEY, generatedParams);
76
        dataContext = preProcessDataContext(map, true);
77
      } else {
78
        ParamObjectAdapter adapter = new ParamObjectAdapter(parameterObject, generatedParams,
79
            incompatibleImprovementsVersion);
80
        dataContext = preProcessDataContext(adapter, false);
81
      }
82
    } else {
83
      HashMap<Object, Object> map = new HashMap<>();
84
      map.put(GENERATED_PARAMS_KEY, generatedParams);
85
      dataContext = preProcessDataContext(map, true);
86
    }
87

88
    CharArrayWriter writer = new CharArrayWriter();
89
    try {
90
      template.process(dataContext, writer);
91
    } catch (TemplateException | IOException e) {
92
      throw new RuntimeException(e);
93
    }
94

95
    // We got SQL ready for MyBatis here. This SQL contains
96
    // params declarations like "#{param}",
97
    // they will be replaced to '?' by MyBatis engine further
98
    String sql = writer.toString();
99

100
    if (!generatedParams.isEmpty()) {
101
      if (!(parameterObject instanceof Map)) {
102
        throw new UnsupportedOperationException("Auto-generated prepared statements parameters"
103
            + " are not available if using parameters object. Use @Param-annotated parameters" + " instead.");
104
      }
105

106
      Map<String, Object> parametersMap = (Map<String, Object>) parameterObject;
107
      for (int i = 0; i < generatedParams.size(); i++) {
108
        parametersMap.put("_p" + i, generatedParams.get(i));
109
      }
110
    }
111

112
    // Pass retrieved SQL into MyBatis engine, it will substitute prepared-statements parameters
113
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
114
    Class<?> parameterType1 = parameterObject == null ? Object.class : parameterObject.getClass();
115
    SqlSource sqlSource = sqlSourceParser.parse(sql, parameterType1, new HashMap<String, Object>());
116
    return sqlSource.getBoundSql(parameterObject);
117
  }
118
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc