Browse Source

升级mybatis至3.5.16

nieqiurong 1 year ago
parent
commit
11a230f5dd

+ 1 - 1
build.gradle

@@ -11,7 +11,7 @@ ext {
     ]
 
     libraries = [
-        mybatisVersion = '3.5.15',
+        mybatisVersion = '3.5.16',
         mybatisSpringVersion = '2.1.2',
         mybatisSpringBootStarterVersion = '2.3.1',
         springVersion = '5.3.27',

+ 35 - 11
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java

@@ -42,9 +42,9 @@ import org.apache.ibatis.transaction.Transaction;
 import org.apache.ibatis.type.TypeHandler;
 
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiFunction;
 import java.util.stream.Collectors;
 
@@ -366,15 +366,16 @@ public class MybatisConfiguration extends Configuration {
 
     // Slow but a one time cost. A better solution is welcome.
     @Override
-    protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
+    public 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;
+            final String resultMapId = rm.getId();
+            for (Object resultMapObject : resultMaps.values()) {
+                if (resultMapObject instanceof ResultMap) {
+                    ResultMap entryResultMap = (ResultMap) resultMapObject;
                     if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
-                        Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap().values();
-                        if (discriminatedResultMapNames.contains(rm.getId())) {
+                        Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap()
+                            .values();
+                        if (discriminatedResultMapNames.contains(resultMapId)) {
                             entryResultMap.forceNestedResultMaps();
                         }
                     }
@@ -387,8 +388,7 @@ public class MybatisConfiguration extends Configuration {
     @Override
     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();
+            for (String discriminatedResultMapName : rm.getDiscriminator().getDiscriminatorMap().values()) {
                 if (hasResultMap(discriminatedResultMapName)) {
                     ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);
                     if (discriminatedResultMap.hasNestedResultMaps()) {
@@ -400,17 +400,32 @@ public class MybatisConfiguration extends Configuration {
         }
     }
 
-    protected class StrictMap<V> extends HashMap<String, V> {
+    protected class StrictMap<V> extends ConcurrentHashMap<String, V> {
 
         private static final long serialVersionUID = -4950446264854982944L;
         private final String name;
         private BiFunction<V, V, String> conflictMessageProducer;
 
+        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;
+        }
+
         /**
          * Assign a function for producing a conflict error message when contains value with the same key.
          * <p>
@@ -445,6 +460,15 @@ public class MybatisConfiguration extends Configuration {
             return super.put(key, value);
         }
 
+        @Override
+        public boolean containsKey(Object key) {
+            if (key == null) {
+                return false;
+            }
+
+            return super.get(key) != null;
+        }
+
         @Override
         public V get(Object key) {
             V value = super.get(key);

+ 103 - 110
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder.java

@@ -20,7 +20,6 @@ import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
 import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
 import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
-import lombok.Getter;
 import org.apache.ibatis.annotations.*;
 import org.apache.ibatis.annotations.ResultMap;
 import org.apache.ibatis.annotations.Options.FlushCachePolicy;
@@ -29,7 +28,6 @@ import org.apache.ibatis.builder.BuilderException;
 import org.apache.ibatis.builder.CacheRefResolver;
 import org.apache.ibatis.builder.IncompleteElementException;
 import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
-import org.apache.ibatis.builder.annotation.MethodResolver;
 import org.apache.ibatis.builder.annotation.ProviderSqlSource;
 import org.apache.ibatis.cursor.Cursor;
 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
@@ -121,32 +119,18 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                 configuration.addIncompleteMethod(new InjectorResolver(this));
             }
         }
-        parsePendingMethods();
+        configuration.parsePendingMethods(false);
     }
 
     void parserInjector() {
         GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);
     }
 
-    private boolean canHaveStatement(Method method) {
+    private static boolean canHaveStatement(Method method) {
         // issue #237
         return !method.isBridge() && !method.isDefault();
     }
 
-    private void parsePendingMethods() {
-        Collection<MethodResolver> incompleteMethods = configuration.getIncompleteMethods();
-        synchronized (incompleteMethods) {
-            Iterator<MethodResolver> iter = incompleteMethods.iterator();
-            while (iter.hasNext()) {
-                try {
-                    iter.next().resolve();
-                    iter.remove();
-                } catch (IncompleteElementException e) {
-                    // This method is still missing a resource
-                }
-            }
-        }
-    }
 
     private void loadXmlResource() {
         // Spring may not know the real resource name so we check a flag
@@ -177,7 +161,8 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
             Integer size = cacheDomain.size() == 0 ? null : cacheDomain.size();
             Long flushInterval = cacheDomain.flushInterval() == 0 ? null : cacheDomain.flushInterval();
             Properties props = convertToProperties(cacheDomain.properties());
-            assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size, cacheDomain.readWrite(), cacheDomain.blocking(), props);
+            assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size,
+                cacheDomain.readWrite(), cacheDomain.blocking(), props);
         }
     }
 
@@ -187,8 +172,7 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         }
         Properties props = new Properties();
         for (Property property : properties) {
-            props.setProperty(property.name(),
-                PropertyParser.parse(property.value(), configuration.getVariables()));
+            props.setProperty(property.name(), PropertyParser.parse(property.value(), configuration.getVariables()));
         }
         return props;
     }
@@ -204,7 +188,7 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
             if (refType != void.class && !refName.isEmpty()) {
                 throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");
             }
-            String namespace = (refType != void.class) ? refType.getName() : refName;
+            String namespace = refType != void.class ? refType.getName() : refName;
             try {
                 assistant.useCacheRef(namespace);
             } catch (IncompleteElementException e) {
@@ -214,7 +198,7 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
     }
 
     private String parseResultMap(Method method) {
-        Class<?> returnType = getReturnType(method);
+        Class<?> returnType = getReturnType(method, type);
         Arg[] args = method.getAnnotationsByType(Arg.class);
         Result[] results = method.getAnnotationsByType(Result.class);
         TypeDiscriminator typeDiscriminator = method.getAnnotation(TypeDiscriminator.class);
@@ -226,24 +210,26 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
     private String generateResultMapName(Method method) {
         Results results = method.getAnnotation(Results.class);
         if (results != null && !results.id().isEmpty()) {
-            return type.getName() + StringPool.DOT + results.id();
+            return type.getName() + "." + results.id();
         }
         StringBuilder suffix = new StringBuilder();
         for (Class<?> c : method.getParameterTypes()) {
-            suffix.append(StringPool.DASH);
+            suffix.append("-");
             suffix.append(c.getSimpleName());
         }
         if (suffix.length() < 1) {
             suffix.append("-void");
         }
-        return type.getName() + StringPool.DOT + method.getName() + suffix;
+        return type.getName() + "." + method.getName() + suffix;
     }
 
-    private void applyResultMap(String resultMapId, Class<?> returnType, Arg[] args, Result[] results, TypeDiscriminator discriminator) {
+    private void applyResultMap(String resultMapId, Class<?> returnType, Arg[] args, Result[] results,
+                                TypeDiscriminator discriminator) {
         List<ResultMapping> resultMappings = new ArrayList<>();
         applyConstructorArgs(args, returnType, resultMappings);
         applyResults(results, returnType, resultMappings);
         Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator);
+        // TODO add AutoMappingBehaviour
         assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);
         createDiscriminatorResultMaps(resultMapId, returnType, discriminator);
     }
@@ -251,11 +237,12 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
     private void createDiscriminatorResultMaps(String resultMapId, Class<?> resultType, TypeDiscriminator discriminator) {
         if (discriminator != null) {
             for (Case c : discriminator.cases()) {
-                String caseResultMapId = resultMapId + StringPool.DASH + c.value();
+                String caseResultMapId = resultMapId + "-" + c.value();
                 List<ResultMapping> resultMappings = new ArrayList<>();
                 // issue #136
                 applyConstructorArgs(c.constructArgs(), resultType, resultMappings);
                 applyResults(c.results(), resultType, resultMappings);
+                // TODO add AutoMappingBehaviour
                 assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null);
             }
         }
@@ -267,13 +254,13 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
             Class<?> javaType = discriminator.javaType() == void.class ? String.class : discriminator.javaType();
             JdbcType jdbcType = discriminator.jdbcType() == JdbcType.UNDEFINED ? null : discriminator.jdbcType();
             @SuppressWarnings("unchecked")
-            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
-                (discriminator.typeHandler() == UnknownTypeHandler.class ? null : discriminator.typeHandler());
+            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) (discriminator
+                .typeHandler() == UnknownTypeHandler.class ? null : discriminator.typeHandler());
             Case[] cases = discriminator.cases();
             Map<String, String> discriminatorMap = new HashMap<>();
             for (Case c : cases) {
                 String value = c.value();
-                String caseResultMapId = resultMapId + StringPool.DASH + value;
+                String caseResultMapId = resultMapId + "-" + value;
                 discriminatorMap.put(value, caseResultMapId);
             }
             return assistant.buildDiscriminator(resultType, column, javaType, jdbcType, typeHandler, discriminatorMap);
@@ -286,19 +273,23 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         final LanguageDriver languageDriver = getLanguageDriver(method);
 
         getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {
-            final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);
+            final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass,
+                languageDriver, method);
             final SqlCommandType sqlCommandType = statementAnnotation.getSqlCommandType();
-            final Options options = getAnnotationWrapper(method, false, Options.class).map(x -> (Options) x.getAnnotation()).orElse(null);
-            final String mappedStatementId = type.getName() + StringPool.DOT + method.getName();
+            final Options options = getAnnotationWrapper(method, false, Options.class).map(x -> (Options) x.getAnnotation())
+                .orElse(null);
+            final String mappedStatementId = type.getName() + "." + method.getName();
 
             final KeyGenerator keyGenerator;
             String keyProperty = null;
             String keyColumn = null;
             if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                 // first check for SelectKey annotation - that overrides everything else
-                SelectKey selectKey = getAnnotationWrapper(method, false, SelectKey.class).map(x -> (SelectKey) x.getAnnotation()).orElse(null);
+                SelectKey selectKey = getAnnotationWrapper(method, false, SelectKey.class)
+                    .map(x -> (SelectKey) x.getAnnotation()).orElse(null);
                 if (selectKey != null) {
-                    keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
+                    keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method),
+                        languageDriver);
                     keyProperty = selectKey.keyProperty();
                 } else if (options == null) {
                     keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
@@ -325,7 +316,8 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                     flushCache = false;
                 }
                 useCache = options.useCache();
-                fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
+                // issue #348
+                fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null;
                 timeout = options.timeout() > -1 ? options.timeout() : null;
                 statementType = options.statementType();
                 if (options.resultSetType() != ResultSetType.DEFAULT) {
@@ -337,35 +329,19 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
             if (isSelect) {
                 ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
                 if (resultMapAnnotation != null) {
-                    resultMapId = String.join(StringPool.COMMA, resultMapAnnotation.value());
+                    resultMapId = String.join(",", resultMapAnnotation.value());
                 } else {
                     resultMapId = generateResultMapName(method);
                 }
             }
 
-            assistant.addMappedStatement(
-                mappedStatementId,
-                sqlSource,
-                statementType,
-                sqlCommandType,
-                fetchSize,
-                timeout,
+            assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout,
                 // ParameterMapID
-                null,
-                parameterTypeClass,
-                resultMapId,
-                getReturnType(method),
-                resultSetType,
-                flushCache,
-                useCache,
-                false,
-                keyGenerator,
-                keyProperty,
-                keyColumn,
-                statementAnnotation.getDatabaseId(),
-                languageDriver,
+                null, parameterTypeClass, resultMapId, getReturnType(method, type), resultSetType, flushCache, useCache,
+                // TODO gcode issue #577
+                false, keyGenerator, keyProperty, keyColumn, statementAnnotation.getDatabaseId(), languageDriver,
                 // ResultSets
-                options != null ? nullOrEmpty(options.resultSets()) : null);
+                options != null ? nullOrEmpty(options.resultSets()) : null, statementAnnotation.isDirtySelect());
         });
     }
 
@@ -382,7 +358,8 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         Class<?> parameterType = null;
         Class<?>[] parameterTypes = method.getParameterTypes();
         for (Class<?> currentParameterType : parameterTypes) {
-            if (!RowBounds.class.isAssignableFrom(currentParameterType) && !ResultHandler.class.isAssignableFrom(currentParameterType)) {
+            if (!RowBounds.class.isAssignableFrom(currentParameterType)
+                && !ResultHandler.class.isAssignableFrom(currentParameterType)) {
                 if (parameterType == null) {
                     parameterType = currentParameterType;
                 } else {
@@ -394,7 +371,7 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         return parameterType;
     }
 
-    private Class<?> getReturnType(Method method) {
+    private static Class<?> getReturnType(Method method, Class<?> type) {
         Class<?> returnType = method.getReturnType();
         Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, type);
         if (resolvedReturnType instanceof Class) {
@@ -467,24 +444,15 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                 flags.add(ResultFlag.ID);
             }
             @SuppressWarnings("unchecked")
-            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
-                ((result.typeHandler() == UnknownTypeHandler.class) ? null : result.typeHandler());
+            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) (result
+                .typeHandler() == UnknownTypeHandler.class ? null : result.typeHandler());
             boolean hasNestedResultMap = hasNestedResultMap(result);
-            ResultMapping resultMapping = assistant.buildResultMapping(
-                resultType,
-                nullOrEmpty(result.property()),
-                nullOrEmpty(result.column()),
-                result.javaType() == void.class ? null : result.javaType(),
+            ResultMapping resultMapping = assistant.buildResultMapping(resultType, nullOrEmpty(result.property()),
+                nullOrEmpty(result.column()), result.javaType() == void.class ? null : result.javaType(),
                 result.jdbcType() == JdbcType.UNDEFINED ? null : result.jdbcType(),
                 hasNestedSelect(result) ? nestedSelectId(result) : null,
-                hasNestedResultMap ? nestedResultMapId(result) : null,
-                null,
-                hasNestedResultMap ? findColumnPrefix(result) : null,
-                typeHandler,
-                flags,
-                null,
-                null,
-                isLazy(result));
+                hasNestedResultMap ? nestedResultMapId(result) : null, null,
+                hasNestedResultMap ? findColumnPrefix(result) : null, typeHandler, flags, null, null, isLazy(result));
             resultMappings.add(resultMapping);
         }
     }
@@ -551,23 +519,12 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                 flags.add(ResultFlag.ID);
             }
             @SuppressWarnings("unchecked")
-            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
-                (arg.typeHandler() == UnknownTypeHandler.class ? null : arg.typeHandler());
-            ResultMapping resultMapping = assistant.buildResultMapping(
-                resultType,
-                nullOrEmpty(arg.name()),
-                nullOrEmpty(arg.column()),
-                arg.javaType() == void.class ? null : arg.javaType(),
-                arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(),
-                nullOrEmpty(arg.select()),
-                nullOrEmpty(arg.resultMap()),
-                null,
-                nullOrEmpty(arg.columnPrefix()),
-                typeHandler,
-                flags,
-                null,
-                null,
-                false);
+            Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) (arg
+                .typeHandler() == UnknownTypeHandler.class ? null : arg.typeHandler());
+            ResultMapping resultMapping = assistant.buildResultMapping(resultType, nullOrEmpty(arg.name()),
+                nullOrEmpty(arg.column()), arg.javaType() == void.class ? null : arg.javaType(),
+                arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(), nullOrEmpty(arg.select()),
+                nullOrEmpty(arg.resultMap()), null, nullOrEmpty(arg.columnPrefix()), typeHandler, flags, null, null, false);
             resultMappings.add(resultMapping);
         }
     }
@@ -576,7 +533,8 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         return value == null || value.trim().length() == 0 ? null : value;
     }
 
-    private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class<?> parameterTypeClass, LanguageDriver languageDriver) {
+    private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId,
+                                                   Class<?> parameterTypeClass, LanguageDriver languageDriver) {
         String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
         Class<?> resultTypeClass = selectKeyAnnotation.resultType();
         StatementType statementType = selectKeyAnnotation.statementType();
@@ -598,9 +556,9 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
         SqlSource sqlSource = buildSqlSource(selectKeyAnnotation, parameterTypeClass, languageDriver, null);
         SqlCommandType sqlCommandType = SqlCommandType.SELECT;
 
-        assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum,
-            flushCache, useCache, false,
-            keyGenerator, keyProperty, keyColumn, databaseId, languageDriver, null);
+        assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap,
+            parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator,
+            keyProperty, keyColumn, databaseId, languageDriver, null, false);
 
         id = assistant.applyCurrentNamespace(id, false);
 
@@ -614,7 +572,8 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                                      Method method) {
         if (annotation instanceof Select) {
             return buildSqlSourceFromStrings(((Select) annotation).value(), parameterType, languageDriver);
-        } else if (annotation instanceof Update) {
+        }
+        if (annotation instanceof Update) {
             return buildSqlSourceFromStrings(((Update) annotation).value(), parameterType, languageDriver);
         } else if (annotation instanceof Insert) {
             return buildSqlSourceFromStrings(((Insert) annotation).value(), parameterType, languageDriver);
@@ -633,48 +592,65 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
 
     @SafeVarargs
     private final Optional<AnnotationWrapper> getAnnotationWrapper(Method method, boolean errorIfNoMatch,
-                                                                   Class<? extends Annotation>... targetTypes) {
+                                                                                           Class<? extends Annotation>... targetTypes) {
         return getAnnotationWrapper(method, errorIfNoMatch, Arrays.asList(targetTypes));
     }
 
     private Optional<AnnotationWrapper> getAnnotationWrapper(Method method, boolean errorIfNoMatch,
-                                                             Collection<Class<? extends Annotation>> targetTypes) {
+                                                                                     Collection<Class<? extends Annotation>> targetTypes) {
         String databaseId = configuration.getDatabaseId();
         Map<String, AnnotationWrapper> statementAnnotations = targetTypes.stream()
             .flatMap(x -> Arrays.stream(method.getAnnotationsByType(x))).map(AnnotationWrapper::new)
             .collect(Collectors.toMap(AnnotationWrapper::getDatabaseId, x -> x, (existing, duplicate) -> {
-                throw new BuilderException(String.format("Detected conflicting annotations '%s' and '%s' on '%s'.",
-                    existing.getAnnotation(), duplicate.getAnnotation(),
-                    method.getDeclaringClass().getName() + StringPool.DOT + method.getName()));
+                throw new BuilderException(
+                    String.format("Detected conflicting annotations '%s' and '%s' on '%s'.", existing.getAnnotation(),
+                        duplicate.getAnnotation(), method.getDeclaringClass().getName() + "." + method.getName()));
             }));
         AnnotationWrapper annotationWrapper = null;
         if (databaseId != null) {
             annotationWrapper = statementAnnotations.get(databaseId);
         }
         if (annotationWrapper == null) {
-            annotationWrapper = statementAnnotations.get(StringPool.EMPTY);
+            annotationWrapper = statementAnnotations.get("");
         }
         if (errorIfNoMatch && annotationWrapper == null && !statementAnnotations.isEmpty()) {
             // Annotations exist, but there is no matching one for the specified databaseId
-            throw new BuilderException(
-                String.format(
-                    "Could not find a statement annotation that correspond a current database or default statement on method '%s.%s'. Current database id is [%s].",
-                    method.getDeclaringClass().getName(), method.getName(), databaseId));
+            throw new BuilderException(String.format(
+                "Could not find a statement annotation that correspond a current database or default statement on method '%s.%s'. Current database id is [%s].",
+                method.getDeclaringClass().getName(), method.getName(), databaseId));
         }
         return Optional.ofNullable(annotationWrapper);
     }
 
-    @Getter
-    private class AnnotationWrapper {
+    public static Class<?> getMethodReturnType(String mapperFqn, String localStatementId) {
+        if (mapperFqn == null || localStatementId == null) {
+            return null;
+        }
+        try {
+            Class<?> mapperClass = Resources.classForName(mapperFqn);
+            for (Method method : mapperClass.getMethods()) {
+                if (method.getName().equals(localStatementId) && canHaveStatement(method)) {
+                    return getReturnType(method, mapperClass);
+                }
+            }
+        } catch (ClassNotFoundException e) {
+            // No corresponding mapper interface which is OK
+        }
+        return null;
+    }
+
+    private static class AnnotationWrapper {
         private final Annotation annotation;
         private final String databaseId;
         private final SqlCommandType sqlCommandType;
+        private boolean dirtySelect;
 
         AnnotationWrapper(Annotation annotation) {
             this.annotation = annotation;
             if (annotation instanceof Select) {
                 databaseId = ((Select) annotation).databaseId();
                 sqlCommandType = SqlCommandType.SELECT;
+                dirtySelect = ((Select) annotation).affectData();
             } else if (annotation instanceof Update) {
                 databaseId = ((Update) annotation).databaseId();
                 sqlCommandType = SqlCommandType.UPDATE;
@@ -687,6 +663,7 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
             } else if (annotation instanceof SelectProvider) {
                 databaseId = ((SelectProvider) annotation).databaseId();
                 sqlCommandType = SqlCommandType.SELECT;
+                dirtySelect = ((SelectProvider) annotation).affectData();
             } else if (annotation instanceof UpdateProvider) {
                 databaseId = ((UpdateProvider) annotation).databaseId();
                 sqlCommandType = SqlCommandType.UPDATE;
@@ -707,5 +684,21 @@ public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
                 }
             }
         }
+
+        Annotation getAnnotation() {
+            return annotation;
+        }
+
+        SqlCommandType getSqlCommandType() {
+            return sqlCommandType;
+        }
+
+        String getDatabaseId() {
+            return databaseId;
+        }
+
+        boolean isDirtySelect() {
+            return dirtySelect;
+        }
     }
 }

+ 1 - 1
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperBuilderAssistant.java

@@ -54,7 +54,7 @@ public class MybatisMapperBuilderAssistant extends MapperBuilderAssistant {
                                             boolean lazy) {
         Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
         TypeHandler<?> typeHandlerInstance = null;
-        if (typeHandler != null && typeHandler != UnknownTypeHandler.class) {
+        if (typeHandler != null) {
             if (IJsonTypeHandler.class.isAssignableFrom(typeHandler)) {
                 try {
                     Field field = resultType.getDeclaredField(property);

+ 1 - 1
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperRegistry.java

@@ -65,7 +65,7 @@ public class MybatisMapperRegistry extends MapperRegistry {
         return knownMappers.containsKey(type);
     }
 
-    /**
+    /** 
      * 清空 Mapper 缓存信息
      */
     protected <T> void removeMapper(Class<T> type) {

+ 167 - 132
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLConfigBuilder.java

@@ -18,6 +18,7 @@ package com.baomidou.mybatisplus.core;
 import org.apache.ibatis.builder.BaseBuilder;
 import org.apache.ibatis.builder.BuilderException;
 import org.apache.ibatis.builder.xml.XMLConfigBuilder;
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
 import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
 import org.apache.ibatis.datasource.DataSourceFactory;
 import org.apache.ibatis.executor.ErrorContext;
@@ -57,6 +58,7 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
     private String environment;
     private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
 
+
     public MybatisXMLConfigBuilder(Reader reader) {
         this(reader, null, null);
     }
@@ -66,7 +68,12 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
     }
 
     public MybatisXMLConfigBuilder(Reader reader, String environment, Properties props) {
-        this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
+        this(MybatisConfiguration.class, reader, environment, props);
+    }
+
+    public MybatisXMLConfigBuilder(Class<? extends Configuration> configClass, Reader reader, String environment,
+                            Properties props) {
+        this(configClass, new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
     }
 
     public MybatisXMLConfigBuilder(InputStream inputStream) {
@@ -78,11 +85,17 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
     }
 
     public MybatisXMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
-        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
+        this(MybatisConfiguration.class, inputStream, environment, props);
     }
 
-    private MybatisXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
-        super(new MybatisConfiguration());
+    public MybatisXMLConfigBuilder(Class<? extends Configuration> configClass, InputStream inputStream, String environment,
+                            Properties props) {
+        this(configClass, new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
+    }
+
+    private MybatisXMLConfigBuilder(Class<? extends Configuration> configClass, XPathParser parser, String environment,
+                             Properties props) {
+        super(newConfig(configClass));
         ErrorContext.instance().resource("SQL Mapper Configuration");
         this.configuration.setVariables(props);
         this.parsed = false;
@@ -104,10 +117,10 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
             // issue #117 read properties first
             propertiesElement(root.evalNode("properties"));
             Properties settings = settingsAsProperties(root.evalNode("settings"));
-            loadCustomVfs(settings);
+            loadCustomVfsImpl(settings);
             loadCustomLogImpl(settings);
             typeAliasesElement(root.evalNode("typeAliases"));
-            pluginElement(root.evalNode("plugins"));
+            pluginsElement(root.evalNode("plugins"));
             objectFactoryElement(root.evalNode("objectFactory"));
             objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
             reflectorFactoryElement(root.evalNode("reflectorFactory"));
@@ -115,8 +128,8 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
             // read it after objectFactory and objectWrapperFactory issue #631
             environmentsElement(root.evalNode("environments"));
             databaseIdProviderElement(root.evalNode("databaseIdProvider"));
-            typeHandlerElement(root.evalNode("typeHandlers"));
-            mapperElement(root.evalNode("mappers"));
+            typeHandlersElement(root.evalNode("typeHandlers"));
+            mappersElement(root.evalNode("mappers"));
         } catch (Exception e) {
             throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
         }
@@ -131,22 +144,24 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
         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).");
+                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 {
+    private void loadCustomVfsImpl(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);
-                }
+        if (value == null) {
+            return;
+        }
+        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);
             }
         }
     }
@@ -156,36 +171,38 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
         configuration.setLogImpl(logImpl);
     }
 
-    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 typeAliasesElement(XNode context) {
+        if (context == null) {
+            return;
+        }
+        for (XNode child : context.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()) {
+    private void pluginsElement(XNode context) throws Exception {
+        if (context != null) {
+            for (XNode child : context.getChildren()) {
                 String interceptor = child.getStringAttribute("interceptor");
                 Properties properties = child.getChildrenAsProperties();
-                Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
+                Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor()
+                    .newInstance();
                 interceptorInstance.setProperties(properties);
                 configuration.addInterceptor(interceptorInstance);
             }
@@ -219,25 +236,27 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
     }
 
     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);
+        if (context == null) {
+            return;
+        }
+        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) {
@@ -270,45 +289,47 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
         configuration.setArgNameBasedConstructorAutoMapping(booleanValueOf(props.getProperty("argNameBasedConstructorAutoMapping"), false));
         configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
         configuration.setNullableOnForEach(booleanValueOf(props.getProperty("nullableOnForEach"), false));
+        // TODO 这里改变了原生行为
         configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), true));
         ((MybatisConfiguration) configuration).setUseGeneratedShortKey(booleanValueOf(props.getProperty("useGeneratedShortKey"), true));
     }
 
     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());
