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

mybatis / ibatis-2 / 749

03 Jan 2026 10:40PM UTC coverage: 65.533% (-0.06%) from 65.595%
749

push

github

web-flow
Merge pull request #344 from hazendaz/master

Use lambda's

1598 of 2797 branches covered (57.13%)

281 of 327 new or added lines in 2 files covered. (85.93%)

3 existing lines in 2 files now uncovered.

5027 of 7671 relevant lines covered (65.53%)

0.66 hits per line

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

88.75
/src/main/java/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java
1
/*
2
 * Copyright 2004-2025 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 com.ibatis.sqlmap.engine.builder.xml;
17

18
import com.ibatis.common.resources.Resources;
19
import com.ibatis.common.xml.NodeletException;
20
import com.ibatis.common.xml.NodeletParser;
21
import com.ibatis.common.xml.NodeletUtils;
22
import com.ibatis.sqlmap.client.SqlMapException;
23
import com.ibatis.sqlmap.engine.cache.CacheController;
24
import com.ibatis.sqlmap.engine.config.CacheModelConfig;
25
import com.ibatis.sqlmap.engine.config.ParameterMapConfig;
26
import com.ibatis.sqlmap.engine.config.ResultMapConfig;
27
import com.ibatis.sqlmap.engine.mapping.statement.DeleteStatement;
28
import com.ibatis.sqlmap.engine.mapping.statement.InsertStatement;
29
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
30
import com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement;
31
import com.ibatis.sqlmap.engine.mapping.statement.SelectStatement;
32
import com.ibatis.sqlmap.engine.mapping.statement.UpdateStatement;
33

34
import java.io.InputStream;
35
import java.io.Reader;
36
import java.util.Properties;
37

38
/**
39
 * The Class SqlMapParser.
40
 */
41
public class SqlMapParser {
42

43
  /** The parser. */
44
  private final NodeletParser parser;
45

46
  /** The state. */
47
  private XmlParserState state;
48

49
  /** The statement parser. */
50
  private SqlStatementParser statementParser;
51

52
  /**
53
   * Instantiates a new sql map parser.
54
   *
55
   * @param state
56
   *          the state
57
   */
58
  public SqlMapParser(XmlParserState state) {
1✔
59
    this.parser = new NodeletParser();
1✔
60
    this.state = state;
1✔
61

62
    parser.setValidation(true);
1✔
63
    parser.setEntityResolver(new SqlMapClasspathEntityResolver());
1✔
64

65
    statementParser = new SqlStatementParser(this.state);
1✔
66

67
    addSqlMapNodelets();
1✔
68
    addSqlNodelets();
1✔
69
    addTypeAliasNodelets();
1✔
70
    addCacheModelNodelets();
1✔
71
    addParameterMapNodelets();
1✔
72
    addResultMapNodelets();
1✔
73
    addStatementNodelets();
1✔
74

75
  }
1✔
76

77
  /**
78
   * Parses the.
79
   *
80
   * @param reader
81
   *          the reader
82
   *
83
   * @throws NodeletException
84
   *           the nodelet exception
85
   */
86
  public void parse(Reader reader) throws NodeletException {
87
    parser.parse(reader);
1✔
88
  }
1✔
89

90
  /**
91
   * Parses the.
92
   *
93
   * @param inputStream
94
   *          the input stream
95
   *
96
   * @throws NodeletException
97
   *           the nodelet exception
98
   */
99
  public void parse(InputStream inputStream) throws NodeletException {
100
    parser.parse(inputStream);
1✔
101
  }
1✔
102

103
  /**
104
   * Adds the sql map nodelets.
105
   */
106
  private void addSqlMapNodelets() {
107
    parser.addNodelet("/sqlMap", node -> {
1✔
108
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
109
      state.setNamespace(attributes.getProperty("namespace"));
1✔
110
    });
1✔
111
  }
1✔
112

113
  /**
114
   * Adds the sql nodelets.
115
   */
116
  private void addSqlNodelets() {
117
    parser.addNodelet("/sqlMap/sql", node -> {
1✔
118
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
119
      String id = attributes.getProperty("id");
1✔
120
      if (state.isUseStatementNamespaces()) {
1!
NEW
121
        id = state.applyNamespace(id);
×
122
      }
123
      if (state.getSqlIncludes().containsKey(id)) {
1!
NEW
124
        throw new SqlMapException("Duplicate <sql>-include '" + id + "' found.");
×
125
      }
126
      state.getSqlIncludes().put(id, node);
1✔
127
    });
1✔
128
  }
1✔
129

130
  /**
131
   * Adds the type alias nodelets.
132
   */
133
  private void addTypeAliasNodelets() {
134
    parser.addNodelet("/sqlMap/typeAlias", node -> {
1✔
135
      Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
136
      String alias = prop.getProperty("alias");
1✔
137
      String type = prop.getProperty("type");
1✔
138
      state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type);
1✔
139
    });
1✔
140
  }
