|
@@ -1,438 +1,438 @@
|
|
-/**
|
|
|
|
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
|
|
|
|
- * <p>
|
|
|
|
- * 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
|
|
|
|
- * <p>
|
|
|
|
- * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
- * <p>
|
|
|
|
- * 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 com.baomidou.mybatisplus;
|
|
|
|
-
|
|
|
|
-import java.io.InputStream;
|
|
|
|
-import java.io.Reader;
|
|
|
|
-import java.util.HashSet;
|
|
|
|
-import java.util.Properties;
|
|
|
|
-import java.util.Set;
|
|
|
|
-
|
|
|
|
-import javax.sql.DataSource;
|
|
|
|
-
|
|
|
|
-import org.apache.ibatis.builder.BaseBuilder;
|
|
|
|
-import org.apache.ibatis.builder.BuilderException;
|
|
|
|
-import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
|
|
|
|
-import org.apache.ibatis.datasource.DataSourceFactory;
|
|
|
|
-import org.apache.ibatis.executor.ErrorContext;
|
|
|
|
-import org.apache.ibatis.executor.loader.ProxyFactory;
|
|
|
|
-import org.apache.ibatis.io.ResolverUtil;
|
|
|
|
-import org.apache.ibatis.io.Resources;
|
|
|
|
-import org.apache.ibatis.io.VFS;
|
|
|
|
-import org.apache.ibatis.logging.Log;
|
|
|
|
-import org.apache.ibatis.mapping.DatabaseIdProvider;
|
|
|
|
-import org.apache.ibatis.mapping.Environment;
|
|
|
|
-import org.apache.ibatis.parsing.XNode;
|
|
|
|
-import org.apache.ibatis.parsing.XPathParser;
|
|
|
|
-import org.apache.ibatis.plugin.Interceptor;
|
|
|
|
-import org.apache.ibatis.reflection.DefaultReflectorFactory;
|
|
|
|
-import org.apache.ibatis.reflection.MetaClass;
|
|
|
|
-import org.apache.ibatis.reflection.ReflectorFactory;
|
|
|
|
-import org.apache.ibatis.reflection.factory.ObjectFactory;
|
|
|
|
-import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
|
|
|
|
-import org.apache.ibatis.session.AutoMappingBehavior;
|
|
|
|
-import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior;
|
|
|
|
-import org.apache.ibatis.session.Configuration;
|
|
|
|
-import org.apache.ibatis.session.ExecutorType;
|
|
|
|
-import org.apache.ibatis.session.LocalCacheScope;
|
|
|
|
-import org.apache.ibatis.transaction.TransactionFactory;
|
|
|
|
-import org.apache.ibatis.type.JdbcType;
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * <p>
|
|
|
|
- * Copy from XMLConfigBuilder in Mybatis and replace default Configuration class
|
|
|
|
- * by MybatisConfiguration class
|
|
|
|
- * </p>
|
|
|
|
- *
|
|
|
|
- * @author hubin
|
|
|
|
- * @Date 2017-01-04
|
|
|
|
- */
|
|
|
|
-public class MybatisXMLConfigBuilder extends BaseBuilder {
|
|
|
|
-
|
|
|
|
- private boolean parsed;
|
|
|
|
- private XPathParser parser;
|
|
|
|
- private String environment;
|
|
|
|
- private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(Reader reader) {
|
|
|
|
- this(reader, null, null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(Reader reader, String environment) {
|
|
|
|
- this(reader, environment, null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(Reader reader, String environment, Properties props) {
|
|
|
|
- this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(InputStream inputStream) {
|
|
|
|
- this(inputStream, null, null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(InputStream inputStream, String environment) {
|
|
|
|
- this(inputStream, environment, null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public MybatisXMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
|
|
|
|
- this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private MybatisXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
|
|
|
|
- //TODO 自定义 Configuration
|
|
|
|
- super(new MybatisConfiguration());
|
|
|
|
- ErrorContext.instance().resource("SQL Mapper Configuration");
|
|
|
|
- this.configuration.setVariables(props);
|
|
|
|
- this.parsed = false;
|
|
|
|
- this.environment = environment;
|
|
|
|
- this.parser = parser;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public Configuration parse() {
|
|
|
|
- if (parsed) {
|
|
|
|
- throw new BuilderException("Each XMLConfigBuilder can only be used once.");
|
|
|
|
- }
|
|
|
|
- parsed = true;
|
|
|
|
- parseConfiguration(parser.evalNode("/configuration"));
|
|
|
|
- return configuration;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void parseConfiguration(XNode root) {
|
|
|
|
- try {
|
|
|
|
- //issue #117 read properties first
|
|
|
|
- propertiesElement(root.evalNode("properties"));
|
|
|
|
- Properties settings = settingsAsProperties(root.evalNode("settings"));
|
|
|
|
- loadCustomVfs(settings);
|
|
|
|
- typeAliasesElement(root.evalNode("typeAliases"));
|
|
|
|
- pluginElement(root.evalNode("plugins"));
|
|
|
|
- objectFactoryElement(root.evalNode("objectFactory"));
|
|
|
|
- objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
|
|
|
|
- reflectorFactoryElement(root.evalNode("reflectorFactory"));
|
|
|
|
- settingsElement(settings);
|
|
|
|
- // read it after objectFactory and objectWrapperFactory issue #631
|
|
|
|
- environmentsElement(root.evalNode("environments"));
|
|
|
|
- databaseIdProviderElement(root.evalNode("databaseIdProvider"));
|
|
|
|
- typeHandlerElement(root.evalNode("typeHandlers"));
|
|
|
|
- mapperElement(root.evalNode("mappers"));
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Properties settingsAsProperties(XNode context) {
|
|
|
|
- if (context == null) {
|
|
|
|
- return new Properties();
|
|
|
|
- }
|
|
|
|
- Properties props = context.getChildrenAsProperties();
|
|
|
|
- // Check that all settings are known to the configuration class
|
|
|
|
- MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
|
|
|
|
- for (Object key : props.keySet()) {
|
|
|
|
- if (!metaConfig.hasSetter(String.valueOf(key))) {
|
|
|
|
- throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return props;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void loadCustomVfs(Properties props) throws ClassNotFoundException {
|
|
|
|
- String value = props.getProperty("vfsImpl");
|
|
|
|
- if (value != null) {
|
|
|
|
- String[] clazzes = value.split(",");
|
|
|
|
- for (String clazz : clazzes) {
|
|
|
|
- if (!clazz.isEmpty()) {
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- Class<? extends VFS> vfsImpl = (Class<? extends VFS>) Resources.classForName(clazz);
|
|
|
|
- configuration.setVfsImpl(vfsImpl);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void typeAliasesElement(XNode parent) {
|
|
|
|
- if (parent != null) {
|
|
|
|
- for (XNode child : parent.getChildren()) {
|
|
|
|
- if ("package".equals(child.getName())) {
|
|
|
|
- String typeAliasPackage = child.getStringAttribute("name");
|
|
|
|
- configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
|
|
|
|
- } else {
|
|
|
|
- String alias = child.getStringAttribute("alias");
|
|
|
|
- String type = child.getStringAttribute("type");
|
|
|
|
- try {
|
|
|
|
- Class<?> clazz = Resources.classForName(type);
|
|
|
|
- if (alias == null) {
|
|
|
|
- typeAliasRegistry.registerAlias(clazz);
|
|
|
|
- } else {
|
|
|
|
- typeAliasRegistry.registerAlias(alias, clazz);
|
|
|
|
- }
|
|
|
|
- } catch (ClassNotFoundException e) {
|
|
|
|
- throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void pluginElement(XNode parent) throws Exception {
|
|
|
|
- if (parent != null) {
|
|
|
|
- for (XNode child : parent.getChildren()) {
|
|
|
|
- String interceptor = child.getStringAttribute("interceptor");
|
|
|
|
- Properties properties = child.getChildrenAsProperties();
|
|
|
|
- Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
|
|
|
|
- interceptorInstance.setProperties(properties);
|
|
|
|
- configuration.addInterceptor(interceptorInstance);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void objectFactoryElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- Properties properties = context.getChildrenAsProperties();
|
|
|
|
- ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
|
|
|
|
- factory.setProperties(properties);
|
|
|
|
- configuration.setObjectFactory(factory);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void objectWrapperFactoryElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
|
|
|
|
- configuration.setObjectWrapperFactory(factory);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void reflectorFactoryElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
|
|
|
|
- configuration.setReflectorFactory(factory);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void propertiesElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- Properties defaults = context.getChildrenAsProperties();
|
|
|
|
- String resource = context.getStringAttribute("resource");
|
|
|
|
- String url = context.getStringAttribute("url");
|
|
|
|
- if (resource != null && url != null) {
|
|
|
|
- throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
|
|
|
|
- }
|
|
|
|
- if (resource != null) {
|
|
|
|
- defaults.putAll(Resources.getResourceAsProperties(resource));
|
|
|
|
- } else if (url != null) {
|
|
|
|
- defaults.putAll(Resources.getUrlAsProperties(url));
|
|
|
|
- }
|
|
|
|
- Properties vars = configuration.getVariables();
|
|
|
|
- if (vars != null) {
|
|
|
|
- defaults.putAll(vars);
|
|
|
|
- }
|
|
|
|
- parser.setVariables(defaults);
|
|
|
|
- configuration.setVariables(defaults);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void settingsElement(Properties props) throws Exception {
|
|
|
|
- configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
|
|
|
|
- configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
|
|
|
|
- configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
|
|
|
|
- configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
|
|
|
|
- configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
|
|
|
|
- configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
|
|
|
|
- configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
|
|
|
|
- configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
|
|
|
|
- configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
|
|
|
|
- configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
|
|
|
|
- configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
|
|
|
|
- configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
|
|
|
|
- configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
|
|
|
|
- configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
|
|
|
|
- configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
|
|
|
|
- configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
|
|
|
|
- configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
|
|
|
|
- configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
|
|
|
|
- configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
|
|
|
|
- configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
|
|
|
|
- configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
|
|
|
|
- configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
|
|
|
|
- configuration.setLogPrefix(props.getProperty("logPrefix"));
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- Class<? extends Log> logImpl = (Class<? extends Log>) resolveClass(props.getProperty("logImpl"));
|
|
|
|
- configuration.setLogImpl(logImpl);
|
|
|
|
- configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void environmentsElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- if (environment == null) {
|
|
|
|
- environment = context.getStringAttribute("default");
|
|
|
|
- }
|
|
|
|
- for (XNode child : context.getChildren()) {
|
|
|
|
- String id = child.getStringAttribute("id");
|
|
|
|
- if (isSpecifiedEnvironment(id)) {
|
|
|
|
- TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
|
|
|
|
- DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
|
|
|
|
- DataSource dataSource = dsFactory.getDataSource();
|
|
|
|
- Environment.Builder environmentBuilder = new Environment.Builder(id)
|
|
|
|
- .transactionFactory(txFactory)
|
|
|
|
- .dataSource(dataSource);
|
|
|
|
- configuration.setEnvironment(environmentBuilder.build());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void databaseIdProviderElement(XNode context) throws Exception {
|
|
|
|
- DatabaseIdProvider databaseIdProvider = null;
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- // awful patch to keep backward compatibility
|
|
|
|
- if ("VENDOR".equals(type)) {
|
|
|
|
- type = "DB_VENDOR";
|
|
|
|
- }
|
|
|
|
- Properties properties = context.getChildrenAsProperties();
|
|
|
|
- databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
|
|
|
|
- databaseIdProvider.setProperties(properties);
|
|
|
|
- }
|
|
|
|
- Environment environment = configuration.getEnvironment();
|
|
|
|
- if (environment != null && databaseIdProvider != null) {
|
|
|
|
- String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
|
|
|
|
- configuration.setDatabaseId(databaseId);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private TransactionFactory transactionManagerElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- Properties props = context.getChildrenAsProperties();
|
|
|
|
- TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
|
|
|
|
- factory.setProperties(props);
|
|
|
|
- return factory;
|
|
|
|
- }
|
|
|
|
- throw new BuilderException("Environment declaration requires a TransactionFactory.");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private DataSourceFactory dataSourceElement(XNode context) throws Exception {
|
|
|
|
- if (context != null) {
|
|
|
|
- String type = context.getStringAttribute("type");
|
|
|
|
- Properties props = context.getChildrenAsProperties();
|
|
|
|
- DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
|
|
|
|
- factory.setProperties(props);
|
|
|
|
- return factory;
|
|
|
|
- }
|
|
|
|
- throw new BuilderException("Environment declaration requires a DataSourceFactory.");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void typeHandlerElement(XNode parent) throws Exception {
|
|
|
|
- if (parent != null) {
|
|
|
|
- for (XNode child : parent.getChildren()) {
|
|
|
|
- if ("package".equals(child.getName())) {
|
|
|
|
- String typeHandlerPackage = child.getStringAttribute("name");
|
|
|
|
- typeHandlerRegistry.register(typeHandlerPackage);
|
|
|
|
- } else {
|
|
|
|
- String javaTypeName = child.getStringAttribute("javaType");
|
|
|
|
- String jdbcTypeName = child.getStringAttribute("jdbcType");
|
|
|
|
- String handlerTypeName = child.getStringAttribute("handler");
|
|
|
|
- Class<?> javaTypeClass = resolveClass(javaTypeName);
|
|
|
|
- JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
|
|
|
|
- Class<?> typeHandlerClass = resolveClass(handlerTypeName);
|
|
|
|
- if (javaTypeClass != null) {
|
|
|
|
- if (jdbcType == null) {
|
|
|
|
- typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
|
|
|
|
- } else {
|
|
|
|
- typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- typeHandlerRegistry.register(typeHandlerClass);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void mapperElement(XNode parent) throws Exception {
|
|
|
|
- /**
|
|
|
|
- * 定义集合 用来分类放置mybatis的Mapper与XML 按顺序依次遍历
|
|
|
|
- */
|
|
|
|
- if (parent != null) {
|
|
|
|
- //指定在classpath中的mapper文件
|
|
|
|
- Set<String> resources = new HashSet<>();
|
|
|
|
- //指向一个mapper接口
|
|
|
|
- Set<Class<?>> mapperClasses = new HashSet<>();
|
|
|
|
- setResource(parent, resources, mapperClasses);
|
|
|
|
- // 依次遍历 首先 resource 然后 mapper
|
|
|
|
- for (String resource : resources) {
|
|
|
|
- ErrorContext.instance().resource(resource);
|
|
|
|
- InputStream inputStream = Resources.getResourceAsStream(resource);
|
|
|
|
- //TODO
|
|
|
|
- MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource,
|
|
|
|
- configuration.getSqlFragments());
|
|
|
|
- mapperParser.parse();
|
|
|
|
- }
|
|
|
|
- for (Class<?> mapper : mapperClasses) {
|
|
|
|
- //TODO
|
|
|
|
- configuration.addMapper(mapper);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 查找mybatis配置文件填充至Set集合
|
|
|
|
- *
|
|
|
|
- * @param parent 节点
|
|
|
|
- * @param resources
|
|
|
|
- * @param mapper
|
|
|
|
- * @throws ClassNotFoundException
|
|
|
|
- */
|
|
|
|
- private void setResource(XNode parent, Set<String> resources, Set<Class<?>> mapper) throws ClassNotFoundException {
|
|
|
|
- for (XNode child : parent.getChildren()) {
|
|
|
|
- if ("package".equals(child.getName())) {
|
|
|
|
- String mapperPackage = child.getStringAttribute("name");
|
|
|
|
- ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
|
|
|
|
- resolverUtil.find(new ResolverUtil.IsA(Object.class), mapperPackage);
|
|
|
|
- Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
|
|
|
|
- mapper.addAll(mapperSet);
|
|
|
|
- } else {
|
|
|
|
- String resource = child.getStringAttribute("resource");
|
|
|
|
- String url = child.getStringAttribute("url");
|
|
|
|
- String mapperClass = child.getStringAttribute("class");
|
|
|
|
- if (resource != null && url == null && mapperClass == null) {
|
|
|
|
- resources.add(resource);
|
|
|
|
- } else if (resource == null && url != null && mapperClass == null) {
|
|
|
|
- resources.add(url);
|
|
|
|
- } else if (resource == null && url == null && mapperClass != null) {
|
|
|
|
- Class<?> mapperInterface = Resources.classForName(mapperClass);
|
|
|
|
- mapper.add(mapperInterface);
|
|
|
|
- } else {
|
|
|
|
- throw new BuilderException(
|
|
|
|
- "A mapper element may only specify a url, resource or class, but not more than one.");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean isSpecifiedEnvironment(String id) {
|
|
|
|
- if (environment == null) {
|
|
|
|
- throw new BuilderException("No environment specified.");
|
|
|
|
- } else if (id == null) {
|
|
|
|
- throw new BuilderException("Environment requires an id attribute.");
|
|
|
|
- } else if (environment.equals(id)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
|
|
+/**
|
|
|
|
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
|
|
|
|
+ * <p>
|
|
|
|
+ * 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
|
|
|
|
+ * <p>
|
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
+ * <p>
|
|
|
|
+ * 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 com.baomidou.mybatisplus;
|
|
|
|
+
|
|
|
|
+import java.io.InputStream;
|
|
|
|
+import java.io.Reader;
|
|
|
|
+import java.util.HashSet;
|
|
|
|
+import java.util.Properties;
|
|
|
|
+import java.util.Set;
|
|
|
|
+
|
|
|
|
+import javax.sql.DataSource;
|
|
|
|
+
|
|
|
|
+import org.apache.ibatis.builder.BaseBuilder;
|
|
|
|
+import org.apache.ibatis.builder.BuilderException;
|
|
|
|
+import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
|
|
|
|
+import org.apache.ibatis.datasource.DataSourceFactory;
|
|
|
|
+import org.apache.ibatis.executor.ErrorContext;
|
|
|
|
+import org.apache.ibatis.executor.loader.ProxyFactory;
|
|
|
|
+import org.apache.ibatis.io.ResolverUtil;
|
|
|
|
+import org.apache.ibatis.io.Resources;
|
|
|
|
+import org.apache.ibatis.io.VFS;
|
|
|
|
+import org.apache.ibatis.logging.Log;
|
|
|
|
+import org.apache.ibatis.mapping.DatabaseIdProvider;
|
|
|
|
+import org.apache.ibatis.mapping.Environment;
|
|
|
|
+import org.apache.ibatis.parsing.XNode;
|
|
|
|
+import org.apache.ibatis.parsing.XPathParser;
|
|
|
|
+import org.apache.ibatis.plugin.Interceptor;
|
|
|
|
+import org.apache.ibatis.reflection.DefaultReflectorFactory;
|
|
|
|
+import org.apache.ibatis.reflection.MetaClass;
|
|
|
|
+import org.apache.ibatis.reflection.ReflectorFactory;
|
|
|
|
+import org.apache.ibatis.reflection.factory.ObjectFactory;
|
|
|
|
+import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
|
|
|
|
+import org.apache.ibatis.session.AutoMappingBehavior;
|
|
|
|
+import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior;
|
|
|
|
+import org.apache.ibatis.session.Configuration;
|
|
|
|
+import org.apache.ibatis.session.ExecutorType;
|
|
|
|
+import org.apache.ibatis.session.LocalCacheScope;
|
|
|
|
+import org.apache.ibatis.transaction.TransactionFactory;
|
|
|
|
+import org.apache.ibatis.type.JdbcType;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * <p>
|
|
|
|
+ * Copy from XMLConfigBuilder in Mybatis and replace default Configuration class
|
|
|
|
+ * by MybatisConfiguration class
|
|
|
|
+ * </p>
|
|
|
|
+ *
|
|
|
|
+ * @author hubin
|
|
|
|
+ * @Date 2017-01-04
|
|
|
|
+ */
|
|
|
|
+public class MybatisXMLConfigBuilder extends BaseBuilder {
|
|
|
|
+
|
|
|
|
+ private boolean parsed;
|
|
|
|
+ private XPathParser parser;
|
|
|
|
+ private String environment;
|
|
|
|
+ private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(Reader reader) {
|
|
|
|
+ this(reader, null, null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(Reader reader, String environment) {
|
|
|
|
+ this(reader, environment, null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(Reader reader, String environment, Properties props) {
|
|
|
|
+ this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(InputStream inputStream) {
|
|
|
|
+ this(inputStream, null, null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(InputStream inputStream, String environment) {
|
|
|
|
+ this(inputStream, environment, null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public MybatisXMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
|
|
|
|
+ this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private MybatisXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
|
|
|
|
+ //TODO 自定义 Configuration
|
|
|
|
+ super(new MybatisConfiguration());
|
|
|
|
+ ErrorContext.instance().resource("SQL Mapper Configuration");
|
|
|
|
+ this.configuration.setVariables(props);
|
|
|
|
+ this.parsed = false;
|
|
|
|
+ this.environment = environment;
|
|
|
|
+ this.parser = parser;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public Configuration parse() {
|
|
|
|
+ if (parsed) {
|
|
|
|
+ throw new BuilderException("Each XMLConfigBuilder can only be used once.");
|
|
|
|
+ }
|
|
|
|
+ parsed = true;
|
|
|
|
+ parseConfiguration(parser.evalNode("/configuration"));
|
|
|
|
+ return configuration;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void parseConfiguration(XNode root) {
|
|
|
|
+ try {
|
|
|
|
+ //issue #117 read properties first
|
|
|
|
+ propertiesElement(root.evalNode("properties"));
|
|
|
|
+ Properties settings = settingsAsProperties(root.evalNode("settings"));
|
|
|
|
+ loadCustomVfs(settings);
|
|
|
|
+ typeAliasesElement(root.evalNode("typeAliases"));
|
|
|
|
+ pluginElement(root.evalNode("plugins"));
|
|
|
|
+ objectFactoryElement(root.evalNode("objectFactory"));
|
|
|
|
+ objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
|
|
|
|
+ reflectorFactoryElement(root.evalNode("reflectorFactory"));
|
|
|
|
+ settingsElement(settings);
|
|
|
|
+ // read it after objectFactory and objectWrapperFactory issue #631
|
|
|
|
+ environmentsElement(root.evalNode("environments"));
|
|
|
|
+ databaseIdProviderElement(root.evalNode("databaseIdProvider"));
|
|
|
|
+ typeHandlerElement(root.evalNode("typeHandlers"));
|
|
|
|
+ mapperElement(root.evalNode("mappers"));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Properties settingsAsProperties(XNode context) {
|
|
|
|
+ if (context == null) {
|
|
|
|
+ return new Properties();
|
|
|
|
+ }
|
|
|
|
+ Properties props = context.getChildrenAsProperties();
|
|
|
|
+ // Check that all settings are known to the configuration class
|
|
|
|
+ MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
|
|
|
|
+ for (Object key : props.keySet()) {
|
|
|
|
+ if (!metaConfig.hasSetter(String.valueOf(key))) {
|
|
|
|
+ throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return props;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void loadCustomVfs(Properties props) throws ClassNotFoundException {
|
|
|
|
+ String value = props.getProperty("vfsImpl");
|
|
|
|
+ if (value != null) {
|
|
|
|
+ String[] clazzes = value.split(",");
|
|
|
|
+ for (String clazz : clazzes) {
|
|
|
|
+ if (!clazz.isEmpty()) {
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ Class<? extends VFS> vfsImpl = (Class<? extends VFS>) Resources.classForName(clazz);
|
|
|
|
+ configuration.setVfsImpl(vfsImpl);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void typeAliasesElement(XNode parent) {
|
|
|
|
+ if (parent != null) {
|
|
|
|
+ for (XNode child : parent.getChildren()) {
|
|
|
|
+ if ("package".equals(child.getName())) {
|
|
|
|
+ String typeAliasPackage = child.getStringAttribute("name");
|
|
|
|
+ configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
|
|
|
|
+ } else {
|
|
|
|
+ String alias = child.getStringAttribute("alias");
|
|
|
|
+ String type = child.getStringAttribute("type");
|
|
|
|
+ try {
|
|
|
|
+ Class<?> clazz = Resources.classForName(type);
|
|
|
|
+ if (alias == null) {
|
|
|
|
+ typeAliasRegistry.registerAlias(clazz);
|
|
|
|
+ } else {
|
|
|
|
+ typeAliasRegistry.registerAlias(alias, clazz);
|
|
|
|
+ }
|
|
|
|
+ } catch (ClassNotFoundException e) {
|
|
|
|
+ throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void pluginElement(XNode parent) throws Exception {
|
|
|
|
+ if (parent != null) {
|
|
|
|
+ for (XNode child : parent.getChildren()) {
|
|
|
|
+ String interceptor = child.getStringAttribute("interceptor");
|
|
|
|
+ Properties properties = child.getChildrenAsProperties();
|
|
|
|
+ Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
|
|
|
|
+ interceptorInstance.setProperties(properties);
|
|
|
|
+ configuration.addInterceptor(interceptorInstance);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void objectFactoryElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ Properties properties = context.getChildrenAsProperties();
|
|
|
|
+ ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
|
|
|
|
+ factory.setProperties(properties);
|
|
|
|
+ configuration.setObjectFactory(factory);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void objectWrapperFactoryElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
|
|
|
|
+ configuration.setObjectWrapperFactory(factory);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void reflectorFactoryElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
|
|
|
|
+ configuration.setReflectorFactory(factory);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void propertiesElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ Properties defaults = context.getChildrenAsProperties();
|
|
|
|
+ String resource = context.getStringAttribute("resource");
|
|
|
|
+ String url = context.getStringAttribute("url");
|
|
|
|
+ if (resource != null && url != null) {
|
|
|
|
+ throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
|
|
|
|
+ }
|
|
|
|
+ if (resource != null) {
|
|
|
|
+ defaults.putAll(Resources.getResourceAsProperties(resource));
|
|
|
|
+ } else if (url != null) {
|
|
|
|
+ defaults.putAll(Resources.getUrlAsProperties(url));
|
|
|
|
+ }
|
|
|
|
+ Properties vars = configuration.getVariables();
|
|
|
|
+ if (vars != null) {
|
|
|
|
+ defaults.putAll(vars);
|
|
|
|
+ }
|
|
|
|
+ parser.setVariables(defaults);
|
|
|
|
+ configuration.setVariables(defaults);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void settingsElement(Properties props) throws Exception {
|
|
|
|
+ configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
|
|
|
|
+ configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
|
|
|
|
+ configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
|
|
|
|
+ configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
|
|
|
|
+ configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
|
|
|
|
+ configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
|
|
|
|
+ configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
|
|
|
|
+ configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
|
|
|
|
+ configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
|
|
|
|
+ configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
|
|
|
|
+ configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
|
|
|
|
+ configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
|
|
|
|
+ configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
|
|
|
|
+ configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
|
|
|
|
+ configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
|
|
|
|
+ configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
|
|
|
|
+ configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
|
|
|
|
+ configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
|
|
|
|
+ configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
|
|
|
|
+ configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
|
|
|
|
+ configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
|
|
|
|
+ configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
|
|
|
|
+ configuration.setLogPrefix(props.getProperty("logPrefix"));
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ Class<? extends Log> logImpl = (Class<? extends Log>) resolveClass(props.getProperty("logImpl"));
|
|
|
|
+ configuration.setLogImpl(logImpl);
|
|
|
|
+ configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void environmentsElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ if (environment == null) {
|
|
|
|
+ environment = context.getStringAttribute("default");
|
|
|
|
+ }
|
|
|
|
+ for (XNode child : context.getChildren()) {
|
|
|
|
+ String id = child.getStringAttribute("id");
|
|
|
|
+ if (isSpecifiedEnvironment(id)) {
|
|
|
|
+ TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
|
|
|
|
+ DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
|
|
|
|
+ DataSource dataSource = dsFactory.getDataSource();
|
|
|
|
+ Environment.Builder environmentBuilder = new Environment.Builder(id)
|
|
|
|
+ .transactionFactory(txFactory)
|
|
|
|
+ .dataSource(dataSource);
|
|
|
|
+ configuration.setEnvironment(environmentBuilder.build());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void databaseIdProviderElement(XNode context) throws Exception {
|
|
|
|
+ DatabaseIdProvider databaseIdProvider = null;
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ // awful patch to keep backward compatibility
|
|
|
|
+ if ("VENDOR".equals(type)) {
|
|
|
|
+ type = "DB_VENDOR";
|
|
|
|
+ }
|
|
|
|
+ Properties properties = context.getChildrenAsProperties();
|
|
|
|
+ databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
|
|
|
|
+ databaseIdProvider.setProperties(properties);
|
|
|
|
+ }
|
|
|
|
+ Environment environment = configuration.getEnvironment();
|
|
|
|
+ if (environment != null && databaseIdProvider != null) {
|
|
|
|
+ String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
|
|
|
|
+ configuration.setDatabaseId(databaseId);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private TransactionFactory transactionManagerElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ Properties props = context.getChildrenAsProperties();
|
|
|
|
+ TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
|
|
|
|
+ factory.setProperties(props);
|
|
|
|
+ return factory;
|
|
|
|
+ }
|
|
|
|
+ throw new BuilderException("Environment declaration requires a TransactionFactory.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private DataSourceFactory dataSourceElement(XNode context) throws Exception {
|
|
|
|
+ if (context != null) {
|
|
|
|
+ String type = context.getStringAttribute("type");
|
|
|
|
+ Properties props = context.getChildrenAsProperties();
|
|
|
|
+ DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
|
|
|
|
+ factory.setProperties(props);
|
|
|
|
+ return factory;
|
|
|
|
+ }
|
|
|
|
+ throw new BuilderException("Environment declaration requires a DataSourceFactory.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void typeHandlerElement(XNode parent) throws Exception {
|
|
|
|
+ if (parent != null) {
|
|
|
|
+ for (XNode child : parent.getChildren()) {
|
|
|
|
+ if ("package".equals(child.getName())) {
|
|
|
|
+ String typeHandlerPackage = child.getStringAttribute("name");
|
|
|
|
+ typeHandlerRegistry.register(typeHandlerPackage);
|
|
|
|
+ } else {
|
|
|
|
+ String javaTypeName = child.getStringAttribute("javaType");
|
|
|
|
+ String jdbcTypeName = child.getStringAttribute("jdbcType");
|
|
|
|
+ String handlerTypeName = child.getStringAttribute("handler");
|
|
|
|
+ Class<?> javaTypeClass = resolveClass(javaTypeName);
|
|
|
|
+ JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
|
|
|
|
+ Class<?> typeHandlerClass = resolveClass(handlerTypeName);
|
|
|
|
+ if (javaTypeClass != null) {
|
|
|
|
+ if (jdbcType == null) {
|
|
|
|
+ typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
|
|
|
|
+ } else {
|
|
|
|
+ typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ typeHandlerRegistry.register(typeHandlerClass);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void mapperElement(XNode parent) throws Exception {
|
|
|
|
+ /**
|
|
|
|
+ * 定义集合 用来分类放置mybatis的Mapper与XML 按顺序依次遍历
|
|
|
|
+ */
|
|
|
|
+ if (parent != null) {
|
|
|
|
+ //指定在classpath中的mapper文件
|
|
|
|
+ Set<String> resources = new HashSet<>();
|
|
|
|
+ //指向一个mapper接口
|
|
|
|
+ Set<Class<?>> mapperClasses = new HashSet<>();
|
|
|
|
+ setResource(parent, resources, mapperClasses);
|
|
|
|
+ // 依次遍历 首先 resource 然后 mapper
|
|
|
|
+ for (String resource : resources) {
|
|
|
|
+ ErrorContext.instance().resource(resource);
|
|
|
|
+ InputStream inputStream = Resources.getResourceAsStream(resource);
|
|
|
|
+ //TODO
|
|
|
|
+ MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource,
|
|
|
|
+ configuration.getSqlFragments());
|
|
|
|
+ mapperParser.parse();
|
|
|
|
+ }
|
|
|
|
+ for (Class<?> mapper : mapperClasses) {
|
|
|
|
+ //TODO
|
|
|
|
+ configuration.addMapper(mapper);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查找mybatis配置文件填充至Set集合
|
|
|
|
+ *
|
|
|
|
+ * @param parent 节点
|
|
|
|
+ * @param resources
|
|
|
|
+ * @param mapper
|
|
|
|
+ * @throws ClassNotFoundException
|
|
|
|
+ */
|
|
|
|
+ private void setResource(XNode parent, Set<String> resources, Set<Class<?>> mapper) throws ClassNotFoundException {
|
|
|
|
+ for (XNode child : parent.getChildren()) {
|
|
|
|
+ if ("package".equals(child.getName())) {
|
|
|
|
+ String mapperPackage = child.getStringAttribute("name");
|
|
|
|
+ ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
|
|
|
|
+ resolverUtil.find(new ResolverUtil.IsA(Object.class), mapperPackage);
|
|
|
|
+ Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
|
|
|
|
+ mapper.addAll(mapperSet);
|
|
|
|
+ } else {
|
|
|
|
+ String resource = child.getStringAttribute("resource");
|
|
|
|
+ String url = child.getStringAttribute("url");
|
|
|
|
+ String mapperClass = child.getStringAttribute("class");
|
|
|
|
+ if (resource != null && url == null && mapperClass == null) {
|
|
|
|
+ resources.add(resource);
|
|
|
|
+ } else if (resource == null && url != null && mapperClass == null) {
|
|
|
|
+ resources.add(url);
|
|
|
|
+ } else if (resource == null && url == null && mapperClass != null) {
|
|
|
|
+ Class<?> mapperInterface = Resources.classForName(mapperClass);
|
|
|
|
+ mapper.add(mapperInterface);
|
|
|
|
+ } else {
|
|
|
|
+ throw new BuilderException(
|
|
|
|
+ "A mapper element may only specify a url, resource or class, but not more than one.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean isSpecifiedEnvironment(String id) {
|
|
|
|
+ if (environment == null) {
|
|
|
|
+ throw new BuilderException("No environment specified.");
|
|
|
|
+ } else if (id == null) {
|
|
|
|
+ throw new BuilderException("Environment requires an id attribute.");
|
|
|
|
+ } else if (environment.equals(id)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|