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

mybatis / mybatis-3 / #3591

18 Apr 2024 02:57PM UTC coverage: 87.132% (-0.04%) from 87.168%
#3591

Pull #3146

github

web-flow
Merge b16b4d1fd into 7ae38a258
Pull Request #3146: Shared ambiguity instance

3535 of 4283 branches covered (82.54%)

9385 of 10771 relevant lines covered (87.13%)

0.87 hits per line

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

88.78
/src/main/java/org/apache/ibatis/session/Configuration.java
1
/*
2
 *    Copyright 2009-2024 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.apache.ibatis.session;
17

18
import java.util.Arrays;
19
import java.util.Collection;
20
import java.util.HashMap;
21
import java.util.HashSet;
22
import java.util.Iterator;
23
import java.util.LinkedList;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.Properties;
27
import java.util.Set;
28
import java.util.concurrent.ConcurrentHashMap;
29
import java.util.concurrent.locks.ReentrantLock;
30
import java.util.function.BiFunction;
31

32
import org.apache.ibatis.binding.MapperRegistry;
33
import org.apache.ibatis.builder.CacheRefResolver;
34
import org.apache.ibatis.builder.IncompleteElementException;
35
import org.apache.ibatis.builder.ResultMapResolver;
36
import org.apache.ibatis.builder.annotation.MethodResolver;
37
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
38
import org.apache.ibatis.cache.Cache;
39
import org.apache.ibatis.cache.decorators.FifoCache;
40
import org.apache.ibatis.cache.decorators.LruCache;
41
import org.apache.ibatis.cache.decorators.SoftCache;
42
import org.apache.ibatis.cache.decorators.WeakCache;
43
import org.apache.ibatis.cache.impl.PerpetualCache;
44
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
45
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
46
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
47
import org.apache.ibatis.executor.BatchExecutor;
48
import org.apache.ibatis.executor.CachingExecutor;
49
import org.apache.ibatis.executor.Executor;
50
import org.apache.ibatis.executor.ReuseExecutor;
51
import org.apache.ibatis.executor.SimpleExecutor;
52
import org.apache.ibatis.executor.keygen.KeyGenerator;
53
import org.apache.ibatis.executor.loader.ProxyFactory;
54
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
55
import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
56
import org.apache.ibatis.executor.parameter.ParameterHandler;
57
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
58
import org.apache.ibatis.executor.resultset.ResultSetHandler;
59
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
60
import org.apache.ibatis.executor.statement.StatementHandler;
61
import org.apache.ibatis.io.VFS;
62
import org.apache.ibatis.logging.Log;
63
import org.apache.ibatis.logging.LogFactory;
64
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
65
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
66
import org.apache.ibatis.logging.log4j.Log4jImpl;
67
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
68
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
69
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
70
import org.apache.ibatis.logging.stdout.StdOutImpl;
71
import org.apache.ibatis.mapping.BoundSql;
72
import org.apache.ibatis.mapping.Environment;
73
import org.apache.ibatis.mapping.MappedStatement;
74
import org.apache.ibatis.mapping.ParameterMap;
75
import org.apache.ibatis.mapping.ResultMap;
76
import org.apache.ibatis.mapping.ResultSetType;
77
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
78
import org.apache.ibatis.parsing.XNode;
79
import org.apache.ibatis.plugin.Interceptor;
80
import org.apache.ibatis.plugin.InterceptorChain;
81
import org.apache.ibatis.reflection.DefaultReflectorFactory;
82
import org.apache.ibatis.reflection.MetaObject;
83
import org.apache.ibatis.reflection.ReflectorFactory;
84
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
85
import org.apache.ibatis.reflection.factory.ObjectFactory;
86
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
87
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
88
import org.apache.ibatis.scripting.LanguageDriver;
89
import org.apache.ibatis.scripting.LanguageDriverRegistry;
90
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
91
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
92
import org.apache.ibatis.transaction.Transaction;
93
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
94
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
95
import org.apache.ibatis.type.JdbcType;
96
import org.apache.ibatis.type.TypeAliasRegistry;
97
import org.apache.ibatis.type.TypeHandler;
98
import org.apache.ibatis.type.TypeHandlerRegistry;
99

100
/**
101
 * @author Clinton Begin
102
 */
