• 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

83.09
/src/main/java/com/ibatis/sqlmap/engine/mapping/result/ResultMap.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.mapping.result;
17

18
import com.ibatis.common.beans.Probe;
19
import com.ibatis.common.beans.ProbeFactory;
20
import com.ibatis.common.jdbc.exception.NestedSQLException;
21
import com.ibatis.sqlmap.client.SqlMapException;
22
import com.ibatis.sqlmap.engine.exchange.DataExchange;
23
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
24
import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
25
import com.ibatis.sqlmap.engine.mapping.result.loader.ResultLoader;
26
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
27
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
28
import com.ibatis.sqlmap.engine.scope.ErrorContext;
29
import com.ibatis.sqlmap.engine.scope.StatementScope;
30
import com.ibatis.sqlmap.engine.type.DomCollectionTypeMarker;
31
import com.ibatis.sqlmap.engine.type.DomTypeMarker;
32
import com.ibatis.sqlmap.engine.type.TypeHandler;
33
import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
34

35
import java.sql.ResultSet;
36
import java.sql.SQLException;
37
import java.util.ArrayList;
38
import java.util.Collection;
39
import java.util.HashMap;
40
import java.util.HashSet;
41
import java.util.Iterator;
42
import java.util.List;
43
import java.util.Map;
44
import java.util.Set;
45
import java.util.StringTokenizer;
46

47
import javax.xml.parsers.DocumentBuilderFactory;
48
import javax.xml.parsers.ParserConfigurationException;
49

50
import org.w3c.dom.Document;
51

52
/**
53
 * Basic implementation of ResultMap interface.
54
 */
