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

mybatis / mybatis-3 / 2586

02 Jan 2025 10:54AM UTC coverage: 87.435% (-0.01%) from 87.446%
2586

push

github

web-flow
Merge pull request #3375 from epochcoder/pr/3349-revert

Revert #3349

3637 of 4407 branches covered (82.53%)

9582 of 10959 relevant lines covered (87.43%)

0.87 hits per line

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

95.87
/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java
1
/*
2
 *    Copyright 2009-2023 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.apache.ibatis.scripting.xmltags;
17

18
import java.util.ArrayList;
19
import java.util.HashMap;
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.mapping.SqlSource;
26
import org.apache.ibatis.parsing.XNode;
27
import org.apache.ibatis.scripting.defaults.RawSqlSource;
28
import org.apache.ibatis.session.Configuration;
29
import org.w3c.dom.Node;
30
import org.w3c.dom.NodeList;
31

32
/**
33
 * @author Clinton Begin
34
 */
35
public class XMLScriptBuilder extends BaseBuilder {
36

37
  private final XNode context;
38
  private boolean isDynamic;
39
  private final Class<?> parameterType;
40
  private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();
1✔
41

42
  public XMLScriptBuilder(Configuration configuration, XNode context) {
43
    this(configuration, context, null);
×
44
  }
×
45

46
  public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {
47
    super(configuration);
1✔
48
    this.context = context;
1✔
49
    this.parameterType = parameterType;
1✔
50
    initNodeHandlerMap();
1✔
51
  }
1✔
52

53
  private void initNodeHandlerMap() {
54
    nodeHandlerMap.put("trim", new TrimHandler());
1✔
55
    nodeHandlerMap.put("where", new WhereHandler());
1✔
56
    nodeHandlerMap.put("set", new SetHandler());
1✔
57
    nodeHandlerMap.put("foreach", new ForEachHandler());
1✔
58
    nodeHandlerMap.put("if", new IfHandler());
1✔
59
    nodeHandlerMap.put("choose", new ChooseHandler());
1✔
60
    nodeHandlerMap.put("when", new IfHandler());
1✔
61
    nodeHandlerMap.put("otherwise", new OtherwiseHandler());
1✔
62
    nodeHandlerMap.put("bind", new BindHandler());
1✔
63
  }
1✔
64

65
  public SqlSource parseScriptNode() {
66
    MixedSqlNode rootSqlNode = parseDynamicTags(context);
1✔
67
    SqlSource sqlSource;
68
    if (isDynamic) {
1✔
69
      sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
1✔
70
    } else {
71
      sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
1✔
72
    }
73
    return sqlSource;
1✔
74
  }
75

76
  protected MixedSqlNode parseDynamicTags(XNode node) {
77
    List<SqlNode> contents = new ArrayList<>();
1✔
78
    NodeList children = node.getNode().getChildNodes();
1✔
79
    for (int i = 0; i < children.getLength(); i++) {
1✔
80
      XNode child = node.newXNode(children.item(i));
1✔
81
      if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
1✔
82
        String data = child.getStringBody("");
1✔
83
        TextSqlNode textSqlNode = new TextSqlNode(data);
1✔
84
        if (textSqlNode.isDynamic()) {
1✔
85
          contents.add(textSqlNode);
1✔
86
          isDynamic = true;
1✔
87
        } else {
88
          contents.add(new StaticTextSqlNode(data));
1✔
89
        }
90
      } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
1!
91
        String nodeName = child.getNode().getNodeName();
1✔
92
        NodeHandler handler = nodeHandlerMap.get(nodeName);
1✔
93
        if (handler == null) {
1!
94
          throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
×
95
        }
96
        handler.handleNode(child, contents);
1✔
97
        isDynamic = true;
1✔
98
      }
99
    }
100
    return new MixedSqlNode(contents);
1✔
101
  }
102

103
  private interface NodeHandler {
104
    void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
105
  }
106

107
  private static class BindHandler implements NodeHandler {
108
    public BindHandler() {
1✔
109
      // Prevent Synthetic Access
110
    }
1✔
111

112
    @Override
113
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
114
      final String name = nodeToHandle.getStringAttribute("name");
1✔
115
      final String expression = nodeToHandle.getStringAttribute("value");
1✔
116
      final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);
1✔
117
      targetContents.add(node);
1✔
118
    }
1✔
119
  }
120