103
public class Configuration {
104

105
  protected Environment environment;
106

107
  protected boolean safeRowBoundsEnabled;
108
  protected boolean safeResultHandlerEnabled = true;
1✔
109
  protected boolean mapUnderscoreToCamelCase;
110
  protected boolean aggressiveLazyLoading;
111
  protected boolean multipleResultSetsEnabled = true;
1✔
112
  protected boolean useGeneratedKeys;
113
  protected boolean useColumnLabel = true;
1✔
114
  protected boolean cacheEnabled = true;
1✔
115
  protected boolean callSettersOnNulls;
116
  protected boolean useActualParamName = true;
1✔
117
  protected boolean returnInstanceForEmptyRow;
118
  protected boolean shrinkWhitespacesInSql;
119
  protected boolean nullableOnForEach;
120
  protected boolean argNameBasedConstructorAutoMapping;
121

122
  protected String logPrefix;
123
  protected Class<? extends Log> logImpl;
124
  protected Class<? extends VFS> vfsImpl;
125
  protected Class<?> defaultSqlProviderType;
126
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
1✔
127
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
1✔
128
  protected Set<String> lazyLoadTriggerMethods = new HashSet<>(
1✔
129
      Arrays.asList("equals", "clone", "hashCode", "toString"));
1✔
130
  protected Integer defaultStatementTimeout;
131
  protected Integer defaultFetchSize;
132
  protected ResultSetType defaultResultSetType;
133
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
1✔
134
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
1✔
135
  protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
1✔
136

137
  protected Properties variables = new Properties();
1✔
138
  protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
1✔
139
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
1✔
140
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
1✔
141

142
  protected boolean lazyLoadingEnabled;
143
  protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
1✔
144

145
  protected String databaseId;
146
  /**
147
   * Configuration factory class. Used to create Configuration for loading deserialized unread properties.
148
   *
149
   * @see <a href='https://github.com/mybatis/old-google-code-issues/issues/300'>Issue 300 (google code)</a>
150
   */
151
  protected Class<?> configurationFactory;
152

153
  protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
1✔
154
  protected final InterceptorChain interceptorChain = new InterceptorChain();
1✔
155
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
1✔
156
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
1✔
157
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
1✔
158

159
  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
1✔
160
      "Mapped Statements collection")
161
          .conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and "
1✔
162
              + targetValue.getResource());
1✔
163
  protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
1✔
164
  protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
1✔
165
  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
1✔
166
  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
1✔
167

168
  protected final Set<String> loadedResources = new HashSet<>();
1✔
169
  protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
1✔
170
  protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
1✔
171
  protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
1✔
172
  protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
1✔
173
  protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();
1✔
174

175
  private final ReentrantLock incompleteResultMapsLock = new ReentrantLock();
1✔
176
  private final ReentrantLock incompleteCacheRefsLock = new ReentrantLock();
1✔
177
  private final ReentrantLock incompleteStatementsLock = new ReentrantLock();
1✔
178
  private final ReentrantLock incompleteMethodsLock = new ReentrantLock();
1✔
179

180
  /*
181
   * A map holds cache-ref relationship. The key is the namespace that references a cache bound to another namespace and
182
   * the value is the namespace which the actual cache is bound to.
183
   */
184
  protected final Map<String, String> cacheRefMap = new HashMap<>();
1✔
185

186
  public Configuration(Environment environment) {
187
    this();
1✔
188
    this.environment = environment;
1✔
189
  }
1✔
190

191
  public Configuration() {
1✔
192
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
1✔
193
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
1✔
194

195
    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
1✔
196
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
1✔
197
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
1✔
198

199
    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
1✔
200
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
1✔
201
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
1✔
202
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
1✔
203
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
1✔
204

205
    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
1✔
206

207
    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
1✔
208
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
1✔
209

210
    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
1✔
211
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
1✔
212
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
1✔
213
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
1✔
214
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
1✔
215
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
1✔
216
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
1✔
217

218
    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
1✔
219
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
1✔
220

221
    languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
1✔
222
    languageRegistry.register(RawLanguageDriver.class);
1✔
223
  }
1✔
224

225
  public String getLogPrefix() {
226
    return logPrefix;
1✔
227
  }
228

229
  public void setLogPrefix(String logPrefix) {
230
    this.logPrefix = logPrefix;
1✔
231
  }
1✔
232

233
  public Class<? extends Log> getLogImpl() {
234
    return logImpl;
1✔
235
  }
236

237
  public void setLogImpl(Class<? extends Log> logImpl) {
238
    if (logImpl != null) {
1✔
239
      this.logImpl = logImpl;
1✔
240
      LogFactory.useCustomLogging(this.logImpl);
1✔
241
    }
242
  }
1✔
243

244
  public Class<? extends VFS> getVfsImpl() {
245
    return this.vfsImpl;
×
246
  }
247

248
  public void setVfsImpl(Class<? extends VFS> vfsImpl) {
249
    if (vfsImpl != null) {
×
250
      this.vfsImpl = vfsImpl;
×
251
      VFS.addImplClass(this.vfsImpl);
×
252
    }
253
  }
×
254

255
  /**
256
   * Gets an applying type when omit a type on sql provider annotation(e.g.
257
   * {@link org.apache.ibatis.annotations.SelectProvider}).
258
   *
259
   * @return the default type for sql provider annotation
260
   *
261
   * @since 3.5.6
262
   */
263
  public Class<?> getDefaultSqlProviderType() {
264
    return defaultSqlProviderType;
1✔
265
  }
266

267
  /**
268
   * Sets an applying type when omit a type on sql provider annotation(e.g.
269
   * {@link org.apache.ibatis.annotations.SelectProvider}).
270
   *
271
   * @param defaultSqlProviderType
272
   *          the default type for sql provider annotation
273
   *
274
   * @since 3.5.6
275
   */
276
  public void setDefaultSqlProviderType(Class<?> defaultSqlProviderType) {
277
    this.defaultSqlProviderType = defaultSqlProviderType;
1✔
278
  }