55
public class ResultMap {
56

57
  /** The Constant PROBE. */
58
  private static final Probe PROBE = ProbeFactory.getProbe();
1✔
59

60
  /** The Constant KEY_SEPARATOR. */
61
  private static final String KEY_SEPARATOR = "\002";
62

63
  /** The id. */
64
  private String id;
65

66
  /** The result class. */
67
  private Class resultClass;
68

69
  /** The result mappings. */
70
  // DO NOT ACCESS EITHER OF THESE OUTSIDE OF THEIR BEAN GETTER/SETTER
71
  private ResultMapping[] resultMappings;
72

73
  /** The remappable result mappings. */
74
  private ThreadLocal remappableResultMappings = new ThreadLocal();
1✔
75

76
  /** The data exchange. */
77
  private DataExchange dataExchange;
78

79
  /** The nested result mappings. */
80
  private List nestedResultMappings;
81

82
  /** The discriminator. */
83
  private Discriminator discriminator;
84

85
  /** The group by props. */
86
  private Set groupByProps;
87

88
  /** The xml name. */
89
  private String xmlName;
90

91
  /** The resource. */
92
  private String resource;
93

94
  /** The delegate. */
95
  protected SqlMapExecutorDelegate delegate;
96

97
  /** The allow remapping. */
98
  protected boolean allowRemapping = false;
1✔
99

100
  /** The Constant NO_VALUE. */
101
  public static final Object NO_VALUE = new Object();
1✔
102

103
  /**
104
   * Constructor to pass a SqlMapExecutorDelegate in.
105
   *
106
   * @param delegate
107
   *          - the SqlMapExecutorDelegate
108
   */
109
  public ResultMap(SqlMapExecutorDelegate delegate) {
1✔
110
    this.delegate = delegate;
1✔
111
  }
1✔
112

113
  /**
114
   * Getter for the SqlMapExecutorDelegate.
115
   *
116
   * @return - the delegate
117
   */
118
  public SqlMapExecutorDelegate getDelegate() {
119
    return delegate;
1✔
120
  }
121

122
  /**
123
   * Gets the id.
124
   *
125
   * @return the id
126
   */
127
  public String getId() {
128
    return id;
1✔
129
  }
130

131
  /**
132
   * Setter for the ID.
133
   *
134
   * @param id
135
   *          - the new ID
136
   */
137
  public void setId(String id) {
138
    this.id = id;
1✔
139
  }
1✔
140

141
  /**
142
   * Gets the result class.
143
   *
144
   * @return the result class
145
   */
146
  public Class getResultClass() {
147
    return resultClass;
1✔
148
  }
149

150
  /**
151
   * Gets the unique key.
152
   *
153
   * @param keyPrefix
154
   *          the key prefix
155
   * @param values
156
   *          the values
157
   *
158
   * @return the unique key
159
   */
160
  public Object getUniqueKey(String keyPrefix, Object[] values) {
161
    if (groupByProps != null) {
1✔
162
      StringBuilder keyBuffer;
163
      if (keyPrefix != null)
1✔
164
        keyBuffer = new StringBuilder(keyPrefix);
1✔
165
      else
166
        keyBuffer = new StringBuilder();
1✔
167
      for (int i = 0; i < getResultMappings().length; i++) {
1✔
168
        String propertyName = getResultMappings()[i].getPropertyName();
1✔
169
        if (groupByProps.contains(propertyName)) {
1✔
170
          keyBuffer.append(values[i]);
1✔
171
          keyBuffer.append('-');
1✔
172
        }
173
      }
174
      if (keyBuffer.length() < 1) {
1!
175
        return null;
×
176
      }
177
      // seperator value not likely to appear in a database
178
      keyBuffer.append(KEY_SEPARATOR);
1✔
179
      return keyBuffer.toString();
1✔
180
    }
181
    return null;
1✔
182
  }
183

184
  /**
185
   * Gets the unique key.
186
   *
187
   * @param values
188
   *          the values
189
   *
190
   * @return the unique key
191
   */
192
  public Object getUniqueKey(Object[] values) {
193
    return getUniqueKey(null, values);
×
194
  }
195

196
  /**
197
   * Setter for the result class (what the results will be mapped into).
198
   *
199
   * @param resultClass
200
   *          - the result class
201
   */
202
  public void setResultClass(Class resultClass) {
203
    this.resultClass = resultClass;
1✔
204
  }
1✔
205

206
  /**
207
   * Getter for the DataExchange object to be used.
208
   *
209
   * @return - the DataExchange object
210
   */
211
  public DataExchange getDataExchange() {
212
    return dataExchange;
×
213
  }
214

215
  /**
216
   * Setter for the DataExchange object to be used.
217
   *
218
   * @param dataExchange
219
   *          - the new DataExchange object
220
   */
221
  public void setDataExchange(DataExchange dataExchange) {
222
    this.dataExchange = dataExchange;
×
223
  }
×
224

225
  /**
226
   * Getter (used by DomDataExchange) for the xml name of the results.
227
   *
228
   * @return - the name
229
   */
230
  public String getXmlName() {
231
    return xmlName;
1✔
232
  }
233

234
  /**
235
   * Setter (used by the SqlMapBuilder) for the xml name of the results.
236
   *
237
   * @param xmlName
238
   *          - the name
239
   */
240
  public void setXmlName(String xmlName) {
241
    this.xmlName = xmlName;
1✔
242
  }
1✔
243

244
  /**
245
   * Getter for the resource (used to report errors).
246
   *
247
   * @return - the resource
248
   */
249
  public String getResource() {
250
    return resource;
1✔
251
  }
252

253
  /**
254
   * Setter for the resource (used by the SqlMapBuilder).
255
   *
256
   * @param resource
257
   *          - the resource name
258
   */
259
  public void setResource(String resource) {
260
    this.resource = resource;
1✔
261
  }
1✔
262

263
  /**
264
   * Adds the group by property.
265
   *
266
   * @param name
267
   *          the name
268
   */
269
  public void addGroupByProperty(String name) {
270
    if (groupByProps == null) {
1!
271
      groupByProps = new HashSet<>();
1✔
272
    }
273
    groupByProps.add(name);
1✔
274
  }
1✔
275

276
  /**
277
   * Checks for group by.
278
   *
279
   * @return true, if successful
280
   */
281
  public boolean hasGroupBy() {
282
    return groupByProps != null && groupByProps.size() > 0;
1!
283
  }
284

285
  /**
286
   * Group by props.
287
   *
288
   * @return the iterator
289
   */
290
  public Iterator groupByProps() {
291
    return groupByProps.iterator();
1✔
292
  }
293

294
  /**
295
   * Adds the nested result mappings.
296
   *
297
   * @param mapping
298
   *          the mapping
299
   */
300
  public void addNestedResultMappings(ResultMapping mapping) {
301
    if (nestedResultMappings == null) {
1✔
302
      nestedResultMappings = new ArrayList<>();
1✔
303
    }
304
    nestedResultMappings.add(mapping);
1✔
305
  }
1✔
306

307
  /**
308
   * Gets the nested result mappings.
309
   *
310
   * @return the nested result mappings
311
   */
312
  public List getNestedResultMappings() {
313
    return nestedResultMappings;
1✔
314
  }
315

316
  /**
317
   * Gets the result mappings.
318
   *
319
   * @return the result mappings
320
   */
321
  public ResultMapping[] getResultMappings() {
322
    if (allowRemapping) {
1✔
323
      return (ResultMapping[]) remappableResultMappings.get();
1✔
324
    }
325
    return resultMappings;
1✔
326
  }
327

328
  /**
329
   * Sets the discriminator.
330
   *
331
   * @param discriminator
332
   *          the new discriminator
333
   */
334
  public void setDiscriminator(Discriminator discriminator) {
335
    if (this.discriminator != null) {
1!
336
      throw new SqlMapException("A discriminator may only be set once per result map.");
×
337
    }
338
    this.discriminator = discriminator;
1✔
339
  }
1✔
340

341
  /**
342
   * Gets the discriminator.
343
   *
344
   * @return the discriminator
345
   */
346
  public Discriminator getDiscriminator() {
347
    return discriminator;
1✔
348
  }
349

350
  /**
351
   * Resolve sub map.
352
   *
353
   * @param statementScope
354
   *          the statement scope
355
   * @param rs
356
   *          the rs
357
   *
358
   * @return the result map
359
   *
360
   * @throws SQLException
361
   *           the SQL exception
362
   */
363
  public ResultMap resolveSubMap(StatementScope statementScope, ResultSet rs) throws SQLException {
364
    ResultMap subMap = this;
1✔
365
    if (discriminator != null) {
1✔
366
      ResultMapping mapping = discriminator.getResultMapping();
1✔
367
      Object value = getPrimitiveResultMappingValue(rs, mapping);
1✔
368
      if (value == null) {
1!
369
        value = doNullMapping(value, mapping);
×
370
      }
371
      subMap = discriminator.getSubMap(String.valueOf(value));
1✔
372
      if (subMap == null) {
1✔
373
        subMap = this;
1✔
374
      } else if (subMap != this) {
1!
375
        subMap = subMap.resolveSubMap(statementScope, rs);
1✔
376
      }
377
    }
378
    return subMap;
1✔
379
  }
380

381
  /**
382
   * Setter for a list of the individual ResultMapping objects.
383
   *
384
   * @param resultMappingList
385
   *          - the list
386
   */
387
  public void setResultMappingList(List resultMappingList) {
388
    if (allowRemapping) {
1✔
389
      this.remappableResultMappings.set(resultMappingList.toArray(new ResultMapping[resultMappingList.size()]));
1✔
390
    } else {
391
      this.resultMappings = (ResultMapping[]) resultMappingList.toArray(new ResultMapping[resultMappingList.size()]);
1✔
392
    }
393

394
    Map props = new HashMap<>();
1✔
395
    props.put("map", this);
1✔
396
    dataExchange = getDelegate().getDataExchangeFactory().getDataExchangeForClass(resultClass);
1✔
397
    dataExchange.initialize(props);
1✔
398
  }
1✔
399

400
  /**
401
   * Getter for the number of ResultMapping objects.
402
   *
403
   * @return - the count
404
   */
405
  public int getResultCount() {
406
    return this.getResultMappings().length;
×
407
  }
408

409
  /**
410
   * Read a row from a resultset and map results to an array.
411
   *
412
   * @param statementScope
413
   *          scope of the request
414
   * @param rs
415
   *          ResultSet to read from
416
   *
417
   * @return row read as an array of column values.
418
   *
419
   * @throws SQLException
420
   *           the SQL exception
421
   */
422
  public Object[] getResults(StatementScope statementScope, ResultSet rs) throws SQLException {
423
    ErrorContext errorContext = statementScope.getErrorContext();
1✔
424
    errorContext.setActivity("applying a result map");
1✔
425
    errorContext.setObjectId(this.getId());
1✔
426
    errorContext.setResource(this.getResource());
1✔
427
    errorContext.setMoreInfo("Check the result map.");
1✔
428

429
    boolean foundData = false;
1✔
430
    Object[] columnValues = new Object[getResultMappings().length];
1✔
431
    for (int i = 0; i < getResultMappings().length; i++) {
1✔
432
      ResultMapping mapping = getResultMappings()[i];
1✔
433
      errorContext.setMoreInfo(mapping.getErrorString());
1✔
434
      if (mapping.getStatementName() != null) {
1✔
435
        if (resultClass == null) {
1!
436
          throw new SqlMapException(
×
437
              "The result class was null when trying to get results for ResultMap named " + getId() + ".");
×
438
        }
439
        if (Map.class.isAssignableFrom(resultClass)) {
1!
440
          Class javaType = mapping.getJavaType();
×
441
          if (javaType == null) {
×
442
            javaType = Object.class;
×
443
          }
444
          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);
×
445
        } else if (DomTypeMarker.class.isAssignableFrom(resultClass)) {
1✔
446
          Class javaType = mapping.getJavaType();
1✔
447
          if (javaType == null) {
1✔
448
            javaType = DomTypeMarker.class;
1✔
449
          }
450
          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);
1✔
451
        } else {
1✔
452
          Probe p = ProbeFactory.getProbe(resultClass);
1✔
453
          Class type = p.getPropertyTypeForSetter(resultClass, mapping.getPropertyName());
1✔
454
          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, type);
1✔
455
        }
456
        foundData = foundData || columnValues[i] != null;
1!
457
      } else if (mapping.getNestedResultMapName() == null) {
1✔
458
        columnValues[i] = getPrimitiveResultMappingValue(rs, mapping);
1✔
459
        if (columnValues[i] == null) {
1✔
460
          columnValues[i] = doNullMapping(columnValues[i], mapping);
1✔
461
        } else {
462
          foundData = true;
1✔
463
        }
464
      }
