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

mybatis / ibatis-2 / 678

27 Dec 2025 01:13AM UTC coverage: 65.584% (+0.05%) from 65.532%
678

push

github

hazendaz
Merge remote-tracking branch 'upstream/master' into support-javax

1606 of 2810 branches covered (57.15%)

167 of 305 new or added lines in 90 files covered. (54.75%)

6 existing lines in 4 files now uncovered.

5067 of 7726 relevant lines covered (65.58%)

0.66 hits per line

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

83.21
/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
      } else {
177
        // seperator value not likely to appear in a database
178
        keyBuffer.append(KEY_SEPARATOR);
1✔
179
        return keyBuffer.toString();
1✔
180
      }
181
    } else {
182
      return null;
1✔
183
    }
184
  }
185

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

398
    Map props = new HashMap<>();
1✔
399
    props.put("map", this);
1✔
400
    dataExchange = getDelegate().getDataExchangeFactory().getDataExchangeForClass(resultClass);
1✔
401
    dataExchange.initialize(props);
1✔
402
  }
1✔
403

404
  /**
405
   * Getter for the number of ResultMapping objects.
406
   *
407
   * @return - the count
408
   */
409
  public int getResultCount() {
410
    return this.getResultMappings().length;
×
411
  }
412

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

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

470
    statementScope.setRowDataFound(foundData);
1✔
471

472
    return columnValues;
1✔
473
  }
474

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

516
    statementScope.setCurrentNestedKey(previousNestedKey);
1✔
517
    return resultObject;
1✔
518
  }
519

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

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

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

568
      Class type = mapping.getJavaType();
1✔
569
      String propertyName = mapping.getPropertyName();
1✔
570

571
      Object obj = PROBE.getObject(resultObject, propertyName);
1✔
572

573
      if (obj == null) {
1✔
574
        if (type == null) {
1!
575
          type = PROBE.getPropertyTypeForSetter(resultObject, propertyName);
1✔
576
        }
577

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

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

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

642
      String statementName = mapping.getStatementName();
1✔
643
      SqlMapClientImpl client = (SqlMapClientImpl) statementScope.getSession().getSqlMapClient();
1✔
644

645
      MappedStatement mappedStatement = client.getMappedStatement(statementName);
1✔
646
      Class parameterType = mappedStatement.getParameterClass();
1✔
647
      Object parameterObject = null;
1✔
648

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

661
      Object result = null;
1✔
662
      if (parameterObject != null) {
1!
663

664
        Sql sql = mappedStatement.getSql();
1✔
665
        ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);
1✔
666
        Class resultClass = resultMap.getResultClass();
1✔
667

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

676
        result = ResultLoader.loadResult(client, statementName, parameterObject, targetType);
1✔
677

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

691
  }
692

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

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

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

751
    Document doc = newDocument("parameter");
1✔
752
    Probe probe = ProbeFactory.getProbe(doc);
1✔
753

754
    String complexName = mapping.getColumnName();
1✔
755

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

772
    return doc;
1✔
773
  }
774

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

800
    Object parameterObject;
801
    if (parameterType == null) {
1!
NEW
802
      parameterObject = new HashMap<>();
×
803
    } else {
804
      parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(parameterType);
1✔
805
    }
806
    String complexName = mapping.getColumnName();
1✔
807

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

827
    return parameterObject;
1✔
828
  }
829

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

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