1✔
141

142
  /**
143
   * Adds the cache model nodelets.
144
   */
145
  private void addCacheModelNodelets() {
146
    parser.addNodelet("/sqlMap/cacheModel", node -> {
1✔
147
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
148
      String id = state.applyNamespace(attributes.getProperty("id"));
1✔
149
      String type = attributes.getProperty("type");
1✔
150
      String readOnlyAttr = attributes.getProperty("readOnly");
1✔
151
      Boolean readOnly = readOnlyAttr == null || readOnlyAttr.isEmpty() ? null
1!
152
          : Boolean.valueOf("true".equals(readOnlyAttr));
1✔
153
      String serializeAttr = attributes.getProperty("serialize");
1✔
154
      Boolean serialize = serializeAttr == null || serializeAttr.isEmpty() ? null
1!
155
          : Boolean.valueOf("true".equals(serializeAttr));
1✔
156
      type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
1✔
157
      Class clazz = Resources.classForName(type);
1✔
158
      if (readOnly == null) {
1✔
159
        readOnly = Boolean.TRUE;
1✔
160
      }
161
      if (serialize == null) {
1✔
162
        serialize = Boolean.FALSE;
1✔
163
      }
164
      CacheModelConfig cacheConfig = state.getConfig().newCacheModelConfig(id,
1✔
165
          (CacheController) Resources.instantiate(clazz), readOnly.booleanValue(), serialize.booleanValue());
1✔
166
      state.setCacheConfig(cacheConfig);
1✔
167
    });
1✔
168
    parser.addNodelet("/sqlMap/cacheModel/end()",
1✔
169
        node -> state.getCacheConfig().setControllerProperties(state.getCacheProps()));
1✔
170
    parser.addNodelet("/sqlMap/cacheModel/property", node -> {
1✔
171
      state.getConfig().getErrorContext().setMoreInfo("Check the cache model properties.");
1✔
172
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
173
      String name = attributes.getProperty("name");
1✔
174
      String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
1✔
175
      state.getCacheProps().setProperty(name, value);
1✔
176
    });
1✔
177
    parser.addNodelet("/sqlMap/cacheModel/flushOnExecute", node -> {
1✔
178
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
179
      String statement = childAttributes.getProperty("statement");
1✔
180
      state.getCacheConfig().addFlushTriggerStatement(statement);
1✔
181
    });
1✔
182
    parser.addNodelet("/sqlMap/cacheModel/flushInterval", node -> {
1✔
183
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
184
      try {
185
        int milliseconds = childAttributes.getProperty("milliseconds") == null ? 0
1!
186
            : Integer.parseInt(childAttributes.getProperty("milliseconds"));
1✔
187
        int seconds = childAttributes.getProperty("seconds") == null ? 0
1!
188
            : Integer.parseInt(childAttributes.getProperty("seconds"));
1✔
189
        int minutes = childAttributes.getProperty("minutes") == null ? 0
1!
190
            : Integer.parseInt(childAttributes.getProperty("minutes"));
1✔
191
        int hours = childAttributes.getProperty("hours") == null ? 0
1!
192
            : Integer.parseInt(childAttributes.getProperty("hours"));
1✔
193
        state.getCacheConfig().setFlushInterval(hours, minutes, seconds, milliseconds);
1✔
NEW
194
      } catch (NumberFormatException e) {
×
NEW
195
        throw new RuntimeException("Error building cache in '" + "resourceNAME"
×
196
            + "'.  Flush interval milliseconds must be a valid long integer value.  Cause: " + e, e);
197
      }
1✔
198
    });
1✔
199
  }
1✔
200

201
  /**
202
   * Adds the parameter map nodelets.
203
   */