1✔
279

280
  public boolean isCallSettersOnNulls() {
281
    return callSettersOnNulls;
1✔
282
  }
283

284
  public void setCallSettersOnNulls(boolean callSettersOnNulls) {
285
    this.callSettersOnNulls = callSettersOnNulls;
1✔
286
  }
1✔
287

288
  public boolean isUseActualParamName() {
289
    return useActualParamName;
1✔
290
  }
291

292
  public void setUseActualParamName(boolean useActualParamName) {
293
    this.useActualParamName = useActualParamName;
1✔
294
  }
1✔
295

296
  public boolean isReturnInstanceForEmptyRow() {
297
    return returnInstanceForEmptyRow;
1✔
298
  }
299

300
  public void setReturnInstanceForEmptyRow(boolean returnEmptyInstance) {
301
    this.returnInstanceForEmptyRow = returnEmptyInstance;
1✔
302
  }
1✔
303

304
  public boolean isShrinkWhitespacesInSql() {
305
    return shrinkWhitespacesInSql;
1✔
306
  }
307

308
  public void setShrinkWhitespacesInSql(boolean shrinkWhitespacesInSql) {
309
    this.shrinkWhitespacesInSql = shrinkWhitespacesInSql;
1✔
310
  }
1✔
311

312
  /**
313
   * Sets the default value of 'nullable' attribute on 'foreach' tag.
314
   *
315
   * @param nullableOnForEach
316
   *          If nullable, set to {@code true}
317
   *
318
   * @since 3.5.9
319
   */
320
  public void setNullableOnForEach(boolean nullableOnForEach) {
321
    this.nullableOnForEach = nullableOnForEach;
1✔
322
  }
1✔
323

324
  /**
325
   * Returns the default value of 'nullable' attribute on 'foreach' tag.
326
   * <p>
327
   * Default is {@code false}.
328
   *
329
   * @return If nullable, set to {@code true}
330
   *
331
   * @since 3.5.9
332
   */
333
  public boolean isNullableOnForEach() {
334
    return nullableOnForEach;
1✔
335
  }
336

337
  public boolean isArgNameBasedConstructorAutoMapping() {
338
    return argNameBasedConstructorAutoMapping;
1✔
339
  }
340

341
  public void setArgNameBasedConstructorAutoMapping(boolean argNameBasedConstructorAutoMapping) {
342
    this.argNameBasedConstructorAutoMapping = argNameBasedConstructorAutoMapping;
1✔
343
  }
1✔
344

345
  public String getDatabaseId() {
346
    return databaseId;
1✔
347
  }
348

349
  public void setDatabaseId(String databaseId) {
350
    this.databaseId = databaseId;
1✔
351
  }
1✔
352

353
  public Class<?> getConfigurationFactory() {
354
    return configurationFactory;
1✔
355
  }
356

357
  public void setConfigurationFactory(Class<?> configurationFactory) {
358
    this.configurationFactory = configurationFactory;
1✔
359
  }
1✔
360

361
  public boolean isSafeResultHandlerEnabled() {
362
    return safeResultHandlerEnabled;
1✔
363
  }
364

365
  public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
366
    this.safeResultHandlerEnabled = safeResultHandlerEnabled;
1✔
367
  }
1✔
368

369
  public boolean isSafeRowBoundsEnabled() {
370
    return safeRowBoundsEnabled;
1✔
371
  }
372

373
  public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
374
    this.safeRowBoundsEnabled = safeRowBoundsEnabled;
1✔
375
  }
1✔
376

377
  public boolean isMapUnderscoreToCamelCase() {
378
    return mapUnderscoreToCamelCase;
1✔
379
  }
380

381
  public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
382
    this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
1✔
383
  }
1✔
384

385
  public void addLoadedResource(String resource) {
386
    loadedResources.add(resource);
1✔
387
  }
1✔
388

389
  public boolean isResourceLoaded(String resource) {
390
    return loadedResources.contains(resource);
1✔
391
  }
392

393
  public Environment getEnvironment() {
394
    return environment;
1✔
395
  }
396

397
  public void setEnvironment(Environment environment) {
398
    this.environment = environment;
1✔
399
  }
1✔
400

401
  public AutoMappingBehavior getAutoMappingBehavior() {
402
    return autoMappingBehavior;
1✔
403
  }
404

405
  public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
406
    this.autoMappingBehavior = autoMappingBehavior;
1✔
407
  }
1✔
408

409
  /**
410
   * Gets the auto mapping unknown column behavior.
411
   *
412
   * @return the auto mapping unknown column behavior
413
   *
414
   * @since 3.4.0
415
   */
416
  public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
417
    return autoMappingUnknownColumnBehavior;
1✔
418
  }
419

420
  /**
421
   * Sets the auto mapping unknown column behavior.
422
   *
423
   * @param autoMappingUnknownColumnBehavior
424
   *          the new auto mapping unknown column behavior
425
   *
426
   * @since 3.4.0
427
   */
428
  public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
429
    this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
1✔
430
  }
1✔
431

