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.function.BiFunction;
30
31 import org.apache.ibatis.binding.MapperRegistry;
32 import org.apache.ibatis.builder.CacheRefResolver;
33 import org.apache.ibatis.builder.IncompleteElementException;
34 import org.apache.ibatis.builder.ResultMapResolver;
35 import org.apache.ibatis.builder.annotation.MethodResolver;
36 import org.apache.ibatis.builder.xml.XMLStatementBuilder;
37 import org.apache.ibatis.cache.Cache;
38 import org.apache.ibatis.cache.decorators.FifoCache;
39 import org.apache.ibatis.cache.decorators.LruCache;
40 import org.apache.ibatis.cache.decorators.SoftCache;
41 import org.apache.ibatis.cache.decorators.WeakCache;
42 import org.apache.ibatis.cache.impl.PerpetualCache;
43 import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
44 import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
45 import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
46 import org.apache.ibatis.executor.BatchExecutor;
47 import org.apache.ibatis.executor.CachingExecutor;
48 import org.apache.ibatis.executor.Executor;
49 import org.apache.ibatis.executor.ReuseExecutor;
50 import org.apache.ibatis.executor.SimpleExecutor;
51 import org.apache.ibatis.executor.keygen.KeyGenerator;
52 import org.apache.ibatis.executor.loader.ProxyFactory;
53 import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
54 import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
55 import org.apache.ibatis.executor.parameter.ParameterHandler;
56 import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
57 import org.apache.ibatis.executor.resultset.ResultSetHandler;
58 import org.apache.ibatis.executor.statement.RoutingStatementHandler;
59 import org.apache.ibatis.executor.statement.StatementHandler;
60 import org.apache.ibatis.io.VFS;
61 import org.apache.ibatis.logging.Log;
62 import org.apache.ibatis.logging.LogFactory;
63 import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
64 import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
65 import org.apache.ibatis.logging.log4j.Log4jImpl;
66 import org.apache.ibatis.logging.log4j2.Log4j2Impl;
67 import org.apache.ibatis.logging.nologging.NoLoggingImpl;
68 import org.apache.ibatis.logging.slf4j.Slf4jImpl;
69 import org.apache.ibatis.logging.stdout.StdOutImpl;
70 import org.apache.ibatis.mapping.BoundSql;
71 import org.apache.ibatis.mapping.Environment;
72 import org.apache.ibatis.mapping.MappedStatement;
73 import org.apache.ibatis.mapping.ParameterMap;
74 import org.apache.ibatis.mapping.ResultMap;
75 import org.apache.ibatis.mapping.ResultSetType;
76 import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
77 import org.apache.ibatis.parsing.XNode;
78 import org.apache.ibatis.plugin.Interceptor;
79 import org.apache.ibatis.plugin.InterceptorChain;
80 import org.apache.ibatis.reflection.DefaultReflectorFactory;
81 import org.apache.ibatis.reflection.MetaObject;
82 import org.apache.ibatis.reflection.ReflectorFactory;
83 import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
84 import org.apache.ibatis.reflection.factory.ObjectFactory;
85 import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
86 import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
87 import org.apache.ibatis.scripting.LanguageDriver;
88 import org.apache.ibatis.scripting.LanguageDriverRegistry;
89 import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
90 import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
91 import org.apache.ibatis.transaction.Transaction;
92 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
93 import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
94 import org.apache.ibatis.type.JdbcType;
95 import org.apache.ibatis.type.TypeAliasRegistry;
96 import org.apache.ibatis.type.TypeHandler;
97 import org.apache.ibatis.type.TypeHandlerRegistry;
98
99
100
101
102 public class Configuration {
103
104 protected Environment environment;
105
106 protected boolean safeRowBoundsEnabled;
107 protected boolean safeResultHandlerEnabled = true;
108 protected boolean mapUnderscoreToCamelCase;
109 protected boolean aggressiveLazyLoading;
110 protected boolean multipleResultSetsEnabled = true;
111 protected boolean useGeneratedKeys;
112 protected boolean useColumnLabel = true;
113 protected boolean cacheEnabled = true;
114 protected boolean callSettersOnNulls;
115 protected boolean useActualParamName = true;
116 protected boolean returnInstanceForEmptyRow;
117 protected boolean shrinkWhitespacesInSql;
118 protected boolean nullableOnForEach;
119 protected boolean argNameBasedConstructorAutoMapping;
120
121 protected String logPrefix;
122 protected Class<? extends Log> logImpl;
123 protected Class<? extends VFS> vfsImpl;
124 protected Class<?> defaultSqlProviderType;
125 protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
126 protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
127 protected Set<String> lazyLoadTriggerMethods = new HashSet<>(
128 Arrays.asList("equals", "clone", "hashCode", "toString"));
129 protected Integer defaultStatementTimeout;
130 protected Integer defaultFetchSize;
131 protected ResultSetType defaultResultSetType;
132 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
133 protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
134 protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
135
136 protected Properties variables = new Properties();
137 protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
138 protected ObjectFactory objectFactory = new DefaultObjectFactory();
139 protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
140
141 protected boolean lazyLoadingEnabled;
142 protected ProxyFactory proxyFactory = new JavassistProxyFactory();
143
144 protected String databaseId;
145
146
147
148
149
150 protected Class<?> configurationFactory;
151
152 protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
153 protected final InterceptorChain interceptorChain = new InterceptorChain();
154 protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
155 protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
156 protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
157
158 protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
159 "Mapped Statements collection")
160 .conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and "
161 + targetValue.getResource());
162 protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
163 protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
164 protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
165 protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
166
167 protected final Set<String> loadedResources = new HashSet<>();
168 protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
169
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
176
177
178
179 protected final Map<String, String> cacheRefMap = new HashMap<>();
180
181 public Configuration(Environment environment) {
182 this();
183 this.environment = environment;
184 }
185
186 public Configuration() {
187 typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
188 typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
189
190 typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
191 typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
192 typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
193
194 typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
195 typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
196 typeAliasRegistry.registerAlias("LRU", LruCache.class);
197 typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
198 typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
199
200 typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
201
202 typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
203 typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
204
205 typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
206 typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
207 typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
208 typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
209 typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
210 typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
211 typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
212
213 typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
214 typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
215
216 languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
217 languageRegistry.register(RawLanguageDriver.class);
218 }
219
220 public String getLogPrefix() {
221 return logPrefix;
222 }
223
224 public void setLogPrefix(String logPrefix) {
225 this.logPrefix = logPrefix;
226 }
227
228 public Class<? extends Log> getLogImpl() {
229 return logImpl;
230 }
231
232 public void setLogImpl(Class<? extends Log> logImpl) {
233 if (logImpl != null) {
234 this.logImpl = logImpl;
235 LogFactory.useCustomLogging(this.logImpl);
236 }
237 }
238
239 public Class<? extends VFS> getVfsImpl() {
240 return this.vfsImpl;
241 }
242
243 public void setVfsImpl(Class<? extends VFS> vfsImpl) {
244 if (vfsImpl != null) {
245 this.vfsImpl = vfsImpl;
246 VFS.addImplClass(this.vfsImpl);
247 }
248 }
249
250
251
252
253
254
255
256
257
258 public Class<?> getDefaultSqlProviderType() {
259 return defaultSqlProviderType;
260 }
261
262
263
264
265
266
267
268
269
270
271 public void setDefaultSqlProviderType(Class<?> defaultSqlProviderType) {
272 this.defaultSqlProviderType = defaultSqlProviderType;
273 }
274
275 public boolean isCallSettersOnNulls() {
276 return callSettersOnNulls;
277 }
278
279 public void setCallSettersOnNulls(boolean callSettersOnNulls) {
280 this.callSettersOnNulls = callSettersOnNulls;
281 }
282
283 public boolean isUseActualParamName() {
284 return useActualParamName;
285 }
286
287 public void setUseActualParamName(boolean useActualParamName) {
288 this.useActualParamName = useActualParamName;
289 }
290
291 public boolean isReturnInstanceForEmptyRow() {
292 return returnInstanceForEmptyRow;
293 }
294
295 public void setReturnInstanceForEmptyRow(boolean returnEmptyInstance) {
296 this.returnInstanceForEmptyRow = returnEmptyInstance;
297 }
298
299 public boolean isShrinkWhitespacesInSql() {
300 return shrinkWhitespacesInSql;
301 }
302
303 public void setShrinkWhitespacesInSql(boolean shrinkWhitespacesInSql) {
304 this.shrinkWhitespacesInSql = shrinkWhitespacesInSql;
305 }
306
307
308
309
310
311
312
313
314
315 public void setNullableOnForEach(boolean nullableOnForEach) {
316 this.nullableOnForEach = nullableOnForEach;
317 }
318
319
320
321
322
323
324
325
326
327
328 public boolean isNullableOnForEach() {
329 return nullableOnForEach;
330 }
331
332 public boolean isArgNameBasedConstructorAutoMapping() {
333 return argNameBasedConstructorAutoMapping;
334 }
335
336 public void setArgNameBasedConstructorAutoMapping(boolean argNameBasedConstructorAutoMapping) {
337 this.argNameBasedConstructorAutoMapping = argNameBasedConstructorAutoMapping;
338 }
339
340 public String getDatabaseId() {
341 return databaseId;
342 }
343
344 public void setDatabaseId(String databaseId) {
345 this.databaseId = databaseId;
346 }
347
348 public Class<?> getConfigurationFactory() {
349 return configurationFactory;
350 }
351
352 public void setConfigurationFactory(Class<?> configurationFactory) {
353 this.configurationFactory = configurationFactory;
354 }
355
356 public boolean isSafeResultHandlerEnabled() {
357 return safeResultHandlerEnabled;
358 }
359
360 public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
361 this.safeResultHandlerEnabled = safeResultHandlerEnabled;
362 }
363
364 public boolean isSafeRowBoundsEnabled() {
365 return safeRowBoundsEnabled;
366 }
367
368 public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
369 this.safeRowBoundsEnabled = safeRowBoundsEnabled;
370 }
371
372 public boolean isMapUnderscoreToCamelCase() {
373 return mapUnderscoreToCamelCase;
374 }
375
376 public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
377 this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
378 }
379
380 public void addLoadedResource(String resource) {
381 loadedResources.add(resource);
382 }
383
384 public boolean isResourceLoaded(String resource) {
385 return loadedResources.contains(resource);
386 }
387
388 public Environment getEnvironment() {
389 return environment;
390 }
391
392 public void setEnvironment(Environment environment) {
393 this.environment = environment;
394 }
395
396 public AutoMappingBehavior getAutoMappingBehavior() {
397 return autoMappingBehavior;
398 }
399
400 public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
401 this.autoMappingBehavior = autoMappingBehavior;
402 }
403
404
405
406
407
408
409
410
411 public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
412 return autoMappingUnknownColumnBehavior;
413 }
414
415
416
417
418
419
420
421
422
423 public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
424 this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
425 }
426
427 public boolean isLazyLoadingEnabled() {
428 return lazyLoadingEnabled;
429 }
430
431 public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
432 this.lazyLoadingEnabled = lazyLoadingEnabled;
433 }
434
435 public ProxyFactory getProxyFactory() {
436 return proxyFactory;
437 }
438
439 public void setProxyFactory(ProxyFactory proxyFactory) {
440 if (proxyFactory == null) {
441 proxyFactory = new JavassistProxyFactory();
442 }
443 this.proxyFactory = proxyFactory;
444 }
445
446 public boolean isAggressiveLazyLoading() {
447 return aggressiveLazyLoading;
448 }
449
450 public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
451 this.aggressiveLazyLoading = aggressiveLazyLoading;
452 }
453
454 public boolean isMultipleResultSetsEnabled() {
455 return multipleResultSetsEnabled;
456 }
457
458 public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
459 this.multipleResultSetsEnabled = multipleResultSetsEnabled;
460 }
461
462 public Set<String> getLazyLoadTriggerMethods() {
463 return lazyLoadTriggerMethods;
464 }
465
466 public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
467 this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
468 }
469
470 public boolean isUseGeneratedKeys() {
471 return useGeneratedKeys;
472 }
473
474 public void setUseGeneratedKeys(boolean useGeneratedKeys) {
475 this.useGeneratedKeys = useGeneratedKeys;
476 }
477
478 public ExecutorType getDefaultExecutorType() {
479 return defaultExecutorType;
480 }
481
482 public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
483 this.defaultExecutorType = defaultExecutorType;
484 }
485
486 public boolean isCacheEnabled() {
487 return cacheEnabled;
488 }
489
490 public void setCacheEnabled(boolean cacheEnabled) {
491 this.cacheEnabled = cacheEnabled;
492 }
493
494 public Integer getDefaultStatementTimeout() {
495 return defaultStatementTimeout;
496 }
497
498 public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
499 this.defaultStatementTimeout = defaultStatementTimeout;
500 }
501
502
503
504
505
506
507
508
509 public Integer getDefaultFetchSize() {
510 return defaultFetchSize;
511 }
512
513
514
515
516
517
518
519
520
521 public void setDefaultFetchSize(Integer defaultFetchSize) {
522 this.defaultFetchSize = defaultFetchSize;
523 }
524
525
526
527
528
529
530
531
532 public ResultSetType getDefaultResultSetType() {
533 return defaultResultSetType;
534 }
535
536
537
538
539
540
541
542
543
544 public void setDefaultResultSetType(ResultSetType defaultResultSetType) {
545 this.defaultResultSetType = defaultResultSetType;
546 }
547
548 public boolean isUseColumnLabel() {
549 return useColumnLabel;
550 }
551
552 public void setUseColumnLabel(boolean useColumnLabel) {
553 this.useColumnLabel = useColumnLabel;
554 }
555
556 public LocalCacheScope getLocalCacheScope() {
557 return localCacheScope;
558 }
559
560 public void setLocalCacheScope(LocalCacheScope localCacheScope) {
561 this.localCacheScope = localCacheScope;
562 }
563
564 public JdbcType getJdbcTypeForNull() {
565 return jdbcTypeForNull;
566 }
567
568 public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
569 this.jdbcTypeForNull = jdbcTypeForNull;
570 }
571
572 public Properties getVariables() {
573 return variables;
574 }
575
576 public void setVariables(Properties variables) {
577 this.variables = variables;
578 }
579
580 public TypeHandlerRegistry getTypeHandlerRegistry() {
581 return typeHandlerRegistry;
582 }
583
584
585
586
587
588
589
590
591
592
593 public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {
594 if (typeHandler != null) {
595 getTypeHandlerRegistry().setDefaultEnumTypeHandler(typeHandler);
596 }
597 }
598
599 public TypeAliasRegistry getTypeAliasRegistry() {
600 return typeAliasRegistry;
601 }
602
603
604
605
606
607
608
609
610 public MapperRegistry getMapperRegistry() {
611 return mapperRegistry;
612 }
613
614 public ReflectorFactory getReflectorFactory() {
615 return reflectorFactory;
616 }
617
618 public void setReflectorFactory(ReflectorFactory reflectorFactory) {
619 this.reflectorFactory = reflectorFactory;
620 }
621
622 public ObjectFactory getObjectFactory() {
623 return objectFactory;
624 }
625
626 public void setObjectFactory(ObjectFactory objectFactory) {
627 this.objectFactory = objectFactory;
628 }
629
630 public ObjectWrapperFactory getObjectWrapperFactory() {
631 return objectWrapperFactory;
632 }
633
634 public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
635 this.objectWrapperFactory = objectWrapperFactory;
636 }
637
638
639
640
641
642
643
644
645 public List<Interceptor> getInterceptors() {
646 return interceptorChain.getInterceptors();
647 }
648
649 public LanguageDriverRegistry getLanguageRegistry() {
650 return languageRegistry;
651 }
652
653 public void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {
654 if (driver == null) {
655 driver = XMLLanguageDriver.class;
656 }
657 getLanguageRegistry().setDefaultDriverClass(driver);
658 }
659
660 public LanguageDriver getDefaultScriptingLanguageInstance() {
661 return languageRegistry.getDefaultDriver();
662 }
663
664
665
666
667
668
669
670
671
672
673
674 public LanguageDriver getLanguageDriver(Class<? extends LanguageDriver> langClass) {
675 if (langClass == null) {
676 return languageRegistry.getDefaultDriver();
677 }
678 languageRegistry.register(langClass);
679 return languageRegistry.getDriver(langClass);
680 }
681
682
683
684
685
686
687
688
689 @Deprecated
690 public LanguageDriver getDefaultScriptingLanuageInstance() {
691 return getDefaultScriptingLanguageInstance();
692 }
693
694 public MetaObject newMetaObject(Object object) {
695 return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
696 }
697
698 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
699 BoundSql boundSql) {
700 ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
701 parameterObject, boundSql);
702 return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
703 }
704
705 public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
706 ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
707 ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
708 resultHandler, boundSql, rowBounds);
709 return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
710 }
711
712 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
713 Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
714 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
715 rowBounds, resultHandler, boundSql);
716 return (StatementHandler) interceptorChain.pluginAll(statementHandler);
717 }
718
719 public Executor newExecutor(Transaction transaction) {
720 return newExecutor(transaction, defaultExecutorType);
721 }
722
723 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
724 executorType = executorType == null ? defaultExecutorType : executorType;
725 Executor executor;
726 if (ExecutorType.BATCH == executorType) {
727 executor = new BatchExecutor(this, transaction);
728 } else if (ExecutorType.REUSE == executorType) {
729 executor = new ReuseExecutor(this, transaction);
730 } else {
731 executor = new SimpleExecutor(this, transaction);
732 }
733 if (cacheEnabled) {
734 executor = new CachingExecutor(executor);
735 }
736 return (Executor) interceptorChain.pluginAll(executor);
737 }
738
739 public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
740 keyGenerators.put(id, keyGenerator);
741 }
742
743 public Collection<String> getKeyGeneratorNames() {
744 return keyGenerators.keySet();
745 }
746
747 public Collection<KeyGenerator> getKeyGenerators() {
748 return keyGenerators.values();
749 }
750
751 public KeyGenerator getKeyGenerator(String id) {
752 return keyGenerators.get(id);
753 }
754
755 public boolean hasKeyGenerator(String id) {
756 return keyGenerators.containsKey(id);
757 }
758
759 public void addCache(Cache cache) {
760 caches.put(cache.getId(), cache);
761 }
762
763 public Collection<String> getCacheNames() {
764 return caches.keySet();
765 }
766
767 public Collection<Cache> getCaches() {
768 return caches.values();
769 }
770
771 public Cache getCache(String id) {
772 return caches.get(id);
773 }
774
775 public boolean hasCache(String id) {
776 return caches.containsKey(id);
777 }
778
779 public void addResultMap(ResultMap rm) {
780 resultMaps.put(rm.getId(), rm);
781 checkLocallyForDiscriminatedNestedResultMaps(rm);
782 checkGloballyForDiscriminatedNestedResultMaps(rm);
783 }
784
785 public Collection<String> getResultMapNames() {
786 return resultMaps.keySet();
787 }
788
789 public Collection<ResultMap> getResultMaps() {
790 return resultMaps.values();
791 }
792
793 public ResultMap getResultMap(String id) {
794 return resultMaps.get(id);
795 }
796
797 public boolean hasResultMap(String id) {
798 return resultMaps.containsKey(id);
799 }
800
801 public void addParameterMap(ParameterMap pm) {
802 parameterMaps.put(pm.getId(), pm);
803 }
804
805 public Collection<String> getParameterMapNames() {
806 return parameterMaps.keySet();
807 }
808
809 public Collection<ParameterMap> getParameterMaps() {
810 return parameterMaps.values();
811 }
812
813 public ParameterMap getParameterMap(String id) {
814 return parameterMaps.get(id);
815 }
816
817 public boolean hasParameterMap(String id) {
818 return parameterMaps.containsKey(id);
819 }
820
821 public void addMappedStatement(MappedStatement ms) {
822 mappedStatements.put(ms.getId(), ms);
823 }
824
825 public Collection<String> getMappedStatementNames() {
826 buildAllStatements();
827 return mappedStatements.keySet();
828 }
829
830 public Collection<MappedStatement> getMappedStatements() {
831 buildAllStatements();
832 return mappedStatements.values();
833 }
834
835 public Collection<XMLStatementBuilder> getIncompleteStatements() {
836 return incompleteStatements;
837 }
838
839 public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
840 incompleteStatements.add(incompleteStatement);
841 }
842
843 public Collection<CacheRefResolver> getIncompleteCacheRefs() {
844 return incompleteCacheRefs;
845 }
846
847 public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
848 incompleteCacheRefs.add(incompleteCacheRef);
849 }
850
851 public Collection<ResultMapResolver> getIncompleteResultMaps() {
852 return incompleteResultMaps;
853 }
854
855 public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
856 incompleteResultMaps.add(resultMapResolver);
857 }
858
859 public void addIncompleteMethod(MethodResolver builder) {
860 incompleteMethods.add(builder);
861 }
862
863 public Collection<MethodResolver> getIncompleteMethods() {
864 return incompleteMethods;
865 }
866
867 public MappedStatement getMappedStatement(String id) {
868 return this.getMappedStatement(id, true);
869 }
870
871 public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
872 if (validateIncompleteStatements) {
873 buildAllStatements();
874 }
875 return mappedStatements.get(id);
876 }
877
878 public Map<String, XNode> getSqlFragments() {
879 return sqlFragments;
880 }
881
882 public void addInterceptor(Interceptor interceptor) {
883 interceptorChain.addInterceptor(interceptor);
884 }
885
886 public void addMappers(String packageName, Class<?> superType) {
887 mapperRegistry.addMappers(packageName, superType);
888 }
889
890 public void addMappers(String packageName) {
891 mapperRegistry.addMappers(packageName);
892 }
893
894 public <T> void addMapper(Class<T> type) {
895 mapperRegistry.addMapper(type);
896 }
897
898 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
899 return mapperRegistry.getMapper(type, sqlSession);
900 }
901
902 public boolean hasMapper(Class<?> type) {
903 return mapperRegistry.hasMapper(type);
904 }
905
906 public boolean hasStatement(String statementName) {
907 return hasStatement(statementName, true);
908 }
909
910 public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
911 if (validateIncompleteStatements) {
912 buildAllStatements();
913 }
914 return mappedStatements.containsKey(statementName);
915 }
916
917 public void addCacheRef(String namespace, String referencedNamespace) {
918 cacheRefMap.put(namespace, referencedNamespace);
919 }
920
921
922
923
924
925 protected void buildAllStatements() {
926 parsePendingResultMaps();
927 if (!incompleteCacheRefs.isEmpty()) {
928 synchronized (incompleteCacheRefs) {
929 incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
930 }
931 }
932 if (!incompleteStatements.isEmpty()) {
933 synchronized (incompleteStatements) {
934 incompleteStatements.removeIf(x -> {
935 x.parseStatementNode();
936 return true;
937 });
938 }
939 }
940 if (!incompleteMethods.isEmpty()) {
941 synchronized (incompleteMethods) {
942 incompleteMethods.removeIf(x -> {
943 x.resolve();
944 return true;
945 });
946 }
947 }
948 }
949
950 private void parsePendingResultMaps() {
951 if (incompleteResultMaps.isEmpty()) {
952 return;
953 }
954 synchronized (incompleteResultMaps) {
955 boolean resolved;
956 IncompleteElementException ex = null;
957 do {
958 resolved = false;
959 Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();
960 while (iterator.hasNext()) {
961 try {
962 iterator.next().resolve();
963 iterator.remove();
964 resolved = true;
965 } catch (IncompleteElementException e) {
966 ex = e;
967 }
968 }
969 } while (resolved);
970 if (!incompleteResultMaps.isEmpty() && ex != null) {
971
972 throw ex;
973 }
974 }
975 }
976
977
978
979
980
981
982
983
984
985 protected String extractNamespace(String statementId) {
986 int lastPeriod = statementId.lastIndexOf('.');
987 return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
988 }
989
990
991 protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
992 if (rm.hasNestedResultMaps()) {
993 final String resultMapId = rm.getId();
994 for (Object resultMapObject : resultMaps.values()) {
995 if (resultMapObject instanceof ResultMap) {
996 ResultMap entryResultMap = (ResultMap) resultMapObject;
997 if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
998 Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap()
999 .values();
1000 if (discriminatedResultMapNames.contains(resultMapId)) {
1001 entryResultMap.forceNestedResultMaps();
1002 }
1003 }
1004 }
1005 }
1006 }
1007 }
1008
1009
1010 protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
1011 if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
1012 for (String discriminatedResultMapName : rm.getDiscriminator().getDiscriminatorMap().values()) {
1013 if (hasResultMap(discriminatedResultMapName)) {
1014 ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);
1015 if (discriminatedResultMap.hasNestedResultMaps()) {
1016 rm.forceNestedResultMaps();
1017 break;
1018 }
1019 }
1020 }
1021 }
1022 }
1023
1024 protected static class StrictMap<V> extends ConcurrentHashMap<String, V> {
1025
1026 private static final long serialVersionUID = -4950446264854982944L;
1027 private final String name;
1028 private BiFunction<V, V, String> conflictMessageProducer;
1029
1030 public StrictMap(String name, int initialCapacity, float loadFactor) {
1031 super(initialCapacity, loadFactor);
1032 this.name = name;
1033 }
1034
1035 public StrictMap(String name, int initialCapacity) {
1036 super(initialCapacity);
1037 this.name = name;
1038 }
1039
1040 public StrictMap(String name) {
1041 this.name = name;
1042 }
1043
1044 public StrictMap(String name, Map<String, ? extends V> m) {
1045 super(m);
1046 this.name = name;
1047 }
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061 public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {
1062 this.conflictMessageProducer = conflictMessageProducer;
1063 return this;
1064 }
1065
1066 @Override
1067 @SuppressWarnings("unchecked")
1068 public V put(String key, V value) {
1069 if (containsKey(key)) {
1070 throw new IllegalArgumentException(name + " already contains key " + key
1071 + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
1072 }
1073 if (key.contains(".")) {
1074 final String shortKey = getShortName(key);
1075 if (super.get(shortKey) == null) {
1076 super.put(shortKey, value);
1077 } else {
1078 super.put(shortKey, (V) new Ambiguity(shortKey));
1079 }
1080 }
1081 return super.put(key, value);
1082 }
1083
1084 @Override
1085 public boolean containsKey(Object key) {
1086 if (key == null) {
1087 return false;
1088 }
1089
1090 return super.get(key) != null;
1091 }
1092
1093 @Override
1094 public V get(Object key) {
1095 V value = super.get(key);
1096 if (value == null) {
1097 throw new IllegalArgumentException(name + " does not contain value for " + key);
1098 }
1099 if (value instanceof Ambiguity) {
1100 throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
1101 + " (try using the full name including the namespace, or rename one of the entries)");
1102 }
1103 return value;
1104 }
1105
1106 protected static class Ambiguity {
1107 private final String subject;
1108
1109 public Ambiguity(String subject) {
1110 this.subject = subject;
1111 }
1112
1113 public String getSubject() {
1114 return subject;
1115 }
1116 }
1117
1118 private String getShortName(String key) {
1119 final String[] keyParts = key.split("\\.");
1120 return keyParts[keyParts.length - 1];
1121 }
1122 }
1123
1124 }