121
  private class TrimHandler implements NodeHandler {
122
    public TrimHandler() {
1✔
123
      // Prevent Synthetic Access
124
    }
1✔
125

126
    @Override
127
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
128
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
129
      String prefix = nodeToHandle.getStringAttribute("prefix");
1✔
130
      String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");
1✔
131
      String suffix = nodeToHandle.getStringAttribute("suffix");
1✔
132
      String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");
1✔
133
      TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);
1✔
134
      targetContents.add(trim);
1✔
135
    }
1✔
136
  }
137

138
  private class WhereHandler implements NodeHandler {
139
    public WhereHandler() {
1✔
140
      // Prevent Synthetic Access
141
    }
1✔
142

143
    @Override
144
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
145
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
146
      WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);
1✔
147
      targetContents.add(where);
1✔
148
    }
1✔
149
  }
150

151
  private class SetHandler implements NodeHandler {
152
    public SetHandler() {
1✔
153
      // Prevent Synthetic Access
154
    }
1✔
155

156
    @Override
157
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
158
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
159
      SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);
1✔
160
      targetContents.add(set);
1✔
161
    }
1✔
162
  }
163

164
  private class ForEachHandler implements NodeHandler {
165
    public ForEachHandler() {
1✔
166
      // Prevent Synthetic Access
167
    }
1✔
168

169
    @Override
170
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
171
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
172
      String collection = nodeToHandle.getStringAttribute("collection");
1✔
173
      Boolean nullable = nodeToHandle.getBooleanAttribute("nullable");
1✔
174
      String item = nodeToHandle.getStringAttribute("item");
1✔
175
      String index = nodeToHandle.getStringAttribute("index");
1✔
176
      String open = nodeToHandle.getStringAttribute("open");
1✔
177
      String close = nodeToHandle.getStringAttribute("close");
1✔
178
      String separator = nodeToHandle.getStringAttribute("separator");
1✔
179
      ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, nullable, index, item,
1✔
180
          open, close, separator);
181
      targetContents.add(forEachSqlNode);
1✔
182
    }
1✔
183
  }
184

185
  private class IfHandler implements NodeHandler {
186
    public IfHandler() {
1✔
187
      // Prevent Synthetic Access
188
    }
1✔
189

190
    @Override
191
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
192
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
193
      String test = nodeToHandle.getStringAttribute("test");
1✔
194
      IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
1✔
195
      targetContents.add(ifSqlNode);
1✔
196
    }
1✔
197
  }
198

199
  private class OtherwiseHandler implements NodeHandler {
200
    public OtherwiseHandler() {
1✔
201
      // Prevent Synthetic Access
202
    }
1✔
203

204
    @Override
205
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
206
      MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
1✔
207
      targetContents.add(mixedSqlNode);
1✔
208
    }
1✔
209
  }
210

211
  private class ChooseHandler implements NodeHandler {
212
    public ChooseHandler() {
1✔
213
      // Prevent Synthetic Access
214
    }
1✔
215

216
    @Override
217
    public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
218
      List<SqlNode> whenSqlNodes = new ArrayList<>();
1✔
219
      List<SqlNode> otherwiseSqlNodes = new ArrayList<>();
1✔
220
      handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
1✔
221
      SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
1✔
222
      ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);
1✔
223
      targetContents.add(chooseSqlNode);
1✔
224
    }
1✔
225

226
    private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes,
227
        List<SqlNode> defaultSqlNodes) {
228
      List<XNode> children = chooseSqlNode.getChildren();
1✔
229
      for (XNode child : children) {
1✔
230
        String nodeName = child.getNode().getNodeName();
1✔
231
        NodeHandler handler = nodeHandlerMap.get(nodeName);
1✔
232
        if (handler instanceof IfHandler) {
1✔
233
          handler.handleNode(child, ifSqlNodes);
1✔
234
        } else if (handler instanceof OtherwiseHandler) {
1!
235
          handler.handleNode(child, defaultSqlNodes);
1✔
236
        }
237
      }
1✔
238
    }
1✔
239

240
    private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
241
      SqlNode defaultSqlNode = null;
1✔
242
      if (defaultSqlNodes.size() == 1) {
1!
243
        defaultSqlNode = defaultSqlNodes.get(0);
1✔
244
      } else if (defaultSqlNodes.size() > 1) {
×
245
        throw new BuilderException("Too many default (otherwise) elements in choose statement.");
×
246
      }
247
      return defaultSqlNode;
1✔
248
    }
249
  }
250

251
}
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

© 2026 Coveralls, Inc