432
  public boolean isLazyLoadingEnabled() {
433
    return lazyLoadingEnabled;
1✔
434
  }
435

436
  public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
437
    this.lazyLoadingEnabled = lazyLoadingEnabled;
1✔
438
  }
1✔
439

440
  public ProxyFactory getProxyFactory() {
441
    return proxyFactory;
1✔
442
  }
443

444
  public void setProxyFactory(ProxyFactory proxyFactory) {
445
    if (proxyFactory == null) {
1✔
446
      proxyFactory = new JavassistProxyFactory();
1✔
447
    }
448
    this.proxyFactory = proxyFactory;
1✔
449
  }
1✔
450

451
  public boolean isAggressiveLazyLoading() {
452
    return aggressiveLazyLoading;
1✔
453
  }
454

455
  public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
456
    this.aggressiveLazyLoading = aggressiveLazyLoading;
1✔
457
  }
1✔
458

459
  public boolean isMultipleResultSetsEnabled() {
460
    return multipleResultSetsEnabled;
1✔
461
  }
462

463
  public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
464
    this.multipleResultSetsEnabled = multipleResultSetsEnabled;
1✔
465
  }
1✔
466

467
  public Set<String> getLazyLoadTriggerMethods() {
468
    return lazyLoadTriggerMethods;
1✔
469
  }
470

471
  public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
472
    this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
1✔
473
  }
1✔
474

475
  public boolean isUseGeneratedKeys() {
476
    return useGeneratedKeys;
1✔
477
  }
478

479
  public void setUseGeneratedKeys(boolean useGeneratedKeys) {
480
    this.useGeneratedKeys = useGeneratedKeys;
1✔
481
  }
1✔
482

483
  public ExecutorType getDefaultExecutorType() {
484
    return defaultExecutorType;
1✔
485
  }
486

487
  public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
488
    this.defaultExecutorType = defaultExecutorType;
1✔
489
  }
1✔
490

491
  public boolean isCacheEnabled() {
492
    return cacheEnabled;
1✔
493
  }
494

495
  public void setCacheEnabled(boolean cacheEnabled) {
496
    this.cacheEnabled = cacheEnabled;
1✔
497
  }
1✔
498

499
  public Integer getDefaultStatementTimeout() {
500
    return defaultStatementTimeout;
1✔
501
  }
502

503
  public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
504
    this.defaultStatementTimeout = defaultStatementTimeout;
1✔
505
  }
1✔
506

507
  /**
508
   * Gets the default fetch size.
509
   *
510
   * @return the default fetch size
511
   *
512
   * @since 3.3.0
513
   */
514
  public Integer getDefaultFetchSize() {
515
    return defaultFetchSize;
1✔
516
  }
517

518
  /**
519
   * Sets the default fetch size.
520
   *
521
   * @param defaultFetchSize
522
   *          the new default fetch size
523
   *
524
   * @since 3.3.0
525
   */
526
  public void setDefaultFetchSize(Integer defaultFetchSize) {
527
    this.defaultFetchSize = defaultFetchSize;
1✔
528
  }
1✔
529

530
  /**
531
   * Gets the default result set type.
532
   *
533
   * @return the default result set type
534
   *
535
   * @since 3.5.2
536
   */
537
  public ResultSetType getDefaultResultSetType() {
538
    return defaultResultSetType;
1✔
539
  }
540

541
  /**
542
   * Sets the default result set type.
543
   *
544
   * @param defaultResultSetType
545
   *          the new default result set type
546
   *
547
   * @since 3.5.2
548
   */
549
  public void setDefaultResultSetType(ResultSetType defaultResultSetType) {
550
    this.defaultResultSetType = defaultResultSetType;
1✔
551
  }
1✔
552

553
  public boolean isUseColumnLabel() {
554
    return useColumnLabel;
1✔
555
  }
556

557
  public void setUseColumnLabel(boolean useColumnLabel) {
558
    this.useColumnLabel = useColumnLabel;
1✔
559
  }
1✔
560

561
  public LocalCacheScope getLocalCacheScope() {
562
    return localCacheScope;
1✔
563
  }
564

565
  public void setLocalCacheScope(LocalCacheScope localCacheScope) {
566
    this.localCacheScope = localCacheScope;
1✔
567
  }
1✔
568

569
  public JdbcType getJdbcTypeForNull() {
570
    return jdbcTypeForNull;
1✔
571
  }
572

573
  public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
574
    this.jdbcTypeForNull = jdbcTypeForNull;
1✔
575
  }
1✔
576

577
  public Properties getVariables() {
578
    return variables;
1✔
579
  }
580

581
  public void setVariables(Properties variables) {
582
    this.variables = variables;
1✔
583
  }
1✔
584

585
  public TypeHandlerRegistry getTypeHandlerRegistry() {
586
    return typeHandlerRegistry;
1✔
587
  }
588

589
  /**
590
   * Set a default {@link TypeHandler} class for {@link Enum}. A default {@link TypeHandler} is
591
   * {@link org.apache.ibatis.type.EnumTypeHandler}.
592
   *
593
   * @param typeHandler
594
   *          a type handler class for {@link Enum}
595
   *
596
   * @since 3.4.5
597
   */