204
  private void addParameterMapNodelets() {
205
    parser.addNodelet("/sqlMap/parameterMap/end()", node -> {
1✔
206
      state.getConfig().getErrorContext().setMoreInfo(null);
1✔
207
      state.getConfig().getErrorContext().setObjectId(null);
1✔
208
      state.setParamConfig(null);
1✔
209
    });
1✔
210
    parser.addNodelet("/sqlMap/parameterMap", node -> {
1✔
211
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
212
      String id = state.applyNamespace(attributes.getProperty("id"));
1✔
213
      String parameterClassName = attributes.getProperty("class");
1✔
214
      parameterClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(parameterClassName);
1✔
215
      try {
216
        state.getConfig().getErrorContext().setMoreInfo("Check the parameter class.");
1✔
217
        ParameterMapConfig paramConf = state.getConfig().newParameterMapConfig(id,
1✔
218
            Resources.classForName(parameterClassName));
1✔
219
        state.setParamConfig(paramConf);
1✔
NEW
220
      } catch (Exception e) {
×
NEW
221
        throw new SqlMapException("Error configuring ParameterMap.  Could not set ParameterClass.  Cause: " + e, e);
×
222
      }
1✔
223
    });
1✔
224
    parser.addNodelet("/sqlMap/parameterMap/parameter", node -> {
1✔
225
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
226
      String propertyName = childAttributes.getProperty("property");
1✔
227
      String jdbcType = childAttributes.getProperty("jdbcType");
1✔
228
      String type = childAttributes.getProperty("typeName");
1✔
229
      String javaType = childAttributes.getProperty("javaType");
1✔
230
      String resultMap = state.applyNamespace(childAttributes.getProperty("resultMap"));
1✔
231
      String nullValue = childAttributes.getProperty("nullValue");
1✔
232
      String mode = childAttributes.getProperty("mode");
1✔
233
      String callback = childAttributes.getProperty("typeHandler");
1✔
234
      String numericScaleProp = childAttributes.getProperty("numericScale");
1✔
235

236
      callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
1✔
237
      Object typeHandlerImpl = null;
1✔
238
      if (callback != null) {
1✔
239
        typeHandlerImpl = Resources.instantiate(callback);
1✔
240
      }
241

242
      javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
243
      Class javaClass = null;
1✔
244
      try {
245
        if (javaType != null && !javaType.isEmpty()) {
1!
246
          javaClass = Resources.classForName(javaType);
1✔
247
        }
NEW
248
      } catch (ClassNotFoundException e) {
×
NEW
249
        throw new RuntimeException("Error setting javaType on parameter mapping.  Cause: " + e);
×
250
      }
1✔
251

252
      Integer numericScale = null;
1✔
253
      if (numericScaleProp != null) {
1!
NEW
254
        numericScale = Integer.valueOf(numericScaleProp);
×
255
      }
256

257
      state.getParamConfig().addParameterMapping(propertyName, javaClass, jdbcType, nullValue, mode, type, numericScale,
1✔
258
          typeHandlerImpl, resultMap);
259
    });
1✔
260
  }
1✔
261

262
  /**
263
   * Adds the result map nodelets.
264
   */
