/*
|
* Copyright 2009-2014 the original author or authors.
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
package org.apache.ibatis.session;
|
|
import java.util.Arrays;
|
import java.util.Collection;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Properties;
|
import java.util.Set;
|
|
import org.apache.ibatis.binding.MapperRegistry;
|
import org.apache.ibatis.builder.CacheRefResolver;
|
import org.apache.ibatis.builder.ResultMapResolver;
|
import org.apache.ibatis.builder.annotation.MethodResolver;
|
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
|
import org.apache.ibatis.cache.Cache;
|
import org.apache.ibatis.cache.decorators.FifoCache;
|
import org.apache.ibatis.cache.decorators.LruCache;
|
import org.apache.ibatis.cache.decorators.SoftCache;
|
import org.apache.ibatis.cache.decorators.WeakCache;
|
import org.apache.ibatis.cache.impl.PerpetualCache;
|
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
|
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
|
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
|
import org.apache.ibatis.executor.BatchExecutor;
|
import org.apache.ibatis.executor.CachingExecutor;
|
import org.apache.ibatis.executor.Executor;
|
import org.apache.ibatis.executor.ReuseExecutor;
|
import org.apache.ibatis.executor.SimpleExecutor;
|
import org.apache.ibatis.executor.keygen.KeyGenerator;
|
import org.apache.ibatis.executor.loader.ProxyFactory;
|
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
|
import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
|
import org.apache.ibatis.executor.parameter.ParameterHandler;
|
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
|
import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
|
import org.apache.ibatis.executor.statement.StatementHandler;
|
import org.apache.ibatis.logging.Log;
|
import org.apache.ibatis.logging.LogFactory;
|
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
|
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
|
import org.apache.ibatis.logging.log4j.Log4jImpl;
|
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
|
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
|
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
|
import org.apache.ibatis.logging.stdout.StdOutImpl;
|
import org.apache.ibatis.mapping.BoundSql;
|
import org.apache.ibatis.mapping.Environment;
|
import org.apache.ibatis.mapping.MappedStatement;
|
import org.apache.ibatis.mapping.ParameterMap;
|
import org.apache.ibatis.mapping.ResultMap;
|
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
|
import org.apache.ibatis.parsing.XNode;
|
import org.apache.ibatis.plugin.Interceptor;
|
import org.apache.ibatis.plugin.InterceptorChain;
|
import org.apache.ibatis.reflection.MetaObject;
|
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
|
import org.apache.ibatis.reflection.factory.ObjectFactory;
|
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
|
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
|
import org.apache.ibatis.scripting.LanguageDriver;
|
import org.apache.ibatis.scripting.LanguageDriverRegistry;
|
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
|
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
|
import org.apache.ibatis.transaction.Transaction;
|
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
|
import org.apache.ibatis.type.JdbcType;
|
import org.apache.ibatis.type.TypeAliasRegistry;
|
import org.apache.ibatis.type.TypeHandlerRegistry;
|
|
/**
|
* @author Clinton Begin
|
* @description 重写put,实现刷新的功能
|
*/
|
public class Configuration {
|
|
protected Environment environment;
|
|
protected boolean safeRowBoundsEnabled = false;
|
protected boolean safeResultHandlerEnabled = true;
|
protected boolean mapUnderscoreToCamelCase = false;
|
protected boolean aggressiveLazyLoading = true;
|
protected boolean multipleResultSetsEnabled = true;
|
protected boolean useGeneratedKeys = false;
|
protected boolean useColumnLabel = true;
|
protected boolean cacheEnabled = true;
|
protected boolean callSettersOnNulls = false;
|
protected String logPrefix;
|
protected Class<? extends Log> logImpl;
|
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
|
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
|
protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(
|
Arrays.asList(new String[] { "equals", "clone", "hashCode",
|
"toString" }));
|
protected Integer defaultStatementTimeout;
|
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
|
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
|
|
protected Properties variables = new Properties();
|
protected ObjectFactory objectFactory = new DefaultObjectFactory();
|
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
|
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
|
|
protected boolean lazyLoadingEnabled = false;
|
protected ProxyFactory proxyFactory;
|
|
protected String databaseId;
|
/**
|
* Configuration factory class. Used to create Configuration for loading
|
* deserialized unread properties.
|
*
|
* @see <a
|
* href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue
|
* 300</a> (google code)
|
*/
|
protected Class<?> configurationFactory;
|
|
protected final InterceptorChain interceptorChain = new InterceptorChain();
|
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
|
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
|
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
|
|
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
|
"Mapped Statements collection");
|
protected final Map<String, Cache> caches = new StrictMap<Cache>(
|
"Caches collection");
|
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>(
|
"Result Maps collection");
|
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>(
|
"Parameter Maps collection");
|
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>(
|
"Key Generators collection");
|
|
protected final Set<String> loadedResources = new HashSet<String>();
|
protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>(
|
"XML fragments parsed from previous mappers");
|
|
protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
|
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
|
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
|
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();
|
|
/*
|
* A map holds cache-ref relationship. The key is the namespace that
|
* references a cache bound to another namespace and the value is the
|
* namespace which the actual cache is bound to.
|
*/
|
protected final Map<String, String> cacheRefMap = new HashMap<String, String>();
|
|
public Configuration(Environment environment) {
|
this();
|
this.environment = environment;
|
}
|
|
public Configuration() {
|
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
|
typeAliasRegistry.registerAlias("MANAGED",
|
ManagedTransactionFactory.class);
|
|
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
|
typeAliasRegistry
|
.registerAlias("POOLED", PooledDataSourceFactory.class);
|
typeAliasRegistry.registerAlias("UNPOOLED",
|
UnpooledDataSourceFactory.class);
|
|
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
|
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
|
typeAliasRegistry.registerAlias("LRU", LruCache.class);
|
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
|
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
|
|
typeAliasRegistry.registerAlias("DB_VENDOR",
|
VendorDatabaseIdProvider.class);
|
|
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
|
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
|
|
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
|
typeAliasRegistry.registerAlias("COMMONS_LOGGING",
|
JakartaCommonsLoggingImpl.class);
|
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
|
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
|
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
|
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
|
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
|
|
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
|
typeAliasRegistry.registerAlias("JAVASSIST",
|
JavassistProxyFactory.class);
|
|
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
|
languageRegistry.register(RawLanguageDriver.class);
|
}
|
|
public String getLogPrefix() {
|
return logPrefix;
|
}
|
|
public void setLogPrefix(String logPrefix) {
|
this.logPrefix = logPrefix;
|
}
|
|
public Class<? extends Log> getLogImpl() {
|
return logImpl;
|
}
|
|
@SuppressWarnings("unchecked")
|
public void setLogImpl(Class<?> logImpl) {
|
if (logImpl != null) {
|
this.logImpl = (Class<? extends Log>) logImpl;
|
LogFactory.useCustomLogging(this.logImpl);
|
}
|
}
|
|
public boolean isCallSettersOnNulls() {
|
return callSettersOnNulls;
|
}
|
|
public void setCallSettersOnNulls(boolean callSettersOnNulls) {
|
this.callSettersOnNulls = callSettersOnNulls;
|
}
|
|
public String getDatabaseId() {
|
return databaseId;
|
}
|
|
public void setDatabaseId(String databaseId) {
|
this.databaseId = databaseId;
|
}
|
|
public Class<?> getConfigurationFactory() {
|
return configurationFactory;
|
}
|
|
public void setConfigurationFactory(Class<?> configurationFactory) {
|
this.configurationFactory = configurationFactory;
|
}
|
|
public boolean isSafeResultHandlerEnabled() {
|
return safeResultHandlerEnabled;
|
}
|
|
public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
|
this.safeResultHandlerEnabled = safeResultHandlerEnabled;
|
}
|
|
public boolean isSafeRowBoundsEnabled() {
|
return safeRowBoundsEnabled;
|
}
|
|
public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
|
this.safeRowBoundsEnabled = safeRowBoundsEnabled;
|
}
|
|
public boolean isMapUnderscoreToCamelCase() {
|
return mapUnderscoreToCamelCase;
|
}
|
|
public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
|
this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
|
}
|
|
public void addLoadedResource(String resource) {
|
loadedResources.add(resource);
|
}
|
|
public boolean isResourceLoaded(String resource) {
|
return loadedResources.contains(resource);
|
}
|
|
public Environment getEnvironment() {
|
return environment;
|
}
|
|
public void setEnvironment(Environment environment) {
|
this.environment = environment;
|
}
|
|
public AutoMappingBehavior getAutoMappingBehavior() {
|
return autoMappingBehavior;
|
}
|
|
public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
|
this.autoMappingBehavior = autoMappingBehavior;
|
}
|
|
public boolean isLazyLoadingEnabled() {
|
return lazyLoadingEnabled;
|
}
|
|
public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
|
this.lazyLoadingEnabled = lazyLoadingEnabled;
|
}
|
|
public ProxyFactory getProxyFactory() {
|
if (proxyFactory == null) {
|
// makes sure CGLIB is not needed unless explicitly requested
|
proxyFactory = new CglibProxyFactory();
|
}
|
return proxyFactory;
|
}
|
|
public void setProxyFactory(ProxyFactory proxyFactory) {
|
this.proxyFactory = proxyFactory;
|
}
|
|
public boolean isAggressiveLazyLoading() {
|
return aggressiveLazyLoading;
|
}
|
|
public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
|
this.aggressiveLazyLoading = aggressiveLazyLoading;
|
}
|
|
public boolean isMultipleResultSetsEnabled() {
|
return multipleResultSetsEnabled;
|
}
|
|
public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
|
this.multipleResultSetsEnabled = multipleResultSetsEnabled;
|
}
|
|
public Set<String> getLazyLoadTriggerMethods() {
|
return lazyLoadTriggerMethods;
|
}
|
|
public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
|
this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
|
}
|
|
public boolean isUseGeneratedKeys() {
|
return useGeneratedKeys;
|
}
|
|
public void setUseGeneratedKeys(boolean useGeneratedKeys) {
|
this.useGeneratedKeys = useGeneratedKeys;
|
}
|
|
public ExecutorType getDefaultExecutorType() {
|
return defaultExecutorType;
|
}
|
|
public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
|
this.defaultExecutorType = defaultExecutorType;
|
}
|
|
public boolean isCacheEnabled() {
|
return cacheEnabled;
|
}
|
|
public void setCacheEnabled(boolean cacheEnabled) {
|
this.cacheEnabled = cacheEnabled;
|
}
|
|
public Integer getDefaultStatementTimeout() {
|
return defaultStatementTimeout;
|
}
|
|
public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
|
this.defaultStatementTimeout = defaultStatementTimeout;
|
}
|
|
public boolean isUseColumnLabel() {
|
return useColumnLabel;
|
}
|
|
public void setUseColumnLabel(boolean useColumnLabel) {
|
this.useColumnLabel = useColumnLabel;
|
}
|
|
public LocalCacheScope getLocalCacheScope() {
|
return localCacheScope;
|
}
|
|
public void setLocalCacheScope(LocalCacheScope localCacheScope) {
|
this.localCacheScope = localCacheScope;
|
}
|
|
public JdbcType getJdbcTypeForNull() {
|
return jdbcTypeForNull;
|
}
|
|
public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
|
this.jdbcTypeForNull = jdbcTypeForNull;
|
}
|
|
public Properties getVariables() {
|
return variables;
|
}
|
|
public void setVariables(Properties variables) {
|
this.variables = variables;
|
}
|
|
public TypeHandlerRegistry getTypeHandlerRegistry() {
|
return typeHandlerRegistry;
|
}
|
|
public TypeAliasRegistry getTypeAliasRegistry() {
|
return typeAliasRegistry;
|
}
|
|
/**
|
* @since 3.2.2
|
*/
|
public MapperRegistry getMapperRegistry() {
|
return mapperRegistry;
|
}
|
|
public ObjectFactory getObjectFactory() {
|
return objectFactory;
|
}
|
|
public void setObjectFactory(ObjectFactory objectFactory) {
|
this.objectFactory = objectFactory;
|
}
|
|
public ObjectWrapperFactory getObjectWrapperFactory() {
|
return objectWrapperFactory;
|
}
|
|
public void setObjectWrapperFactory(
|
ObjectWrapperFactory objectWrapperFactory) {
|
this.objectWrapperFactory = objectWrapperFactory;
|
}
|
|
/**
|
* @since 3.2.2
|
*/
|
public List<Interceptor> getInterceptors() {
|
return interceptorChain.getInterceptors();
|
}
|
|
public LanguageDriverRegistry getLanguageRegistry() {
|
return languageRegistry;
|
}
|
|
public void setDefaultScriptingLanguage(Class<?> driver) {
|
if (driver == null) {
|
driver = XMLLanguageDriver.class;
|
}
|
getLanguageRegistry().setDefaultDriverClass(driver);
|
}
|
|
public LanguageDriver getDefaultScriptingLanuageInstance() {
|
return languageRegistry.getDefaultDriver();
|
}
|
|
public MetaObject newMetaObject(Object object) {
|
return MetaObject
|
.forObject(object, objectFactory, objectWrapperFactory);
|
}
|
|
public ParameterHandler newParameterHandler(
|
MappedStatement mappedStatement, Object parameterObject,
|
BoundSql boundSql) {
|
ParameterHandler parameterHandler = mappedStatement.getLang()
|
.createParameterHandler(mappedStatement, parameterObject,
|
boundSql);
|
parameterHandler = (ParameterHandler) interceptorChain
|
.pluginAll(parameterHandler);
|
return parameterHandler;
|
}
|
|
public ResultSetHandler newResultSetHandler(Executor executor,
|
MappedStatement mappedStatement, RowBounds rowBounds,
|
ParameterHandler parameterHandler, ResultHandler resultHandler,
|
BoundSql boundSql) {
|
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(
|
executor, mappedStatement, parameterHandler, resultHandler,
|
boundSql, rowBounds);
|
resultSetHandler = (ResultSetHandler) interceptorChain
|
.pluginAll(resultSetHandler);
|
return resultSetHandler;
|
}
|
|
public StatementHandler newStatementHandler(Executor executor,
|
MappedStatement mappedStatement, Object parameterObject,
|
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
StatementHandler statementHandler = new RoutingStatementHandler(
|
executor, mappedStatement, parameterObject, rowBounds,
|
resultHandler, boundSql);
|
statementHandler = (StatementHandler) interceptorChain
|
.pluginAll(statementHandler);
|
return statementHandler;
|
}
|
|
public Executor newExecutor(Transaction transaction) {
|
return newExecutor(transaction, defaultExecutorType);
|
}
|
|
public Executor newExecutor(Transaction transaction,
|
ExecutorType executorType) {
|
executorType = executorType == null ? defaultExecutorType
|
: executorType;
|
executorType = executorType == null ? ExecutorType.SIMPLE
|
: executorType;
|
Executor executor;
|
if (ExecutorType.BATCH == executorType) {
|
executor = new BatchExecutor(this, transaction);
|
} else if (ExecutorType.REUSE == executorType) {
|
executor = new ReuseExecutor(this, transaction);
|
} else {
|
executor = new SimpleExecutor(this, transaction);
|
}
|
if (cacheEnabled) {
|
executor = new CachingExecutor(executor);
|
}
|
executor = (Executor) interceptorChain.pluginAll(executor);
|
return executor;
|
}
|
|
public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
|
keyGenerators.put(id, keyGenerator);
|
}
|
|
public Collection<String> getKeyGeneratorNames() {
|
return keyGenerators.keySet();
|
}
|
|
public Collection<KeyGenerator> getKeyGenerators() {
|
return keyGenerators.values();
|
}
|
|
public KeyGenerator getKeyGenerator(String id) {
|
return keyGenerators.get(id);
|
}
|
|
public boolean hasKeyGenerator(String id) {
|
return keyGenerators.containsKey(id);
|
}
|
|
public void addCache(Cache cache) {
|
caches.put(cache.getId(), cache);
|
}
|
|
public Collection<String> getCacheNames() {
|
return caches.keySet();
|
}
|
|
public Collection<Cache> getCaches() {
|
return caches.values();
|
}
|
|
public Cache getCache(String id) {
|
return caches.get(id);
|
}
|
|
public boolean hasCache(String id) {
|
return caches.containsKey(id);
|
}
|
|
public void addResultMap(ResultMap rm) {
|
resultMaps.put(rm.getId(), rm);
|
checkLocallyForDiscriminatedNestedResultMaps(rm);
|
checkGloballyForDiscriminatedNestedResultMaps(rm);
|
}
|
|
public Collection<String> getResultMapNames() {
|
return resultMaps.keySet();
|
}
|
|
public Collection<ResultMap> getResultMaps() {
|
return resultMaps.values();
|
}
|
|
public ResultMap getResultMap(String id) {
|
return resultMaps.get(id);
|
}
|
|
public boolean hasResultMap(String id) {
|
return resultMaps.containsKey(id);
|
}
|
|
public void addParameterMap(ParameterMap pm) {
|
parameterMaps.put(pm.getId(), pm);
|
}
|
|
public Collection<String> getParameterMapNames() {
|
return parameterMaps.keySet();
|
}
|
|
public Collection<ParameterMap> getParameterMaps() {
|
return parameterMaps.values();
|
}
|
|
public ParameterMap getParameterMap(String id) {
|
return parameterMaps.get(id);
|
}
|
|
public boolean hasParameterMap(String id) {
|
return parameterMaps.containsKey(id);
|
}
|
|
public void addMappedStatement(MappedStatement ms) {
|
mappedStatements.put(ms.getId(), ms);
|
}
|
|
public Collection<String> getMappedStatementNames() {
|
buildAllStatements();
|
return mappedStatements.keySet();
|
}
|
|
public Collection<MappedStatement> getMappedStatements() {
|
buildAllStatements();
|
return mappedStatements.values();
|
}
|
|
public Collection<XMLStatementBuilder> getIncompleteStatements() {
|
return incompleteStatements;
|
}
|
|
public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
|
incompleteStatements.add(incompleteStatement);
|
}
|
|
public Collection<CacheRefResolver> getIncompleteCacheRefs() {
|
return incompleteCacheRefs;
|
}
|
|
public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
|
incompleteCacheRefs.add(incompleteCacheRef);
|
}
|
|
public Collection<ResultMapResolver> getIncompleteResultMaps() {
|
return incompleteResultMaps;
|
}
|
|
public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
|
incompleteResultMaps.add(resultMapResolver);
|
}
|
|
public void addIncompleteMethod(MethodResolver builder) {
|
incompleteMethods.add(builder);
|
}
|
|
public Collection<MethodResolver> getIncompleteMethods() {
|
return incompleteMethods;
|
}
|
|
public MappedStatement getMappedStatement(String id) {
|
return this.getMappedStatement(id, true);
|
}
|
|
public MappedStatement getMappedStatement(String id,
|
boolean validateIncompleteStatements) {
|
if (validateIncompleteStatements) {
|
buildAllStatements();
|
}
|
return mappedStatements.get(id);
|
}
|
|
public Map<String, XNode> getSqlFragments() {
|
return sqlFragments;
|
}
|
|
public void addInterceptor(Interceptor interceptor) {
|
interceptorChain.addInterceptor(interceptor);
|
}
|
|
public void addMappers(String packageName, Class<?> superType) {
|
mapperRegistry.addMappers(packageName, superType);
|
}
|
|
public void addMappers(String packageName) {
|
mapperRegistry.addMappers(packageName);
|
}
|
|
public <T> void addMapper(Class<T> type) {
|
mapperRegistry.addMapper(type);
|
}
|
|
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
|
return mapperRegistry.getMapper(type, sqlSession);
|
}
|
|
public boolean hasMapper(Class<?> type) {
|
return mapperRegistry.hasMapper(type);
|
}
|
|
public boolean hasStatement(String statementName) {
|
return hasStatement(statementName, true);
|
}
|
|
public boolean hasStatement(String statementName,
|
boolean validateIncompleteStatements) {
|
if (validateIncompleteStatements) {
|
buildAllStatements();
|
}
|
return mappedStatements.containsKey(statementName);
|
}
|
|
public void addCacheRef(String namespace, String referencedNamespace) {
|
cacheRefMap.put(namespace, referencedNamespace);
|
}
|
|
/*
|
* Parses all the unprocessed statement nodes in the cache. It is
|
* recommended to call this method once all the mappers are added as it
|
* provides fail-fast statement validation.
|
*/
|
protected void buildAllStatements() {
|
if (!incompleteResultMaps.isEmpty()) {
|
synchronized (incompleteResultMaps) {
|
// This always throws a BuilderException.
|
incompleteResultMaps.iterator().next().resolve();
|
}
|
}
|
if (!incompleteCacheRefs.isEmpty()) {
|
synchronized (incompleteCacheRefs) {
|
// This always throws a BuilderException.
|
incompleteCacheRefs.iterator().next().resolveCacheRef();
|
}
|
}
|
if (!incompleteStatements.isEmpty()) {
|
synchronized (incompleteStatements) {
|
// This always throws a BuilderException.
|
incompleteStatements.iterator().next().parseStatementNode();
|
}
|
}
|
if (!incompleteMethods.isEmpty()) {
|
synchronized (incompleteMethods) {
|
// This always throws a BuilderException.
|
incompleteMethods.iterator().next().resolve();
|
}
|
}
|
}
|
|
/*
|
* Extracts namespace from fully qualified statement id.
|
*
|
* @param statementId
|
*
|
* @return namespace or null when id does not contain period.
|
*/
|
protected String extractNamespace(String statementId) {
|
int lastPeriod = statementId.lastIndexOf('.');
|
return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
|
}
|
|
// Slow but a one time cost. A better solution is welcome.
|
protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
|
if (rm.hasNestedResultMaps()) {
|
for (Map.Entry<String, ResultMap> entry : resultMaps.entrySet()) {
|
Object value = entry.getValue();
|
if (value instanceof ResultMap) {
|
ResultMap entryResultMap = (ResultMap) value;
|
if (!entryResultMap.hasNestedResultMaps()
|
&& entryResultMap.getDiscriminator() != null) {
|
Collection<String> discriminatedResultMapNames = entryResultMap
|
.getDiscriminator().getDiscriminatorMap()
|
.values();
|
if (discriminatedResultMapNames.contains(rm.getId())) {
|
entryResultMap.forceNestedResultMaps();
|
}
|
}
|
}
|
}
|
}
|
}
|
|
// Slow but a one time cost. A better solution is welcome.
|
protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
|
if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
|
for (Map.Entry<String, String> entry : rm.getDiscriminator()
|
.getDiscriminatorMap().entrySet()) {
|
String discriminatedResultMapName = entry.getValue();
|
if (hasResultMap(discriminatedResultMapName)) {
|
ResultMap discriminatedResultMap = resultMaps
|
.get(discriminatedResultMapName);
|
if (discriminatedResultMap.hasNestedResultMaps()) {
|
rm.forceNestedResultMaps();
|
break;
|
}
|
}
|
}
|
}
|
}
|
|
protected static class StrictMap<V> extends HashMap<String, V> {
|
|
private static final long serialVersionUID = -4950446264854982944L;
|
private String name;
|
|
public StrictMap(String name, int initialCapacity, float loadFactor) {
|
super(initialCapacity, loadFactor);
|
this.name = name;
|
}
|
|
public StrictMap(String name, int initialCapacity) {
|
super(initialCapacity);
|
this.name = name;
|
}
|
|
public StrictMap(String name) {
|
super();
|
this.name = name;
|
}
|
|
public StrictMap(String name, Map<String, ? extends V> m) {
|
super(m);
|
this.name = name;
|
}
|
|
// TODO 如果现在状态为刷新,则刷新(先删除后添加)
|
@SuppressWarnings("unchecked")
|
public V put(String key, V value) {
|
if (org.apache.ibatis.thread.Runnable.isRefresh()) {
|
remove(key);
|
org.apache.ibatis.thread.Runnable.log.debug("refresh key:"
|
+ key.substring(key.lastIndexOf(".") + 1));
|
}
|
if (containsKey(key))
|
throw new IllegalArgumentException(name
|
+ " already contains value for " + key);
|
if (key.contains(".")) {
|
final String shortKey = getShortName(key);
|
if (super.get(shortKey) == null) {
|
super.put(shortKey, value);
|
} else {
|
super.put(shortKey, (V) new Ambiguity(shortKey));
|
}
|
}
|
return super.put(key, value);
|
}
|
|
public V get(Object key) {
|
V value = super.get(key);
|
if (value == null) {
|
throw new IllegalArgumentException(name
|
+ " does not contain value for " + key);
|
}
|
if (value instanceof Ambiguity) {
|
throw new IllegalArgumentException(
|
((Ambiguity) value).getSubject()
|
+ " is ambiguous in "
|
+ name
|
+ " (try using the full name including the namespace, or rename one of the entries)");
|
}
|
return value;
|
}
|
|
private String getShortName(String key) {
|
final String[] keyparts = key.split("\\.");
|
final String shortKey = keyparts[keyparts.length - 1];
|
return shortKey;
|
}
|
|
protected static class Ambiguity {
|
private String subject;
|
|
public Ambiguity(String subject) {
|
this.subject = subject;
|
}
|
|
public String getSubject() {
|
return subject;
|
}
|
}
|
}
|
|
}
|