465
    }
466

467
    statementScope.setRowDataFound(foundData);
1✔
468

469
    return columnValues;
1✔
470
  }
471

472
  /**
473
   * Sets the result object values.
474
   *
475
   * @param statementScope
476
   *          the statement scope
477
   * @param resultObject
478
   *          the result object
479
   * @param values
480
   *          the values
481
   *
482
   * @return the object
483
   */
484
  public Object setResultObjectValues(StatementScope statementScope, Object resultObject, Object[] values) {
485
    final String previousNestedKey = statementScope.getCurrentNestedKey();
1✔
486
    String ukey = (String) getUniqueKey(statementScope.getCurrentNestedKey(), values);
1✔
487
    Map uniqueKeys = statementScope.getUniqueKeys(this);
1✔
488
    statementScope.setCurrentNestedKey(ukey);
1✔
489
    if (uniqueKeys != null && uniqueKeys.containsKey(ukey)) {
1✔
490
      // Unique key is already known, so get the existing result object and process additional
491
      // results.
492
      resultObject = uniqueKeys.get(ukey);
1✔
493
      applyNestedResultMap(statementScope, resultObject, values);
1✔
494
      resultObject = NO_VALUE;
1✔
495
    } else if (ukey == null || uniqueKeys == null || !uniqueKeys.containsKey(ukey)) {
1!
496
      // Unique key is NOT known, so create a new result object and then process additional
497
      // results.
498
      resultObject = dataExchange.setData(statementScope, this, resultObject, values);
1✔
499
      // Lazy init key set, only if we're grouped by something (i.e. ukey != null)
500
      if (ukey != null) {
1✔
501
        if (uniqueKeys == null) {
1✔
502
          uniqueKeys = new HashMap<>();
1✔
503
          statementScope.setUniqueKeys(this, uniqueKeys);
1✔
504
        }
505
        uniqueKeys.put(ukey, resultObject);
1✔
506
      }
507
      applyNestedResultMap(statementScope, resultObject, values);
1✔
508
    } else {
509
      // Otherwise, we don't care about these results.
510
      resultObject = NO_VALUE;
×
511
    }
512

513
    statementScope.setCurrentNestedKey(previousNestedKey);
1✔
514
    return resultObject;
1✔
515
  }