-                    break;
-                }
+        if (context == null) {
+            return;
+        }
+        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());
+                break;
             }
         }
     }
 
     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).getDeclaredConstructor().newInstance();
-            databaseIdProvider.setProperties(properties);
+        if (context == null) {
+            return;
+        }
+        String type = context.getStringAttribute("type");
+        // awful patch to keep backward compatibility
+        if ("VENDOR".equals(type)) {
+            type = "DB_VENDOR";
         }
+        Properties properties = context.getChildrenAsProperties();
+        DatabaseIdProvider databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor()
+            .newInstance();
+        databaseIdProvider.setProperties(properties);
         Environment environment = configuration.getEnvironment();
-        if (environment != null && databaseIdProvider != null) {
+        if (environment != null) {
             String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
             configuration.setDatabaseId(databaseId);
         }
@@ -336,61 +357,66 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
         throw new BuilderException("Environment declaration requires a DataSourceFactory.");
     }
 
-    private void typeHandlerElement(XNode parent) {
-        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);
-                        }
+    private void typeHandlersElement(XNode context) {
+        if (context == null) {
+            return;
+        }
+        for (XNode child : context.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(typeHandlerClass);
+                        typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
                     }
+                } else {
+                    typeHandlerRegistry.register(typeHandlerClass);
                 }
             }
         }
     }
 