598
  public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {
599
    if (typeHandler != null) {
1!
600
      getTypeHandlerRegistry().setDefaultEnumTypeHandler(typeHandler);
×
601
    }
602
  }
1✔
603

604
  public TypeAliasRegistry getTypeAliasRegistry() {
605
    return typeAliasRegistry;
1✔
606
  }
607

608
  /**
609
   * Gets the mapper registry.
610
   *
611
   * @return the mapper registry
612
   *
613
   * @since 3.2.2
614
   */
615
  public MapperRegistry getMapperRegistry() {
616
    return mapperRegistry;
1✔
617
  }
618

619
  public ReflectorFactory getReflectorFactory() {
620
    return reflectorFactory;
1✔
621
  }
622

623
  public void setReflectorFactory(ReflectorFactory reflectorFactory) {
624
    this.reflectorFactory = reflectorFactory;
×
625
  }
×
626

627
  public ObjectFactory getObjectFactory() {
628
    return objectFactory;
1✔
629
  }
630

631
  public void setObjectFactory(ObjectFactory objectFactory) {
632
    this.objectFactory = objectFactory;
1✔
633
  }
1✔
634

635
  public ObjectWrapperFactory getObjectWrapperFactory() {
636
    return objectWrapperFactory;
1✔
637
  }
638

639
  public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
640
    this.objectWrapperFactory = objectWrapperFactory;
1✔
641
  }
1✔
642

643
  /**
644
   * Gets the interceptors.
645
   *
646
   * @return the interceptors
647
   *
648
   * @since 3.2.2
649
   */
650
  public List<Interceptor> getInterceptors() {
651
    return interceptorChain.getInterceptors();
×
652
  }
653

654
  public LanguageDriverRegistry getLanguageRegistry() {
655
    return languageRegistry;
1✔
656
  }
657

658
  public void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {
659
    if (driver == null) {
1✔
660
      driver = XMLLanguageDriver.class;
1✔
661
    }
662
    getLanguageRegistry().setDefaultDriverClass(driver);
1✔
663
  }
1✔
664

665
  public LanguageDriver getDefaultScriptingLanguageInstance() {
666
    return languageRegistry.getDefaultDriver();
1✔
667
  }
668

669
  /**
670
   * Gets the language driver.
671
   *
672
   * @param langClass
673
   *          the lang class
674
   *
675
   * @return the language driver
676
   *
677
   * @since 3.5.1
678
   */
679
  public LanguageDriver getLanguageDriver(Class<? extends LanguageDriver> langClass) {
680
    if (langClass == null) {
1✔
681
      return languageRegistry.getDefaultDriver();
1✔
682
    }
683
    languageRegistry.register(langClass);
1✔
684
    return languageRegistry.getDriver(langClass);
1✔
685
  }
686

687
  /**
688
   * Gets the default scripting language instance.
689
   *
690
   * @return the default scripting language instance
691
   *
692
   * @deprecated Use {@link #getDefaultScriptingLanguageInstance()}
693
   */
694
  @Deprecated
695
  public LanguageDriver getDefaultScriptingLanuageInstance() {
696
    return getDefaultScriptingLanguageInstance();
1✔
697
  }
698

699
  public MetaObject newMetaObject(Object object) {
700
    return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
1✔
701
  }
702

703
  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
704
      BoundSql boundSql) {
705
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
1✔
706
        parameterObject, boundSql);
707
    return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
1✔
708
  }
709

710
  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
711
      ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
712
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
1✔
713
        resultHandler, boundSql, rowBounds);
714
    return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
1✔
715
  }
716

717
  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
718
      Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
719
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
1✔
720
        rowBounds, resultHandler, boundSql);
721
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
1✔
722
  }
723

724
  public Executor newExecutor(Transaction transaction) {
725
    return newExecutor(transaction, defaultExecutorType);
×
726
  }
727

728
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
729
    executorType = executorType == null ? defaultExecutorType : executorType;
1!
730
    Executor executor;
731
    if (ExecutorType.BATCH == executorType) {
1✔
732
      executor = new BatchExecutor(this, transaction);
1✔
733
    } else if (ExecutorType.REUSE == executorType) {
1✔
734
      executor = new ReuseExecutor(this, transaction);
1✔
735
    } else {
736
      executor = new SimpleExecutor(this, transaction);
1✔
737
    }
738
    if (cacheEnabled) {
1!
739
      executor = new CachingExecutor(executor);
1✔
740
    }
741
    return (Executor) interceptorChain.pluginAll(executor);
1✔
742
  }
743

744
  public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
745
    keyGenerators.put(id, keyGenerator);
1✔
746
  }
1✔
747

748
  public Collection<String> getKeyGeneratorNames() {
749
    return keyGenerators.keySet();
×
750
  }
751

752
  public Collection<KeyGenerator> getKeyGenerators() {
753
    return keyGenerators.values();
×
754
  }
755

756
  public KeyGenerator getKeyGenerator(String id) {
757
    return keyGenerators.get(id);
1✔
758
  }
759

760
  public boolean hasKeyGenerator(String id) {
761
    return keyGenerators.containsKey(id);
1✔
762
  }