516

517
  /**
518
   * Apply nested result map.
519
   *
520
   * @param statementScope
521
   *          the statement scope
522
   * @param resultObject
523
   *          the result object
524
   * @param values
525
   *          the values
526
   */
527
  private void applyNestedResultMap(StatementScope statementScope, Object resultObject, Object[] values) {
528
    if (resultObject != null && resultObject != NO_VALUE) {
1!
529
      if (nestedResultMappings != null) {
1✔
530
        for (int i = 0, n = nestedResultMappings.size(); i < n; i++) {
1✔
531
          ResultMapping resultMapping = (ResultMapping) nestedResultMappings.get(i);
1✔
532
          setNestedResultMappingValue(resultMapping, statementScope, resultObject, values);
1✔
533
        }
534
      }
535
    }
536
  }
1✔
537

538
  /**
539
   * Some changes in this method for IBATIS-225:
540
   * <ul>
541
   * <li>We no longer require the nested property to be a collection. This will allow reuses of resultMaps on 1:1
542
   * relationships</li>
543
   * <li>If the nested property is not a collection, then it will be created/replaced by the values generated from the
544
   * current row.</li>
545
   * </ul>
546
   *
547
   * @param mapping
548
   *          the mapping
549
   * @param statementScope
550
   *          the statement scope
551
   * @param resultObject
552
   *          the result object
553
   * @param values
554
   *          the values
555
   */
