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

mybatis / ibatis-2 / 730

28 Dec 2025 10:16PM UTC coverage: 65.615% (+0.5%) from 65.146%
730

push

github

web-flow
Update README.md

1602 of 2802 branches covered (57.17%)

5053 of 7701 relevant lines covered (65.61%)

0.66 hits per line

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

89.29
/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.Nodelet;
20
import com.ibatis.common.xml.NodeletException;
21
import com.ibatis.common.xml.NodeletParser;
22
import com.ibatis.common.xml.NodeletUtils;
23
import com.ibatis.sqlmap.client.SqlMapException;
24
import com.ibatis.sqlmap.engine.cache.CacheController;
25
import com.ibatis.sqlmap.engine.config.CacheModelConfig;
26
import com.ibatis.sqlmap.engine.config.ParameterMapConfig;
27
import com.ibatis.sqlmap.engine.config.ResultMapConfig;
28
import com.ibatis.sqlmap.engine.mapping.statement.DeleteStatement;
29
import com.ibatis.sqlmap.engine.mapping.statement.InsertStatement;
30
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
31
import com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement;
32
import com.ibatis.sqlmap.engine.mapping.statement.SelectStatement;
33
import com.ibatis.sqlmap.engine.mapping.statement.UpdateStatement;
34

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

39
import org.w3c.dom.Node;
40

41
/**
42
 * The Class SqlMapParser.
43
 */
44
public class SqlMapParser {
45

46
  /** The parser. */
47
  private final NodeletParser parser;
48

49
  /** The state. */
50
  private XmlParserState state;
51

52
  /** The statement parser. */
53
  private SqlStatementParser statementParser;
54

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

65
    parser.setValidation(true);
1✔
66
    parser.setEntityResolver(new SqlMapClasspathEntityResolver());
1✔
67

68
    statementParser = new SqlStatementParser(this.state);
1✔
69

70
    addSqlMapNodelets();
1✔
71
    addSqlNodelets();
1✔
72
    addTypeAliasNodelets();
1✔
73
    addCacheModelNodelets();
1✔
74
    addParameterMapNodelets();
1✔
75
    addResultMapNodelets();
1✔
76
    addStatementNodelets();
1✔
77

78
  }
1✔
79

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

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

106
  /**
107
   * Adds the sql map nodelets.
108
   */
109
  private void addSqlMapNodelets() {
110
    parser.addNodelet("/sqlMap", new Nodelet() {
1✔
111
      public void process(Node node) throws Exception {
112
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
113
        state.setNamespace(attributes.getProperty("namespace"));
1✔
114
      }
1✔
115
    });
116
  }
1✔
117

118
  /**
119
   * Adds the sql nodelets.
120
   */
121
  private void addSqlNodelets() {
122
    parser.addNodelet("/sqlMap/sql", new Nodelet() {
1✔
123
      public void process(Node node) throws Exception {
124
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
125
        String id = attributes.getProperty("id");
1✔
126
        if (state.isUseStatementNamespaces()) {
1!
127
          id = state.applyNamespace(id);
×
128
        }
129
        if (state.getSqlIncludes().containsKey(id)) {
1!
130
          throw new SqlMapException("Duplicate <sql>-include '" + id + "' found.");
×
131
        } else {
132
          state.getSqlIncludes().put(id, node);
1✔
133
        }
134
      }
1✔
135
    });
136
  }
1✔
137

138
  /**
139
   * Adds the type alias nodelets.
140
   */
141
  private void addTypeAliasNodelets() {
142
    parser.addNodelet("/sqlMap/typeAlias", new Nodelet() {
1✔
143
      public void process(Node node) throws Exception {
144
        Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
145
        String alias = prop.getProperty("alias");
1✔
146
        String type = prop.getProperty("type");
1✔
147
        state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type);
1✔
148
      }
1✔
149
    });
150
  }
1✔
151

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

