1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
102
103 public class Configuration {
104
105 protected Environment environment;
106
107 protected boolean safeRowBoundsEnabled;
108 protected boolean safeResultHandlerEnabled = true;
109 protected boolean mapUnderscoreToCamelCase;
110 protected boolean aggressiveLazyLoading;
111 protected boolean multipleResultSetsEnabled = true;
112 protected boolean useGeneratedKeys;
113 protected boolean useColumnLabel = true;
114 protected boolean cacheEnabled = true;
115 protected boolean callSettersOnNulls;
116 protected boolean useActualParamName = true;
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;
127 protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
128 protected Set<String> lazyLoadTriggerMethods = new HashSet<>(
129 Arrays.asList("equals", "clone", "hashCode", "toString"));
130 protected Integer defaultStatementTimeout;
131 protected Integer defaultFetchSize;
132 protected ResultSetType defaultResultSetType;
133 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
134 protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
135 protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
136
137 protected Properties variables = new Properties();
138 protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
139 protected ObjectFactory objectFactory = new DefaultObjectFactory();
140 protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
141
142 protected boolean lazyLoadingEnabled;
143 protected ProxyFactory proxyFactory = new JavassistProxyFactory();
144
145 protected String databaseId;
146
147
148
149
150
151 protected Class<?> configurationFactory;
152
153 protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
154 protected final InterceptorChain interceptorChain = new InterceptorChain();
155 protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
156 protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
157 protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
158
159 protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
160 "Mapped Statements collection")
161 .conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and "
162 + targetValue.getResource());
163 protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
164 protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
165 protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
166 protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
167
168 protected final Set<String> loadedResources = new HashSet<>();
169 protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
170 protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
171 protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
172 protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
173 protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();
174
175 private final ReentrantLock incompleteResultMapsLock = new ReentrantLock();
176 private final ReentrantLock incompleteCacheRefsLock = new ReentrantLock();
177 private final ReentrantLock incompleteStatementsLock = new ReentrantLock();
178 private final ReentrantLock incompleteMethodsLock = new ReentrantLock();
179
180
181
182
183
184 protected final Map<String, String> cacheRefMap = new HashMap<>();
185
186 public Configuration(Environment environment) {
187 this();
188 this.environment = environment;
189 }
190
191 public Configuration() {
192 typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
193 typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
194
195 typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
196 typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
197 typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
198
199 typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
200 typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
201 typeAliasRegistry.registerAlias("LRU", LruCache.class);
202 typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
203 typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
204
205 typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
206
207 typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
208 typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
209
210 typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
211 typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
212 typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
213 typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
214 typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
215 typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
216 typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
217
218 typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
219 typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
220
221 languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
222 languageRegistry.register(RawLanguageDriver.class);
223 }
224
225 public String getLogPrefix() {
226 return logPrefix;
227 }
228
229 public void setLogPrefix(String logPrefix) {
230 this.logPrefix = logPrefix;
231 }
232
233 public Class<? extends Log> getLogImpl() {
234 return logImpl;
235 }
236
237 public void setLogImpl(Class<? extends Log> logImpl) {
238 if (logImpl != null) {
239 this.logImpl = logImpl;
240 LogFactory.useCustomLogging(this.logImpl);
241 }
242 }
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
257
258
259
260
261
262
263 public Class<?> getDefaultSqlProviderType() {
264 return defaultSqlProviderType;
265 }
266
267
268
269
270
271
272
273
274
275
276 public void setDefaultSqlProviderType(Class<?> defaultSqlProviderType) {
277 this.defaultSqlProviderType = defaultSqlProviderType;
278 }
279
280 public boolean isCallSettersOnNulls() {
281 return callSettersOnNulls;
282 }
283
284 public void setCallSettersOnNulls(boolean callSettersOnNulls) {
285 this.callSettersOnNulls = callSettersOnNulls;
286 }
287
288 public boolean isUseActualParamName() {
289 return useActualParamName;
290 }
291
292 public void setUseActualParamName(boolean useActualParamName) {
293 this.useActualParamName = useActualParamName;
294 }
295
296 public boolean isReturnInstanceForEmptyRow() {
297 return returnInstanceForEmptyRow;
298 }
299
300 public void setReturnInstanceForEmptyRow(boolean returnEmptyInstance) {
301 this.returnInstanceForEmptyRow = returnEmptyInstance;
302 }
303
304 public boolean isShrinkWhitespacesInSql() {
305 return shrinkWhitespacesInSql;
306 }
307
308 public void setShrinkWhitespacesInSql(boolean shrinkWhitespacesInSql) {
309 this.shrinkWhitespacesInSql = shrinkWhitespacesInSql;
310 }
311
312
313
314
315
316
317
318
319
320 public void setNullableOnForEach(boolean nullableOnForEach) {
321 this.nullableOnForEach = nullableOnForEach;
322 }
323
324
325
326
327
328
329
330
331
332
333 public boolean isNullableOnForEach() {
334 return nullableOnForEach;
335 }
336
337 public boolean isArgNameBasedConstructorAutoMapping() {
338 return argNameBasedConstructorAutoMapping;
339 }
340
341 public void setArgNameBasedConstructorAutoMapping(boolean argNameBasedConstructorAutoMapping) {
342 this.argNameBasedConstructorAutoMapping = argNameBasedConstructorAutoMapping;
343 }
344
345 public String getDatabaseId() {
346 return databaseId;
347 }
348
349 public void setDatabaseId(String databaseId) {
350 this.databaseId = databaseId;
351 }
352
353 public Class<?> getConfigurationFactory() {
354 return configurationFactory;
355 }
356
357 public void setConfigurationFactory(Class<?> configurationFactory) {
358 this.configurationFactory = configurationFactory;
359 }
360
361 public boolean isSafeResultHandlerEnabled() {
362 return safeResultHandlerEnabled;
363 }
364
365 public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
366 this.safeResultHandlerEnabled = safeResultHandlerEnabled;
367 }
368
369 public boolean isSafeRowBoundsEnabled() {
370 return safeRowBoundsEnabled;
371 }
372
373 public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
374 this.safeRowBoundsEnabled = safeRowBoundsEnabled;
375 }
376
377 public boolean isMapUnderscoreToCamelCase() {
378 return mapUnderscoreToCamelCase;
379 }
380
381 public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
382 this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
383 }
384
385 public void addLoadedResource(String resource) {
386 loadedResources.add(resource);
387 }
388
389 public boolean isResourceLoaded(String resource) {
390 return loadedResources.contains(resource);
391 }
392
393 public Environment getEnvironment() {
394 return environment;
395 }
396
397 public void setEnvironment(Environment environment) {
398 this.environment = environment;
399 }
400
401 public AutoMappingBehavior getAutoMappingBehavior() {
402 return autoMappingBehavior;
403 }
404
405 public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
406 this.autoMappingBehavior = autoMappingBehavior;
407 }
408
409
410
411
412
413
414
415
416 public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
417 return autoMappingUnknownColumnBehavior;
418 }
419
420
421
422
423
424
425
426
427
428 public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
429 this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
430 }
431
432 public boolean isLazyLoadingEnabled() {
433 return lazyLoadingEnabled;
434 }
435
436 public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
437 this.lazyLoadingEnabled = lazyLoadingEnabled;
438 }
439
440 public ProxyFactory getProxyFactory() {
441 return proxyFactory;
442 }
443
444 public void setProxyFactory(ProxyFactory proxyFactory) {
445 if (proxyFactory == null) {
446 proxyFactory = new JavassistProxyFactory();
447 }
448 this.proxyFactory = proxyFactory;
449 }
450
451 public boolean isAggressiveLazyLoading() {
452 return aggressiveLazyLoading;
453 }
454
455 public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
456 this.aggressiveLazyLoading = aggressiveLazyLoading;
457 }
458
459 public boolean isMultipleResultSetsEnabled() {
460 return multipleResultSetsEnabled;
461 }
462
463 public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
464 this.multipleResultSetsEnabled = multipleResultSetsEnabled;
465 }
466
467 public Set<String> getLazyLoadTriggerMethods() {
468 return lazyLoadTriggerMethods;
469 }
470
471 public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
472 this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
473 }
474
475 public boolean isUseGeneratedKeys() {
476 return useGeneratedKeys;
477 }
478
479 public void setUseGeneratedKeys(boolean useGeneratedKeys) {
480 this.useGeneratedKeys = useGeneratedKeys;
481 }
482
483 public ExecutorType getDefaultExecutorType() {
484 return defaultExecutorType;
485 }
486
487 public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
488 this.defaultExecutorType = defaultExecutorType;
489 }
490
491 public boolean isCacheEnabled() {
492 return cacheEnabled;
493 }
494
495 public void setCacheEnabled(boolean cacheEnabled) {
496 this.cacheEnabled = cacheEnabled;
497 }
498
499 public Integer getDefaultStatementTimeout() {
500 return defaultStatementTimeout;
501 }
502
503 public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
504 this.defaultStatementTimeout = defaultStatementTimeout;
505 }
506
507
508
509
510
511
512
513
514 public Integer getDefaultFetchSize() {
515 return defaultFetchSize;
516 }
517
518
519
520
521
522
523
524
525
526 public void setDefaultFetchSize(Integer defaultFetchSize) {
527 this.defaultFetchSize = defaultFetchSize;
528 }
529
530
531
532
533
534
535
536
537 public ResultSetType getDefaultResultSetType() {
538 return defaultResultSetType;
539 }
540
541
542
543
544
545
546
547
548
549 public void setDefaultResultSetType(ResultSetType defaultResultSetType) {
550 this.defaultResultSetType = defaultResultSetType;
551 }
552
553 public boolean isUseColumnLabel() {
554 return useColumnLabel;
555 }
556
557 public void setUseColumnLabel(boolean useColumnLabel) {
558 this.useColumnLabel = useColumnLabel;
559 }
560
561 public LocalCacheScope getLocalCacheScope() {
562 return localCacheScope;
563 }
564
565 public void setLocalCacheScope(LocalCacheScope localCacheScope) {
566 this.localCacheScope = localCacheScope;
567 }
568
569 public JdbcType getJdbcTypeForNull() {
570 return jdbcTypeForNull;
571 }
572
573 public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
574 this.jdbcTypeForNull = jdbcTypeForNull;
575 }
576
577 public Properties getVariables() {
578 return variables;
579 }
580
581 public void setVariables(Properties variables) {
582 this.variables = variables;
583 }
584
585 public TypeHandlerRegistry getTypeHandlerRegistry() {
586 return typeHandlerRegistry;
587 }
588
589
590
591
592
593
594
595
596
597
598 public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {
599 if (typeHandler != null) {
600 getTypeHandlerRegistry().setDefaultEnumTypeHandler(typeHandler);
601 }
602 }
603
604 public TypeAliasRegistry getTypeAliasRegistry() {
605 return typeAliasRegistry;
606 }
607
608
609
610
611
612
613
614
615 public MapperRegistry getMapperRegistry() {
616 return mapperRegistry;
617 }
618
619 public ReflectorFactory getReflectorFactory() {
620 return reflectorFactory;
621 }
622
623 public void setReflectorFactory(ReflectorFactory reflectorFactory) {
624 this.reflectorFactory = reflectorFactory;
625 }
626
627 public ObjectFactory getObjectFactory() {
628 return objectFactory;
629 }
630
631 public void setObjectFactory(ObjectFactory objectFactory) {
632 this.objectFactory = objectFactory;
633 }
634
635 public ObjectWrapperFactory getObjectWrapperFactory() {
636 return objectWrapperFactory;
637 }
638
639 public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
640 this.objectWrapperFactory = objectWrapperFactory;
641 }
642
643
644
645
646
647
648
649
650 public List<Interceptor> getInterceptors() {
651 return interceptorChain.getInterceptors();
652 }
653
654 public LanguageDriverRegistry getLanguageRegistry() {
655 return languageRegistry;
656 }
657
658 public void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {
659 if (driver == null) {
660 driver = XMLLanguageDriver.class;
661 }
662 getLanguageRegistry().setDefaultDriverClass(driver);
663 }
664
665 public LanguageDriver getDefaultScriptingLanguageInstance() {
666 return languageRegistry.getDefaultDriver();
667 }
668
669
670
671
672
673
674
675
676
677
678
679 public LanguageDriver getLanguageDriver(Class<? extends LanguageDriver> langClass) {
680 if (langClass == null) {
681 return languageRegistry.getDefaultDriver();
682 }
683 languageRegistry.register(langClass);
684 return languageRegistry.getDriver(langClass);
685 }
686
687
688
689
690
691
692
693
694 @Deprecated
695 public LanguageDriver getDefaultScriptingLanuageInstance() {
696 return getDefaultScriptingLanguageInstance();
697 }
698
699 public MetaObject newMetaObject(Object object) {
700 return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
701 }
702
703 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
704 BoundSql boundSql) {
705 ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
706 parameterObject, boundSql);
707 return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
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,
713 resultHandler, boundSql, rowBounds);
714 return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
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,
720 rowBounds, resultHandler, boundSql);
721 return (StatementHandler) interceptorChain.pluginAll(statementHandler);
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;
730 Executor executor;
731 if (ExecutorType.BATCH == executorType) {
732 executor = new BatchExecutor(this, transaction);
733 } else if (ExecutorType.REUSE == executorType) {
734 executor = new ReuseExecutor(this, transaction);
735 } else {
736 executor = new SimpleExecutor(this, transaction);
737 }
738 if (cacheEnabled) {
739 executor = new CachingExecutor(executor);
740 }
741 return (Executor) interceptorChain.pluginAll(executor);
742 }
743
744 public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
745 keyGenerators.put(id, keyGenerator);
746 }
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);
758 }
759
760 public boolean hasKeyGenerator(String id) {
761 return keyGenerators.containsKey(id);
762 }
763
764 public void addCache(Cache cache) {
765 caches.put(cache.getId(), cache);
766 }
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);
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);
786 checkLocallyForDiscriminatedNestedResultMaps(rm);
787 checkGloballyForDiscriminatedNestedResultMaps(rm);
788 }
789
790 public Collection<String> getResultMapNames() {
791 return resultMaps.keySet();
792 }
793
794 public Collection<ResultMap> getResultMaps() {
795 return resultMaps.values();
796 }
797
798 public ResultMap getResultMap(String id) {
799 return resultMaps.get(id);
800 }
801
802 public boolean hasResultMap(String id) {
803 return resultMaps.containsKey(id);
804 }
805
806 public void addParameterMap(ParameterMap pm) {
807 parameterMaps.put(pm.getId(), pm);
808 }
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);
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);
828 }
829
830 public Collection<String> getMappedStatementNames() {
831 buildAllStatements();
832 return mappedStatements.keySet();
833 }
834
835 public Collection<MappedStatement> getMappedStatements() {
836 buildAllStatements();
837 return mappedStatements.values();
838 }
839
840
841
842
843 @Deprecated
844 public Collection<XMLStatementBuilder> getIncompleteStatements() {
845 return incompleteStatements;
846 }
847
848 public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
849 incompleteStatementsLock.lock();
850 try {
851 incompleteStatements.add(incompleteStatement);
852 } finally {
853 incompleteStatementsLock.unlock();
854 }
855 }
856
857
858
859
860 @Deprecated
861 public Collection<CacheRefResolver> getIncompleteCacheRefs() {
862 return incompleteCacheRefs;
863 }
864
865 public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
866 incompleteCacheRefsLock.lock();
867 try {
868 incompleteCacheRefs.add(incompleteCacheRef);
869 } finally {
870 incompleteCacheRefsLock.unlock();
871 }
872 }
873
874
875
876
877 @Deprecated
878 public Collection<ResultMapResolver> getIncompleteResultMaps() {
879 return incompleteResultMaps;
880 }
881
882 public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
883 incompleteResultMapsLock.lock();
884 try {
885 incompleteResultMaps.add(resultMapResolver);
886 } finally {
887 incompleteResultMapsLock.unlock();
888 }
889 }
890
891 public void addIncompleteMethod(MethodResolver builder) {
892 incompleteMethodsLock.lock();
893 try {
894 incompleteMethods.add(builder);
895 } finally {
896 incompleteMethodsLock.unlock();
897 }
898 }
899
900
901
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);
910 }
911
912 public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
913 if (validateIncompleteStatements) {
914 buildAllStatements();
915 }
916 return mappedStatements.get(id);
917 }
918
919 public Map<String, XNode> getSqlFragments() {
920 return sqlFragments;
921 }
922
923 public void addInterceptor(Interceptor interceptor) {
924 interceptorChain.addInterceptor(interceptor);
925 }
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);
933 }
934
935 public <T> void addMapper(Class<T> type) {
936 mapperRegistry.addMapper(type);
937 }
938
939 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
940 return mapperRegistry.getMapper(type, sqlSession);
941 }
942
943 public boolean hasMapper(Class<?> type) {
944 return mapperRegistry.hasMapper(type);
945 }
946
947 public boolean hasStatement(String statementName) {
948 return hasStatement(statementName, true);
949 }
950
951 public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
952 if (validateIncompleteStatements) {
953 buildAllStatements();
954 }
955 return mappedStatements.containsKey(statementName);
956 }
957
958 public void addCacheRef(String namespace, String referencedNamespace) {
959 cacheRefMap.put(namespace, referencedNamespace);
960 }
961
962
963
964
965
966 protected void buildAllStatements() {
967 parsePendingResultMaps(true);
968 parsePendingCacheRefs(true);
969 parsePendingStatements(true);
970 parsePendingMethods(true);
971 }
972
973 public void parsePendingMethods(boolean reportUnresolved) {
974 if (incompleteMethods.isEmpty()) {
975 return;
976 }
977 incompleteMethodsLock.lock();
978 try {
979 incompleteMethods.removeIf(x -> {
980 x.resolve();
981 return true;
982 });
983 } catch (IncompleteElementException e) {
984 if (reportUnresolved) {
985 throw e;
986 }
987 } finally {
988 incompleteMethodsLock.unlock();
989 }
990 }
991
992 public void parsePendingStatements(boolean reportUnresolved) {
993 if (incompleteStatements.isEmpty()) {
994 return;
995 }
996 incompleteStatementsLock.lock();
997 try {
998 incompleteStatements.removeIf(x -> {
999 x.parseStatementNode();
1000 return true;
1001 });
1002 } catch (IncompleteElementException e) {
1003 if (reportUnresolved) {
1004 throw e;
1005 }
1006 } finally {
1007 incompleteStatementsLock.unlock();
1008 }
1009 }
1010
1011 public void parsePendingCacheRefs(boolean reportUnresolved) {
1012 if (incompleteCacheRefs.isEmpty()) {
1013 return;
1014 }
1015 incompleteCacheRefsLock.lock();
1016 try {
1017 incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
1018 } catch (IncompleteElementException e) {
1019 if (reportUnresolved) {
1020 throw e;
1021 }
1022 } finally {
1023 incompleteCacheRefsLock.unlock();
1024 }
1025 }
1026
1027 public void parsePendingResultMaps(boolean reportUnresolved) {
1028 if (incompleteResultMaps.isEmpty()) {
1029 return;
1030 }
1031 incompleteResultMapsLock.lock();
1032 try {
1033 boolean resolved;
1034 IncompleteElementException ex = null;
1035 do {
1036 resolved = false;
1037 Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();
1038 while (iterator.hasNext()) {
1039 try {
1040 iterator.next().resolve();
1041 iterator.remove();
1042 resolved = true;
1043 } catch (IncompleteElementException e) {
1044 ex = e;
1045 }
1046 }
1047 } while (resolved);
1048 if (reportUnresolved && !incompleteResultMaps.isEmpty() && ex != null) {
1049
1050 throw ex;
1051 }
1052 } finally {
1053 incompleteResultMapsLock.unlock();
1054 }
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065 protected String extractNamespace(String statementId) {
1066 int lastPeriod = statementId.lastIndexOf('.');
1067 return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
1068 }
1069
1070
1071 protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
1072 if (rm.hasNestedResultMaps()) {
1073 final String resultMapId = rm.getId();
1074 for (Object resultMapObject : resultMaps.values()) {
1075 if (resultMapObject instanceof ResultMap) {
1076 ResultMap entryResultMap = (ResultMap) resultMapObject;
1077 if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
1078 Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap()
1079 .values();
1080 if (discriminatedResultMapNames.contains(resultMapId)) {
1081 entryResultMap.forceNestedResultMaps();
1082 }
1083 }
1084 }
1085 }
1086 }
1087 }
1088
1089
1090 protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
1091 if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
1092 for (String discriminatedResultMapName : rm.getDiscriminator().getDiscriminatorMap().values()) {
1093 if (hasResultMap(discriminatedResultMapName)) {
1094 ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);
1095 if (discriminatedResultMap.hasNestedResultMaps()) {
1096 rm.forceNestedResultMaps();
1097 break;
1098 }
1099 }
1100 }
1101 }
1102 }
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
1110 public StrictMap(String name, int initialCapacity, float loadFactor) {
1111 super(initialCapacity, loadFactor);
1112 this.name = name;
1113 }
1114
1115 public StrictMap(String name, int initialCapacity) {
1116 super(initialCapacity);
1117 this.name = name;
1118 }
1119
1120 public StrictMap(String name) {
1121 this.name = name;
1122 }
1123
1124 public StrictMap(String name, Map<String, ? extends V> m) {
1125 super(m);
1126 this.name = name;
1127 }
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141 public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {
1142 this.conflictMessageProducer = conflictMessageProducer;
1143 return this;
1144 }
1145
1146 @Override
1147 @SuppressWarnings("unchecked")
1148 public V put(String key, V value) {
1149 if (containsKey(key)) {
1150 throw new IllegalArgumentException(name + " already contains key " + key
1151 + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
1152 }
1153 if (key.contains(".")) {
1154 final String shortKey = getShortName(key);
1155 if (super.get(shortKey) == null) {
1156 super.put(shortKey, value);
1157 } else {
1158 super.put(shortKey, (V) new Ambiguity(shortKey));
1159 }
1160 }
1161 return super.put(key, value);
1162 }
1163
1164 @Override
1165 public boolean containsKey(Object key) {
1166 if (key == null) {
1167 return false;
1168 }
1169
1170 return super.get(key) != null;
1171 }
1172
1173 @Override
1174 public V get(Object key) {
1175 V value = super.get(key);
1176 if (value == null) {
1177 throw new IllegalArgumentException(name + " does not contain value for " + key);
1178 }
1179 if (value instanceof Ambiguity) {
1180 throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
1181 + " (try using the full name including the namespace, or rename one of the entries)");
1182 }
1183 return value;
1184 }
1185
1186 protected static class Ambiguity {
1187 private final String subject;
1188
1189 public Ambiguity(String subject) {
1190 this.subject = subject;
1191 }
1192
1193 public String getSubject() {
1194 return subject;
1195 }
1196 }
1197
1198 private String getShortName(String key) {
1199 final String[] keyParts = key.split("\\.");
1200 return keyParts[keyParts.length - 1];
1201 }
1202 }
1203
1204 }