556
  protected void setNestedResultMappingValue(ResultMapping mapping, StatementScope statementScope, Object resultObject,
557
      Object[] values) {
558
    try {
559

560
      String resultMapName = mapping.getNestedResultMapName();
1✔
561
      ResultMap resultMap = getDelegate().getResultMap(resultMapName);
1✔
562
      // get the discriminated submap if it exists
563
      resultMap = resultMap.resolveSubMap(statementScope, statementScope.getResultSet());
1✔
564

565
      Class type = mapping.getJavaType();
1✔
566
      String propertyName = mapping.getPropertyName();
1✔
567

568
      Object obj = PROBE.getObject(resultObject, propertyName);
1✔
569

570
      if (obj == null) {
1✔
571
        if (type == null) {
1!
572
          type = PROBE.getPropertyTypeForSetter(resultObject, propertyName);
1✔
573
        }
574

575
        try {
576
          // create the object if is it a Collection. If not a Collection
577
          // then we will just set the property to the object created
578
          // in processing the nested result map
579
          if (Collection.class.isAssignableFrom(type)) {
1✔
580
            obj = ResultObjectFactoryUtil.createObjectThroughFactory(type);
1✔
581
            PROBE.setObject(resultObject, propertyName, obj);
1✔
582
          }
583
        } catch (Exception e) {
×
584
          throw new SqlMapException(
×
585
              "Error instantiating collection property for mapping '" + mapping.getPropertyName() + "'.  Cause: " + e,
×
586
              e);
587
        }
1✔
588
      }
589

590
      // JIRA 375
591
      // "Provide a way for not creating items from nested ResultMaps when the items contain only null values"
592
      boolean subResultObjectAbsent = false;
1✔
593
      if (mapping.getNotNullColumn() != null) {
1!
594
        if (statementScope.getResultSet().getObject(mapping.getNotNullColumn()) == null) {
×
595
          subResultObjectAbsent = true;
×
596
        }
597
      }
598
      if (!subResultObjectAbsent) {
1!
599
        values = resultMap.getResults(statementScope, statementScope.getResultSet());
1✔
600
        if (statementScope.isRowDataFound()) {
1✔
601
          Object o = resultMap.setResultObjectValues(statementScope, null, values);
1✔
602
          if (o != NO_VALUE) {
1✔
603
            if (obj != null && obj instanceof Collection) {
1✔
604
              ((Collection) obj).add(o);
1✔
605
            } else {
606
              PROBE.setObject(resultObject, propertyName, o);
1✔
607
            }
608
          }
609
        }
610
      }
611
    } catch (SQLException e) {
×
612
      throw new SqlMapException(
×
613
          "Error getting nested result map values for '" + mapping.getPropertyName() + "'.  Cause: " + e, e);
×
614
    }
1✔
615
  }