-    private void mapperElement(XNode parent) throws Exception {
-        if (parent != null) {
-            for (XNode child : parent.getChildren()) {
-                if ("package".equals(child.getName())) {
-                    String mapperPackage = child.getStringAttribute("name");
-                    configuration.addMappers(mapperPackage);
-                } else {
-                    String resource = child.getStringAttribute("resource");
-                    String url = child.getStringAttribute("url");
-                    String mapperClass = child.getStringAttribute("class");
-                    if (resource != null && url == null && mapperClass == null) {
-                        ErrorContext.instance().resource(resource);
-                        try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
-                            MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
-                            mapperParser.parse();
-                        }
-                    } else if (resource == null && url != null && mapperClass == null) {
-                        ErrorContext.instance().resource(url);
-                        try (InputStream inputStream = Resources.getUrlAsStream(url)) {
-                            MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
-                            mapperParser.parse();
-                        }
-                    } else if (resource == null && url == null && mapperClass != null) {
-                        Class<?> mapperInterface = Resources.classForName(mapperClass);
-                        configuration.addMapper(mapperInterface);
-                    } else {
-                        throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
+    private void mappersElement(XNode context) throws Exception {
+        if (context == null) {
+            return;
+        }
+        for (XNode child : context.getChildren()) {
+            if ("package".equals(child.getName())) {
+                String mapperPackage = child.getStringAttribute("name");
+                configuration.addMappers(mapperPackage);
+            } else {
+                String resource = child.getStringAttribute("resource");
+                String url = child.getStringAttribute("url");
+                String mapperClass = child.getStringAttribute("class");
+                if (resource != null && url == null && mapperClass == null) {
+                    ErrorContext.instance().resource(resource);
+                    try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
+                        XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,
+                            configuration.getSqlFragments());
+                        mapperParser.parse();
+                    }
+                } else if (resource == null && url != null && mapperClass == null) {
+                    ErrorContext.instance().resource(url);
+                    try (InputStream inputStream = Resources.getUrlAsStream(url)) {
+                        XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url,
+                            configuration.getSqlFragments());
+                        mapperParser.parse();
                     }
+                } else if (resource == null && url == null && mapperClass != null) {
+                    Class<?> mapperInterface = Resources.classForName(mapperClass);
+                    configuration.addMapper(mapperInterface);
+                } else {
+                    throw new BuilderException(
+                        "A mapper element may only specify a url, resource or class, but not more than one.");
                 }
             }
         }
@@ -405,4 +431,13 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
         }
         return environment.equals(id);
     }