763

764
  public void addCache(Cache cache) {
765
    caches.put(cache.getId(), cache);
1✔
766
  }
1✔
767

768
  public Collection<String> getCacheNames() {
769
    return caches.keySet();
×
770
  }
771

772
  public Collection<Cache> getCaches() {
773
    return caches.values();
×
774
  }
775

776
  public Cache getCache(String id) {
777
    return caches.get(id);
1✔
778
  }
779

780
  public boolean hasCache(String id) {
781
    return caches.containsKey(id);
×
782
  }
783

784
  public void addResultMap(ResultMap rm) {
785
    resultMaps.put(rm.getId(), rm);
1✔
786
    checkLocallyForDiscriminatedNestedResultMaps(rm);
1✔
787
    checkGloballyForDiscriminatedNestedResultMaps(rm);
1✔
788
  }
1✔
789

790
  public Collection<String> getResultMapNames() {
791
    return resultMaps.keySet();
×
792
  }
793

794
  public Collection<ResultMap> getResultMaps() {
795
    return resultMaps.values();
1✔
796
  }
797

798
  public ResultMap getResultMap(String id) {
799
    return resultMaps.get(id);
1✔
800
  }
801

802
  public boolean hasResultMap(String id) {
803
    return resultMaps.containsKey(id);
1✔
804
  }
805

806
  public void addParameterMap(ParameterMap pm) {
807
    parameterMaps.put(pm.getId(), pm);
1✔
808
  }
1✔
809

810
  public Collection<String> getParameterMapNames() {
811
    return parameterMaps.keySet();
×
812
  }
813

814
  public Collection<ParameterMap> getParameterMaps() {
815
    return parameterMaps.values();
×
816
  }
817

818
  public ParameterMap getParameterMap(String id) {
819
    return parameterMaps.get(id);
1✔
820
  }
821

822
  public boolean hasParameterMap(String id) {
823
    return parameterMaps.containsKey(id);
×
824
  }
825

826
  public void addMappedStatement(MappedStatement ms) {
827
    mappedStatements.put(ms.getId(), ms);
1✔
828
  }
1✔
829

830
  public Collection<String> getMappedStatementNames() {
831
    buildAllStatements();
1✔
832
    return mappedStatements.keySet();
1✔
833
  }
834

835
  public Collection<MappedStatement> getMappedStatements() {
836
    buildAllStatements();
×
837
    return mappedStatements.values();
×
838
  }
839

840
  /**
841
   * @deprecated call {@link #parsePendingStatements(boolean)}
842
   */
843
  @Deprecated
844
  public Collection<XMLStatementBuilder> getIncompleteStatements() {
845
    return incompleteStatements;
×
846
  }
847

848
  public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
849
    incompleteStatementsLock.lock();
1✔
850
    try {
851
      incompleteStatements.add(incompleteStatement);
1✔
852
    } finally {
853
      incompleteStatementsLock.unlock();
1✔
854
    }
855
  }
1✔
856

857
  /**
858
   * @deprecated call {@link #parsePendingCacheRefs(boolean)}
859
   */
860
  @Deprecated
861
  public Collection<CacheRefResolver> getIncompleteCacheRefs() {
862
    return incompleteCacheRefs;
×
863
  }
864

865
  public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
866
    incompleteCacheRefsLock.lock();
1✔
867
    try {
868
      incompleteCacheRefs.add(incompleteCacheRef);
1✔
869
    } finally {
870
      incompleteCacheRefsLock.unlock();
1✔
871
    }
872
  }
1✔
873

874
  /**
875
   * @deprecated call {@link #parsePendingResultMaps(boolean)}
876
   */
877
  @Deprecated
878
  public Collection<ResultMapResolver> getIncompleteResultMaps() {
879
    return incompleteResultMaps;
×
880
  }
881

882
  public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
883
    incompleteResultMapsLock.lock();
1✔
884
    try {
885
      incompleteResultMaps.add(resultMapResolver);
1✔
886
    } finally {
887
      incompleteResultMapsLock.unlock();
1✔
888
    }
889
  }
1✔
890

891
  public void addIncompleteMethod(MethodResolver builder) {
892
    incompleteMethodsLock.lock();
1✔
893
    try {
894
      incompleteMethods.add(builder);
1✔
895
    } finally {
896
      incompleteMethodsLock.unlock();
1✔
897
    }
898
  }
1✔
899

900
  /**
901
   * @deprecated call {@link #parsePendingMethods(boolean)}
902
   */
903
  @Deprecated
904
  public Collection<MethodResolver> getIncompleteMethods() {
905
    return incompleteMethods;
×
906
  }
907

908
  public MappedStatement getMappedStatement(String id) {
909
    return this.getMappedStatement(id, true);
1✔
910
  }
911

912
  public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
913
    if (validateIncompleteStatements) {
1✔
914
      buildAllStatements();
1✔
915
    }
916
    return mappedStatements.get(id);
1✔
917
  }
918

919
  public Map<String, XNode> getSqlFragments() {
920
    return sqlFragments;
1✔
921
  }
922