1✔
616

617
  /**
618
   * Gets the nested select mapping value.
619
   *
620
   * @param statementScope
621
   *          the statement scope
622
   * @param rs
623
   *          the rs
624
   * @param mapping
625
   *          the mapping
626
   * @param targetType
627
   *          the target type
628
   *
629
   * @return the nested select mapping value
630
   *
631
   * @throws SQLException
632
   *           the SQL exception
633
   */
634
  protected Object getNestedSelectMappingValue(StatementScope statementScope, ResultSet rs, ResultMapping mapping,
635
      Class targetType) throws SQLException {
636
    try {
637
      TypeHandlerFactory typeHandlerFactory = getDelegate().getTypeHandlerFactory();
1✔
638

639
      String statementName = mapping.getStatementName();
1✔
640
      SqlMapClientImpl client = (SqlMapClientImpl) statementScope.getSession().getSqlMapClient();
1✔
641

642
      MappedStatement mappedStatement = client.getMappedStatement(statementName);
1✔
643
      Class parameterType = mappedStatement.getParameterClass();
1✔
644
      Object parameterObject = null;
1✔
645

646
      if (parameterType == null) {
1!
647
        parameterObject = prepareBeanParameterObject(statementScope, rs, mapping, parameterType);
×
648
      } else {
649
        if (typeHandlerFactory.hasTypeHandler(parameterType)) {
1✔
650
          parameterObject = preparePrimitiveParameterObject(rs, mapping, parameterType);
1✔
651
        } else if (DomTypeMarker.class.isAssignableFrom(parameterType)) {
1✔
652
          parameterObject = prepareDomParameterObject(rs, mapping);
1✔
653
        } else {
654
          parameterObject = prepareBeanParameterObject(statementScope, rs, mapping, parameterType);
1✔
655
        }
656
      }
657

658
      Object result = null;
1✔
659
      if (parameterObject != null) {
1!
660

661
        Sql sql = mappedStatement.getSql();
1✔
662
        ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
1✔
663
        Class resultClass = resultMap.getResultClass();
1✔
664

665
        if (resultClass != null && !DomTypeMarker.class.isAssignableFrom(targetType)) {
1!
666
          if (DomCollectionTypeMarker.class.isAssignableFrom(resultClass)) {
1!
667
            targetType = DomCollectionTypeMarker.class;
×
668
          } else if (DomTypeMarker.class.isAssignableFrom(resultClass)) {
1!
669
            targetType = DomTypeMarker.class;
×
670
          }
671
        }
672

673
        result = ResultLoader.loadResult(client, statementName, parameterObject, targetType);
1✔
674

675
        String nullValue = mapping.getNullValue();
1✔
676
        if (result == null && nullValue != null) {
1!
677
          TypeHandler typeHandler = typeHandlerFactory.getTypeHandler(targetType);
×
678
          if (typeHandler != null) {
×
679
            result = typeHandler.valueOf(nullValue);
×
680
          }
681
        }
682
      }
683
      return result;
1✔
684
    } catch (InstantiationException | IllegalAccessException e) {
×
685
      throw new NestedSQLException("Error setting nested bean property.  Cause: " + e, e);
×
686
    }
687

688
  }
