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