923
  public void addInterceptor(Interceptor interceptor) {
924
    interceptorChain.addInterceptor(interceptor);
1✔
925
  }
1✔
926

927
  public void addMappers(String packageName, Class<?> superType) {
928
    mapperRegistry.addMappers(packageName, superType);
×
929
  }
×
930

931
  public void addMappers(String packageName) {
932
    mapperRegistry.addMappers(packageName);
1✔
933
  }
1✔
934

935
  public <T> void addMapper(Class<T> type) {
936
    mapperRegistry.addMapper(type);
1✔
937
  }
1✔
938

939
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
940
    return mapperRegistry.getMapper(type, sqlSession);
1✔
941
  }
942

943
  public boolean hasMapper(Class<?> type) {
944
    return mapperRegistry.hasMapper(type);
1✔
945
  }
946

947
  public boolean hasStatement(String statementName) {
948
    return hasStatement(statementName, true);
1✔
949
  }
950

951
  public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
952
    if (validateIncompleteStatements) {
1✔
953
      buildAllStatements();
1✔
954
    }
955
    return mappedStatements.containsKey(statementName);
1✔
956
  }
957

958
  public void addCacheRef(String namespace, String referencedNamespace) {
959
    cacheRefMap.put(namespace, referencedNamespace);
1✔
960
  }
1✔
961

962
  /*
963
   * Parses all the unprocessed statement nodes in the cache. It is recommended to call this method once all the mappers
964
   * are added as it provides fail-fast statement validation.
965
   */
966
  protected void buildAllStatements() {
967
    parsePendingResultMaps(true);
1✔
968
    parsePendingCacheRefs(true);
1✔
969
    parsePendingStatements(true);
1✔
970
    parsePendingMethods(true);
1✔
971
  }
1✔
972

973
  public void parsePendingMethods(boolean reportUnresolved) {
974
    if (incompleteMethods.isEmpty()) {
1✔
975
      return;
1✔
976
    }
977
    incompleteMethodsLock.lock();
1✔
978
    try {
979
      incompleteMethods.removeIf(x -> {
1✔
980
        x.resolve();
1✔
981
        return true;
1✔
982
      });
983
    } catch (IncompleteElementException e) {
1✔
984
      if (reportUnresolved) {
1!
985
        throw e;
×
986
      }
987
    } finally {
988
      incompleteMethodsLock.unlock();
1✔
989
    }
990
  }
1✔
991

992
  public void parsePendingStatements(boolean reportUnresolved) {
993
    if (incompleteStatements.isEmpty()) {
1✔
994
      return;
1✔
995
    }
996
    incompleteStatementsLock.lock();
1✔
997
    try {
998
      incompleteStatements.removeIf(x -> {
1✔
999
        x.parseStatementNode();
1✔
1000
        return true;
1✔
1001
      });
1002
    } catch (IncompleteElementException e) {
1✔
1003
      if (reportUnresolved) {
1✔
1004
        throw e;
1✔
1005
      }
1006
    } finally {
1007
      incompleteStatementsLock.unlock();
1✔
1008
    }
1009
  }
1✔
1010

1011
  public void parsePendingCacheRefs(boolean reportUnresolved) {
1012
    if (incompleteCacheRefs.isEmpty()) {
1✔
1013
      return;
1✔
1014
    }
1015
    incompleteCacheRefsLock.lock();
1✔
1016
    try {
1017
      incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
1!
1018
    } catch (IncompleteElementException e) {
1✔
1019
      if (reportUnresolved) {
1!
1020
        throw e;
×
1021
      }
1022
    } finally {
1023
      incompleteCacheRefsLock.unlock();
1✔
1024
    }
1025
  }
1✔
1026

1027
  public void parsePendingResultMaps(boolean reportUnresolved) {
1028
    if (incompleteResultMaps.isEmpty()) {
1✔
1029
      return;
1✔
1030
    }
1031
    incompleteResultMapsLock.lock();
1✔
1032
    try {
1033
      boolean resolved;
1034
      IncompleteElementException ex = null;
1✔
1035
      do {
1036
        resolved = false;
1✔
1037
        Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();
1✔
1038
        while (iterator.hasNext()) {
1✔
1039
          try {
1040
            iterator.next().resolve();
1✔
1041
            iterator.remove();
1✔
1042
            resolved = true;
1✔
1043
          } catch (IncompleteElementException e) {
1✔
1044
            ex = e;
1✔
1045
          }
1✔
1046
        }
1047
      } while (resolved);
1✔
1048
      if (reportUnresolved && !incompleteResultMaps.isEmpty() && ex != null) {
1!
1049
        // At least one result map is unresolvable.
1050
        throw ex;
×
1051
      }
1052
    } finally {
1053
      incompleteResultMapsLock.unlock();
1✔
1054
    }
1055
  }
1✔
1056

1057
  /**
1058
   * Extracts namespace from fully qualified statement id.
1059
   *
1060
   * @param statementId
1061
   *          the statement id
1062
   *
1063
   * @return namespace or null when id does not contain period.
1064
   */
1065
  protected String extractNamespace(String statementId) {
1066
    int lastPeriod = statementId.lastIndexOf('.');
×
1067
    return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
×
1068
  }