689

690
  /**
691
   * Prepare primitive parameter object.
692
   *
693
   * @param rs
694
   *          the rs
695
   * @param mapping
696
   *          the mapping
697
   * @param parameterType
698
   *          the parameter type
699
   *
700
   * @return the object
701
   *
702
   * @throws SQLException
703
   *           the SQL exception
704
   */
705
  private Object preparePrimitiveParameterObject(ResultSet rs, ResultMapping mapping, Class parameterType)
706
      throws SQLException {
707
    TypeHandlerFactory typeHandlerFactory = getDelegate().getTypeHandlerFactory();
1✔
708
    TypeHandler th = typeHandlerFactory.getTypeHandler(parameterType);
1✔
709
    return th.getResult(rs, mapping.getColumnName());
1✔
710
  }
711

712
  /**
713
   * New document.
714
   *
715
   * @param root
716
   *          the root
717
   *
718
   * @return the document
719
   */
720
  private Document newDocument(String root) {
721
    try {
722
      Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
1✔
723
      doc.appendChild(doc.createElement(root));
1✔
724
      return doc;
1✔
725
    } catch (ParserConfigurationException e) {
×
726
      throw new RuntimeException("Error creating XML document.  Cause: " + e);
×
727
    }
728
  }
729

730
  /**
731
   * Prepare dom parameter object.
732
   *
733
   * @param rs
734
   *          the rs
735
   * @param mapping
736
   *          the mapping
737
   *
738
   * @return the object
739
   *
740
   * @throws SQLException
741
   *           the SQL exception
742
   */
743
  private Object prepareDomParameterObject(ResultSet rs, ResultMapping mapping) throws SQLException {
744
    TypeHandlerFactory typeHandlerFactory = getDelegate().getTypeHandlerFactory();
1✔
745

746
    Document doc = newDocument("parameter");
1✔
747
    Probe probe = ProbeFactory.getProbe(doc);
1✔
748

749
    String complexName = mapping.getColumnName();
1✔
750

751
    TypeHandler stringTypeHandler = typeHandlerFactory.getTypeHandler(String.class);
1✔
752
    if (complexName.indexOf('=') > -1) {
1!
753
      // old 1.x style multiple params
754
      StringTokenizer parser = new StringTokenizer(complexName, "{}=, ", false);
1✔
755
      while (parser.hasMoreTokens()) {
1✔
756
        String propName = parser.nextToken();
1✔
757
        String colName = parser.nextToken();
1✔
758
        Object propValue = stringTypeHandler.getResult(rs, colName);
1✔
759
        probe.setObject(doc, propName, propValue.toString());
1✔
760
      }
1✔
761
    } else {
1✔
762
      // single param
763
      Object propValue = stringTypeHandler.getResult(rs, complexName);
×
764
      probe.setObject(doc, "value", propValue.toString());
×
765
    }
766

767
    return doc;
1✔
768
  }
769

770
  /**
771
   * Prepare bean parameter object.
772
   *
773
   * @param statementScope
774
   *          the statement scope
775
   * @param rs
776
   *          the rs
777
   * @param mapping
778
   *          the mapping
779
   * @param parameterType
780
   *          the parameter type
781
   *
782
   * @return the object
783
   *
784
   * @throws InstantiationException
785
   *           the instantiation exception
786
   * @throws IllegalAccessException
787
   *           the illegal access exception
788
   * @throws SQLException
789
   *           the SQL exception
790
   */