222
  /**
223
   * Adds the parameter map nodelets.
224
   */
225
  private void addParameterMapNodelets() {
226
    parser.addNodelet("/sqlMap/parameterMap/end()", new Nodelet() {
1✔
227
      public void process(Node node) throws Exception {
228
        state.getConfig().getErrorContext().setMoreInfo(null);
1✔
229
        state.getConfig().getErrorContext().setObjectId(null);
1✔
230
        state.setParamConfig(null);
1✔
231
      }
1✔
232
    });
233
    parser.addNodelet("/sqlMap/parameterMap", new Nodelet() {
1✔
234
      public void process(Node node) throws Exception {
235
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
236
        String id = state.applyNamespace(attributes.getProperty("id"));
1✔
237
        String parameterClassName = attributes.getProperty("class");
1✔
238
        parameterClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(parameterClassName);
1✔
239
        try {
240
          state.getConfig().getErrorContext().setMoreInfo("Check the parameter class.");
1✔
241
          ParameterMapConfig paramConf = state.getConfig().newParameterMapConfig(id,
1✔
242
              Resources.classForName(parameterClassName));
1✔
243
          state.setParamConfig(paramConf);
1✔
244
        } catch (Exception e) {
×
245
          throw new SqlMapException("Error configuring ParameterMap.  Could not set ParameterClass.  Cause: " + e, e);
×
246
        }
1✔
247
      }
1✔
248
    });
249
    parser.addNodelet("/sqlMap/parameterMap/parameter", new Nodelet() {
1✔
250
      public void process(Node node) throws Exception {
251
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
252
        String propertyName = childAttributes.getProperty("property");
1✔
253
        String jdbcType = childAttributes.getProperty("jdbcType");
1✔
254
        String type = childAttributes.getProperty("typeName");
1✔
255
        String javaType = childAttributes.getProperty("javaType");
1✔
256
        String resultMap = state.applyNamespace(childAttributes.getProperty("resultMap"));
1✔
257
        String nullValue = childAttributes.getProperty("nullValue");
1✔
258
        String mode = childAttributes.getProperty("mode");
1✔
259
        String callback = childAttributes.getProperty("typeHandler");
1✔
260
        String numericScaleProp = childAttributes.getProperty("numericScale");
1✔
261

262
        callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
1✔
263
        Object typeHandlerImpl = null;
1✔
264
        if (callback != null) {
1✔
265
          typeHandlerImpl = Resources.instantiate(callback);
1✔
266
        }
267

268
        javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
269
        Class javaClass = null;
1✔
270
        try {
271
          if (javaType != null && !javaType.isEmpty()) {
1!
272
            javaClass = Resources.classForName(javaType);
1✔
273
          }
274
        } catch (ClassNotFoundException e) {
×
275
          throw new RuntimeException("Error setting javaType on parameter mapping.  Cause: " + e);
×
276
        }
1✔
277

278
        Integer numericScale = null;
1✔
279
        if (numericScaleProp != null) {
1!
280
          numericScale = Integer.valueOf(numericScaleProp);
×
281
        }
282

283
        state.getParamConfig().addParameterMapping(propertyName, javaClass, jdbcType, nullValue, mode, type,
1✔
284
            numericScale, typeHandlerImpl, resultMap);
285
      }
1✔
286
    });
287
  }
1✔
288

289
  /**
290
   * Adds the result map nodelets.
291
   */