1069

1070
  // Slow but a one time cost. A better solution is welcome.
1071
  protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
1072
    if (rm.hasNestedResultMaps()) {
1✔
1073
      final String resultMapId = rm.getId();
1✔
1074
      for (Object resultMapObject : resultMaps.values()) {
1✔
1075
        if (resultMapObject instanceof ResultMap) {
1✔
1076
          ResultMap entryResultMap = (ResultMap) resultMapObject;
1✔
1077
          if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
1✔
1078
            Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap()
1✔
1079
                .values();
1✔
1080
            if (discriminatedResultMapNames.contains(resultMapId)) {
1!
1081
              entryResultMap.forceNestedResultMaps();
×
1082
            }
1083
          }
1084
        }
1085
      }
1✔
1086
    }
1087
  }
1✔
1088

1089
  // Slow but a one time cost. A better solution is welcome.
1090
  protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
1091
    if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
1✔
1092
      for (String discriminatedResultMapName : rm.getDiscriminator().getDiscriminatorMap().values()) {
1✔
1093
        if (hasResultMap(discriminatedResultMapName)) {
1✔
1094
          ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);
1✔
1095
          if (discriminatedResultMap.hasNestedResultMaps()) {
1✔
1096
            rm.forceNestedResultMaps();
1✔
1097
            break;
1✔
1098
          }
1099
        }
1100
      }
1✔
1101
    }
1102
  }
1✔
1103

1104
  protected static class StrictMap<V> extends ConcurrentHashMap<String, V> {
1105

1106
    private static final long serialVersionUID = -4950446264854982944L;
1107
    private final String name;
1108
    private BiFunction<V, V, String> conflictMessageProducer;
1109
    private static final Object AMBIGUITY_INSTANCE = new Object();
1✔
1110

1111
    public StrictMap(String name, int initialCapacity, float loadFactor) {
1112
      super(initialCapacity, loadFactor);
×
1113
      this.name = name;
×
1114
    }
×
1115

1116
    public StrictMap(String name, int initialCapacity) {
1117
      super(initialCapacity);
×
1118
      this.name = name;
×
1119
    }
×
1120

1121
    public StrictMap(String name) {
1✔
1122
      this.name = name;
1✔
1123
    }
1✔
1124

1125
    public StrictMap(String name, Map<String, ? extends V> m) {
1126
      super(m);
×
1127
      this.name = name;
×
1128
    }
×
1129

1130
    /**
1131
     * Assign a function for producing a conflict error message when contains value with the same key.
1132
     * <p>
1133
     * function arguments are 1st is saved value and 2nd is target value.
1134
     *
1135
     * @param conflictMessageProducer
1136
     *          A function for producing a conflict error message
1137
     *
1138
     * @return a conflict error message
1139
     *
1140
     * @since 3.5.0
1141
     */
1142
    public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {
1143
      this.conflictMessageProducer = conflictMessageProducer;
1✔
1144
      return this;
1✔
1145
    }
1146

1147
    @Override
1148
    @SuppressWarnings("unchecked")
1149
    public V put(String key, V value) {
1150
      if (containsKey(key)) {
1✔
1151
        throw new IllegalArgumentException(name + " already contains key " + key
1✔
1152
            + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
1✔
1153
      }
1154
      if (key.contains(".")) {
1✔
1155
        final String shortKey = getShortName(key);
1✔
1156
        if (super.get(shortKey) == null) {
1✔
1157
          super.put(shortKey, value);
1✔
1158
        } else {
1159
          super.put(shortKey, (V) AMBIGUITY_INSTANCE);
1✔
1160
        }
1161
      }
1162
      return super.put(key, value);
1✔
1163
    }
1164

1165
    @Override
1166
    public boolean containsKey(Object key) {
1167
      if (key == null) {
1✔
1168
        return false;
1✔
1169
      }
1170

1171
      return super.get(key) != null;
1✔
1172
    }
1173

1174
    @Override
1175
    public V get(Object key) {
1176
      V value = super.get(key);
1✔
1177
      if (value == null) {
1✔
1178
        throw new IllegalArgumentException(name + " does not contain value for " + key);
1✔
1179
      }
1180
      if (AMBIGUITY_INSTANCE == value) {
1✔
1181
        throw new IllegalArgumentException(key + " is ambiguous in " + name
1✔
1182
            + " (try using the full name including the namespace, or rename one of the entries)");
1183
      }
1184
      return value;
1✔
1185
    }
1186

1187
    /**
1188
     * remove class code
1189
     *
1190
     * @deprecated 3.5.17
1191
     */
1192
    @Deprecated
1193
    protected static class Ambiguity {
1194

1195
      private final String subject;
1196

1197
      public Ambiguity(String subject) {
×
1198
        this.subject = subject;
×
1199
      }
×
1200

1201
      public String getSubject() {
1202
        return subject;
×
1203
      }
1204
    }
1205

1206
    private String getShortName(String key) {
1207
      final String[] keyParts = key.split("\\.");
1✔
1208
      return keyParts[keyParts.length - 1];
1✔
1209
    }
1210
  }
1211

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