+
+    private static Configuration newConfig(Class<? extends Configuration> configClass) {
+        try {
+            return configClass.getDeclaredConstructor().newInstance();
+        } catch (Exception ex) {
+            throw new BuilderException("Failed to create a new Configuration instance.", ex);
+        }
+    }
+
 }

+ 5 - 51
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLMapperBuilder.java

@@ -19,6 +19,7 @@ import org.apache.ibatis.builder.BaseBuilder;
 import org.apache.ibatis.builder.BuilderException;
 import org.apache.ibatis.builder.CacheRefResolver;
 import org.apache.ibatis.builder.IncompleteElementException;
+import org.apache.ibatis.builder.MapperBuilderAssistant;
 import org.apache.ibatis.builder.ResultMapResolver;
 import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
 import org.apache.ibatis.builder.xml.XMLStatementBuilder;
@@ -42,10 +43,8 @@ import java.io.InputStream;
 import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -59,7 +58,7 @@ import java.util.Properties;
 public class MybatisXMLMapperBuilder extends BaseBuilder {
 
     private final XPathParser parser;
-    private final MybatisMapperBuilderAssistant builderAssistant;
+    private final MapperBuilderAssistant builderAssistant;
     private final Map<String, XNode> sqlFragments;
     private final String resource;
 
@@ -104,9 +103,9 @@ public class MybatisXMLMapperBuilder extends BaseBuilder {
             configuration.addLoadedResource(resource);
             bindMapperForNamespace();
         }
-        parsePendingResultMaps();
-        parsePendingCacheRefs();
-        parsePendingStatements();
+        configuration.parsePendingResultMaps(false);
+        configuration.parsePendingCacheRefs(false);
+        configuration.parsePendingStatements(false);
     }
 
     public XNode getSqlFragment(String refid) {
@@ -150,51 +149,6 @@ public class MybatisXMLMapperBuilder extends BaseBuilder {
         }
     }
 