265
  private void addResultMapNodelets() {
266
    parser.addNodelet("/sqlMap/resultMap/end()", node -> {
1✔
267
      state.getConfig().getErrorContext().setMoreInfo(null);
1✔
268
      state.getConfig().getErrorContext().setObjectId(null);
1✔
269
    });
1✔
270
    parser.addNodelet("/sqlMap/resultMap", node -> {
1✔
271
      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
272
      String id = state.applyNamespace(attributes.getProperty("id"));
1✔
273
      String resultClassName = attributes.getProperty("class");
1✔
274
      String extended = state.applyNamespace(attributes.getProperty("extends"));
1✔
275
      String xmlName = attributes.getProperty("xmlName");
1✔
276
      String groupBy = attributes.getProperty("groupBy");
1✔
277

278
      resultClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(resultClassName);
1✔
279
      Class resultClass;
280
      try {
281
        state.getConfig().getErrorContext().setMoreInfo("Check the result class.");
1✔
282
        resultClass = Resources.classForName(resultClassName);
1✔
NEW
283
      } catch (Exception e) {
×
NEW
284
        throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
×
285
      }
1✔
286
      ResultMapConfig resultConf = state.getConfig().newResultMapConfig(id, resultClass, groupBy, extended, xmlName);
1✔
287
      state.setResultConfig(resultConf);
1✔
288
    });
1✔
289
    parser.addNodelet("/sqlMap/resultMap/result", node -> {
1✔
290
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
291
      String propertyName = childAttributes.getProperty("property");
1✔
292
      String nullValue = childAttributes.getProperty("nullValue");
1✔
293
      String jdbcType = childAttributes.getProperty("jdbcType");
1✔
294
      String javaType = childAttributes.getProperty("javaType");
1✔
295
      String columnName = childAttributes.getProperty("column");
1✔
296
      String columnIndexProp = childAttributes.getProperty("columnIndex");
1✔
297
      String statementName = childAttributes.getProperty("select");
1✔
298
      String resultMapName = childAttributes.getProperty("resultMap");
1✔
299
      String callback = childAttributes.getProperty("typeHandler");
1✔
300
      String notNullColumn = childAttributes.getProperty("notNullColumn");
1✔
301

302
      state.getConfig().getErrorContext().setMoreInfo("Check the result mapping property type or name.");
1✔
303
      Class javaClass = null;
1✔
304
      try {
305
        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
306
        if (javaType != null && !javaType.isEmpty()) {
1!
307
          javaClass = Resources.classForName(javaType);
1✔
308
        }
NEW
309
      } catch (ClassNotFoundException e) {
×
NEW
310
        throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
×
311
      }
1✔
312

313
      state.getConfig().getErrorContext().setMoreInfo("Check the result mapping typeHandler attribute '" + callback
1✔
314
          + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
315
      Object typeHandlerImpl = null;
1✔
316
      try {
317
        if (callback != null && !callback.isEmpty()) {
1!
318
          callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
1✔
319
          typeHandlerImpl = Resources.instantiate(callback);
1✔
320
        }
NEW
321
      } catch (Exception e) {
×
NEW
322
        throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
×
323
      }
1✔
324

325
      Integer columnIndex = null;
1✔
326
      if (columnIndexProp != null) {
1✔
327
        try {
328
          columnIndex = Integer.valueOf(columnIndexProp);
1✔
UNCOV
329
        } catch (Exception e) {
×
NEW
330
          throw new RuntimeException("Error parsing column index.  Cause: " + e, e);
×
331
        }
1✔
332
      }
333

334
      state.getResultConfig().addResultMapping(propertyName, columnName, columnIndex, javaClass, jdbcType, nullValue,
1✔
335
          notNullColumn, statementName, resultMapName, typeHandlerImpl);
336
    });
1✔
337

338
    parser.addNodelet("/sqlMap/resultMap/discriminator/subMap", node -> {
1✔
339
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
340
      String value = childAttributes.getProperty("value");
1✔
341
      String resultMap = childAttributes.getProperty("resultMap");
1✔
342
      resultMap = state.applyNamespace(resultMap);
1✔
343
      state.getResultConfig().addDiscriminatorSubMap(value, resultMap);
1✔
344
    });
1✔
345

346
    parser.addNodelet("/sqlMap/resultMap/discriminator", node -> {
1✔
347
      Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
348
      String nullValue = childAttributes.getProperty("nullValue");
1✔
349
      String jdbcType = childAttributes.getProperty("jdbcType");
1✔
350
      String javaType = childAttributes.getProperty("javaType");
1✔
351
      String columnName = childAttributes.getProperty("column");
1✔
352
      String columnIndexProp = childAttributes.getProperty("columnIndex");
1✔
353
      String callback = childAttributes.getProperty("typeHandler");
1✔
354

355
      state.getConfig().getErrorContext().setMoreInfo("Check the disriminator type or name.");
1✔
356
      Class javaClass = null;
1✔
357
      try {
358
        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
359
        if (javaType != null && !javaType.isEmpty()) {
1!
360
          javaClass = Resources.classForName(javaType);
1✔
361
        }
NEW
362
      } catch (ClassNotFoundException e) {
×
NEW
363
        throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
×
364
      }
1✔
365

366
      state.getConfig().getErrorContext().setMoreInfo("Check the result mapping discriminator typeHandler attribute '"
1✔
367
          + callback + "' (must be a TypeHandlerCallback implementation).");
368
      Object typeHandlerImpl = null;
1✔
369
      try {
370
        if (callback != null && !callback.isEmpty()) {
1!
NEW
371
          callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
×
NEW
372
          typeHandlerImpl = Resources.instantiate(callback);
×
373
        }
NEW
374
      } catch (Exception e) {
×
NEW
375
        throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
×
376
      }
1✔
377

378
      Integer columnIndex = null;
1✔
379
      if (columnIndexProp != null) {
1!
380
        try {
NEW
381
          columnIndex = Integer.valueOf(columnIndexProp);
×
382
        } catch (Exception e) {
×
NEW
383
          throw new RuntimeException("Error parsing column index.  Cause: " + e, e);
×
UNCOV
384
        }
×
385
      }
386

387
      state.getResultConfig().setDiscriminator(columnName, columnIndex, javaClass, jdbcType, nullValue,
1✔
388
          typeHandlerImpl);
389
    });
1✔
390
  }
1✔
391

392
  /**
393
   * Adds the statement nodelets.
394
   */
395
  protected void addStatementNodelets() {
396
    parser.addNodelet("/sqlMap/statement", node -> statementParser.parseGeneralStatement(node, new MappedStatement()));
1✔
397
    parser.addNodelet("/sqlMap/insert", node -> statementParser.parseGeneralStatement(node, new InsertStatement()));
1✔
398
    parser.addNodelet("/sqlMap/update", node -> statementParser.parseGeneralStatement(node, new UpdateStatement()));
1✔
399
    parser.addNodelet("/sqlMap/delete", node -> statementParser.parseGeneralStatement(node, new DeleteStatement()));
1✔
400
    parser.addNodelet("/sqlMap/select", node -> statementParser.parseGeneralStatement(node, new SelectStatement()));
1✔
401
    parser.addNodelet("/sqlMap/procedure",
1✔
402
        node -> statementParser.parseGeneralStatement(node, new ProcedureStatement()));
1✔
403
  }
1✔
404

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