292
  private void addResultMapNodelets() {
293
    parser.addNodelet("/sqlMap/resultMap/end()", new Nodelet() {
1✔
294
      public void process(Node node) throws Exception {
295
        state.getConfig().getErrorContext().setMoreInfo(null);
1✔
296
        state.getConfig().getErrorContext().setObjectId(null);
1✔
297
      }
1✔
298
    });
299
    parser.addNodelet("/sqlMap/resultMap", new Nodelet() {
1✔
300
      public void process(Node node) throws Exception {
301
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
302
        String id = state.applyNamespace(attributes.getProperty("id"));
1✔
303
        String resultClassName = attributes.getProperty("class");
1✔
304
        String extended = state.applyNamespace(attributes.getProperty("extends"));
1✔
305
        String xmlName = attributes.getProperty("xmlName");
1✔
306
        String groupBy = attributes.getProperty("groupBy");
1✔
307

308
        resultClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(resultClassName);
1✔
309
        Class resultClass;
310
        try {
311
          state.getConfig().getErrorContext().setMoreInfo("Check the result class.");
1✔
312
          resultClass = Resources.classForName(resultClassName);
1✔
313
        } catch (Exception e) {
×
314
          throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
×
315
        }
1✔
316
        ResultMapConfig resultConf = state.getConfig().newResultMapConfig(id, resultClass, groupBy, extended, xmlName);
1✔
317
        state.setResultConfig(resultConf);
1✔
318
      }
1✔
319
    });
320
    parser.addNodelet("/sqlMap/resultMap/result", new Nodelet() {
1✔
321
      public void process(Node node) throws Exception {
322
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
323
        String propertyName = childAttributes.getProperty("property");
1✔
324
        String nullValue = childAttributes.getProperty("nullValue");
1✔
325
        String jdbcType = childAttributes.getProperty("jdbcType");
1✔
326
        String javaType = childAttributes.getProperty("javaType");
1✔
327
        String columnName = childAttributes.getProperty("column");
1✔
328
        String columnIndexProp = childAttributes.getProperty("columnIndex");
1✔
329
        String statementName = childAttributes.getProperty("select");
1✔
330
        String resultMapName = childAttributes.getProperty("resultMap");
1✔
331
        String callback = childAttributes.getProperty("typeHandler");
1✔
332
        String notNullColumn = childAttributes.getProperty("notNullColumn");
1✔
333

334
        state.getConfig().getErrorContext().setMoreInfo("Check the result mapping property type or name.");
1✔
335
        Class javaClass = null;
1✔
336
        try {
337
          javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
338
          if (javaType != null && !javaType.isEmpty()) {
1!
339
            javaClass = Resources.classForName(javaType);
1✔
340
          }
341
        } catch (ClassNotFoundException e) {
×
342
          throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
×
343
        }
1✔
344

345
        state.getConfig().getErrorContext().setMoreInfo("Check the result mapping typeHandler attribute '" + callback
1✔
346
            + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
347
        Object typeHandlerImpl = null;
1✔
348
        try {
349
          if (callback != null && !callback.isEmpty()) {
1!
350
            callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
1✔
351
            typeHandlerImpl = Resources.instantiate(callback);
1✔
352
          }
353
        } catch (Exception e) {
×
354
          throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
×
355
        }
1✔
356

357
        Integer columnIndex = null;
1✔
358
        if (columnIndexProp != null) {
1✔
359
          try {
360
            columnIndex = Integer.valueOf(columnIndexProp);
1✔
361
          } catch (Exception e) {
×
362
            throw new RuntimeException("Error parsing column index.  Cause: " + e, e);
×
363
          }
1✔
364
        }
365

366
        state.getResultConfig().addResultMapping(propertyName, columnName, columnIndex, javaClass, jdbcType, nullValue,
1✔
367
            notNullColumn, statementName, resultMapName, typeHandlerImpl);
368
      }
1✔
369
    });
370

371
    parser.addNodelet("/sqlMap/resultMap/discriminator/subMap", new Nodelet() {
1✔
372
      public void process(Node node) throws Exception {
373
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
374
        String value = childAttributes.getProperty("value");
1✔
375
        String resultMap = childAttributes.getProperty("resultMap");
1✔
376
        resultMap = state.applyNamespace(resultMap);
1✔
377
        state.getResultConfig().addDiscriminatorSubMap(value, resultMap);
1✔
378
      }
1✔
379
    });
380

381
    parser.addNodelet("/sqlMap/resultMap/discriminator", new Nodelet() {
1✔
382
      public void process(Node node) throws Exception {
383
        Properties childAttributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
1✔
384
        String nullValue = childAttributes.getProperty("nullValue");
1✔
385
        String jdbcType = childAttributes.getProperty("jdbcType");
1✔
386
        String javaType = childAttributes.getProperty("javaType");
1✔
387
        String columnName = childAttributes.getProperty("column");
1✔
388
        String columnIndexProp = childAttributes.getProperty("columnIndex");
1✔
389
        String callback = childAttributes.getProperty("typeHandler");
1✔
390

391
        state.getConfig().getErrorContext().setMoreInfo("Check the disriminator type or name.");
1✔
392
        Class javaClass = null;
1✔
393
        try {
394
          javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
1✔
395
          if (javaType != null && !javaType.isEmpty()) {
1!
396
            javaClass = Resources.classForName(javaType);
1✔
397
          }
398
        } catch (ClassNotFoundException e) {
×
399
          throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
×
400
        }
1✔
401

402
        state.getConfig().getErrorContext().setMoreInfo("Check the result mapping discriminator typeHandler attribute '"
1✔
403
            + callback + "' (must be a TypeHandlerCallback implementation).");
404
        Object typeHandlerImpl = null;
1✔
405
        try {
406
          if (callback != null && !callback.isEmpty()) {
1!
407
            callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
×
408
            typeHandlerImpl = Resources.instantiate(callback);
×
409
          }
410
        } catch (Exception e) {
×
411
          throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
×
412
        }
1✔
413

414
        Integer columnIndex = null;
1✔
415
        if (columnIndexProp != null) {
1!
416
          try {
417
            columnIndex = Integer.valueOf(columnIndexProp);
×
418
          } catch (Exception e) {
×
419
            throw new RuntimeException("Error parsing column index.  Cause: " + e, e);
×
420
          }
×
421
        }
422

423
        state.getResultConfig().setDiscriminator(columnName, columnIndex, javaClass, jdbcType, nullValue,
1✔
424
            typeHandlerImpl);
425
      }
1✔
426
    });
427
  }
1✔
428

429
  /**
430
   * Adds the statement nodelets.
431
   */
432
  protected void addStatementNodelets() {
433
    parser.addNodelet("/sqlMap/statement", new Nodelet() {
1✔
434
      public void process(Node node) throws Exception {
435
        statementParser.parseGeneralStatement(node, new MappedStatement());
1✔
436
      }
1✔
437
    });
438
    parser.addNodelet("/sqlMap/insert", new Nodelet() {
1✔
439
      public void process(Node node) throws Exception {
440
        statementParser.parseGeneralStatement(node, new InsertStatement());
1✔
441
      }
1✔
442
    });
443
    parser.addNodelet("/sqlMap/update", new Nodelet() {
1✔
444
      public void process(Node node) throws Exception {
445
        statementParser.parseGeneralStatement(node, new UpdateStatement());
1✔
446
      }
1✔
447
    });
448
    parser.addNodelet("/sqlMap/delete", new Nodelet() {
1✔
449
      public void process(Node node) throws Exception {
450
        statementParser.parseGeneralStatement(node, new DeleteStatement());
1✔
451
      }
1✔
452
    });
453
    parser.addNodelet("/sqlMap/select", new Nodelet() {
1✔
454
      public void process(Node node) throws Exception {
455
        statementParser.parseGeneralStatement(node, new SelectStatement());
1✔
456
      }
1✔
457
    });
458
    parser.addNodelet("/sqlMap/procedure", new Nodelet() {
1✔
459
      public void process(Node node) throws Exception {
460
        statementParser.parseGeneralStatement(node, new ProcedureStatement());
1✔
461
      }
1✔
462
    });
463
  }
1✔
464

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