791
  private Object prepareBeanParameterObject(StatementScope statementScope, ResultSet rs, ResultMapping mapping,
792
      Class parameterType) throws InstantiationException, IllegalAccessException, SQLException {
793
    TypeHandlerFactory typeHandlerFactory = getDelegate().getTypeHandlerFactory();
1✔
794

795
    Object parameterObject;
796
    if (parameterType == null) {
1!
797
      parameterObject = new HashMap<>();
×
798
    } else {
799
      parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(parameterType);
1✔
800
    }
801
    String complexName = mapping.getColumnName();
1✔
802

803
    if (complexName.indexOf('=') > -1 || complexName.indexOf(',') > -1) {
1!
804
      StringTokenizer parser = new StringTokenizer(complexName, "{}=, ", false);
1✔
805
      while (parser.hasMoreTokens()) {
1✔
806
        String propName = parser.nextToken();
1✔
807
        String colName = parser.nextToken();
1✔
808
        Class propType = PROBE.getPropertyTypeForSetter(parameterObject, propName);
1✔
809
        TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(propType);
1✔
810
        Object propValue = propTypeHandler.getResult(rs, colName);
1✔
811
        PROBE.setObject(parameterObject, propName, propValue);
1✔
812
      }
1✔
813
    } else {
1✔
814
      // single param
815
      TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(parameterType);
×
816
      if (propTypeHandler == null) {
×
817
        propTypeHandler = typeHandlerFactory.getUnkownTypeHandler();
×
818
      }
819
      parameterObject = propTypeHandler.getResult(rs, complexName);
×
820
    }
821

822
    return parameterObject;
1✔
823
  }
824

825
  /**
826
   * Gets the primitive result mapping value.
827
   *
828
   * @param rs
829
   *          the rs
830
   * @param mapping
831
   *          the mapping
832
   *
833
   * @return the primitive result mapping value
834
   *
835
   * @throws SQLException
836
   *           the SQL exception
837
   */
838
  protected Object getPrimitiveResultMappingValue(ResultSet rs, ResultMapping mapping) throws SQLException {
839
    Object value = null;
1✔
840
    TypeHandler typeHandler = mapping.getTypeHandler();
1✔
841
    if (typeHandler != null) {
1!
842
      String columnName = mapping.getColumnName();
1✔
843
      int columnIndex = mapping.getColumnIndex();
1✔
844
      if (columnName == null) {
1!
845
        value = typeHandler.getResult(rs, columnIndex);
×
846
      } else {
847
        value = typeHandler.getResult(rs, columnName);
1✔
848
      }
849
    } else {
1✔
850
      throw new SqlMapException("No type handler could be found to map the property '" + mapping.getPropertyName()
×
851
          + "' to the column '" + mapping.getColumnName()
×
852
          + "'.  One or both of the types, or the combination of types is not supported.");
853
    }
854
    return value;
1✔
855
  }
856

857
  /**
858
   * Do null mapping.
859
   *
860
   * @param value
861
   *          the value
862
   * @param mapping
863
   *          the mapping
864
   *
865
   * @return the object
866
   *
867
   * @throws SqlMapException
868
   *           the sql map exception
869
   */
870
  protected Object doNullMapping(Object value, ResultMapping mapping) throws SqlMapException {
871
    if (value == null) {
1!
872
      TypeHandler typeHandler = mapping.getTypeHandler();
1✔
873
      if (typeHandler != null) {
1!
874
        String nullValue = mapping.getNullValue();
1✔
875
        if (nullValue != null)
1✔
876
          value = typeHandler.valueOf(nullValue);
1✔
877
        return value;
1✔
878
      }
879
      throw new SqlMapException("No type handler could be found to map the property '" + mapping.getPropertyName()
×
880
          + "' to the column '" + mapping.getColumnName()
×
881
          + "'.  One or both of the types, or the combination of types is not supported.");
882
    }
883
    return value;
×
884
  }
885
}
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