-    private void parsePendingResultMaps() {
-        Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
-        synchronized (incompleteResultMaps) {
-            Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
-            while (iter.hasNext()) {
-                try {
-                    iter.next().resolve();
-                    iter.remove();
-                } catch (IncompleteElementException e) {
-                    // ResultMap is still missing a resource...
-                }
-            }
-        }
-    }
-
-    private void parsePendingCacheRefs() {
-        Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
-        synchronized (incompleteCacheRefs) {
-            Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
-            while (iter.hasNext()) {
-                try {
-                    iter.next().resolveCacheRef();
-                    iter.remove();
-                } catch (IncompleteElementException e) {
-                    // Cache ref is still missing a resource...
-                }
-            }
-        }
-    }
-
-    private void parsePendingStatements() {
-        Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
-        synchronized (incompleteStatements) {
-            Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
-            while (iter.hasNext()) {
-                try {
-                    iter.next().parseStatementNode();
-                    iter.remove();
-                } catch (IncompleteElementException e) {
-                    // Statement is still missing a resource...
-                }
-            }
-        }
-    }
-
     private void cacheRefElement(XNode context) {
         if (context != null) {
             configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));

+ 5 - 6
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperMethod.java

@@ -197,14 +197,13 @@ public class MybatisMapperMethod {
     private <E> Object convertToArray(List<E> list) {
         Class<?> arrayComponentType = method.getReturnType().getComponentType();
         Object array = Array.newInstance(arrayComponentType, list.size());
-        if (arrayComponentType.isPrimitive()) {
-            for (int i = 0; i < list.size(); i++) {
-                Array.set(array, i, list.get(i));
-            }
-            return array;
-        } else {
+        if (!arrayComponentType.isPrimitive()) {
             return list.toArray((E[]) array);
         }
+        for (int i = 0; i < list.size(); i++) {
+            Array.set(array, i, list.get(i));
+        }
+        return array;
     }
 
     private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {

+ 16 - 19
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java

@@ -15,10 +15,11 @@
  */
 package com.baomidou.mybatisplus.core.override;
 
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import org.apache.ibatis.binding.MapperMethod;
 import org.apache.ibatis.binding.MapperProxy;
 import org.apache.ibatis.reflection.ExceptionUtil;
 import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.util.MapUtil;
 
 import java.io.Serializable;
 import java.lang.invoke.MethodHandle;
@@ -39,7 +40,7 @@ import java.util.Map;
  */
 public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
 
-    private static final long serialVersionUID = -5154982058833204559L;
+    private static final long serialVersionUID = -4724728412955527868L;
     private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
         | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
     private static final Constructor<MethodHandles.Lookup> lookupConstructor;
@@ -73,7 +74,7 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
                 throw new IllegalStateException(
                     "There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
                     e);
-            } catch (Throwable t) {
+            } catch (Exception e) {
                 lookup = null;
             }
         }
@@ -85,9 +86,8 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
         try {
             if (Object.class.equals(method.getDeclaringClass())) {
                 return method.invoke(this, args);
-            } else {
-                return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
             }
+            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
         } catch (Throwable t) {
             throw ExceptionUtil.unwrapThrowable(t);
         }
@@ -95,21 +95,19 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
 
     private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
         try {
-            return CollectionUtils.computeIfAbsent(methodCache, method, m -> {
-                if (m.isDefault()) {
-                    try {
-                        if (privateLookupInMethod == null) {
-                            return new DefaultMethodInvoker(getMethodHandleJava8(method));
-                        } else {
-                            return new DefaultMethodInvoker(getMethodHandleJava9(method));
-                        }
-                    } catch (IllegalAccessException | InstantiationException | InvocationTargetException
-                        | NoSuchMethodException e) {
-                        throw new RuntimeException(e);
-                    }
-                } else {
+            return MapUtil.computeIfAbsent(methodCache, method, m -> {
+                if (!m.isDefault()) {
                     return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
                 }
+                try {
+                    if (privateLookupInMethod == null) {
+                        return new DefaultMethodInvoker(getMethodHandleJava8(method));
+                    }
+                    return new DefaultMethodInvoker(getMethodHandleJava9(method));
+                } catch (IllegalAccessException | InstantiationException | InvocationTargetException
+                         | NoSuchMethodException e) {
+                    throw new RuntimeException(e);
+                }
             });
         } catch (RuntimeException re) {
             Throwable cause = re.getCause();
@@ -143,7 +141,6 @@ public class MybatisMapperProxy<T> implements InvocationHandler, Serializable {
         private final MybatisMapperMethod mapperMethod;
 
         public PlainMethodInvoker(MybatisMapperMethod mapperMethod) {
-            super();
             this.mapperMethod = mapperMethod;
         }