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