瀏覽代碼

feat(refactor): 不改了,小命要紧

hcl 5 年之前
父節點
當前提交
4678ff4f9b

+ 16 - 7
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/ClassUtils.java

@@ -37,19 +37,27 @@ public final class ClassUtils {
      * 代理 class 的名称
      */
     private static final List<String> PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory"
-        // cglib
-        , "org.springframework.cglib.proxy.Factory"
-        , "javassist.util.proxy.ProxyObject"
-        // javassist
-        , "org.apache.ibatis.javassist.util.proxy.ProxyObject");
+            // cglib
+            , "org.springframework.cglib.proxy.Factory"
+            , "javassist.util.proxy.ProxyObject"
+            // javassist
+            , "org.apache.ibatis.javassist.util.proxy.ProxyObject");
 
     private ClassUtils() {
     }
 
     /**
-     * <p>
+     * 判断传入的类型是否是布尔类型
+     *
+     * @param type 类型
+     * @return 如果是原生布尔或者包装类型布尔,均返回 true
+     */
+    public static boolean isBoolean(Class<?> type) {
+        return type == boolean.class || Boolean.class == type;
+    }
+
+    /**
      * 判断是否为代理对象
-     * </p>
      *
      * @param clazz 传入 class 对象
      * @return 如果对象class是代理 class,返回 true
@@ -155,4 +163,5 @@ public final class ClassUtils {
         int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
         return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
     }
+
 }

+ 0 - 553
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/IOUtils.java

@@ -1,553 +0,0 @@
-/*
- * Copyright (c) 2011-2020, baomidou (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>
- * https://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.core.toolkit;
-
-import org.apache.ibatis.logging.Log;
-import org.apache.ibatis.logging.LogFactory;
-
-import java.io.*;
-import java.net.HttpURLConnection;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.URLConnection;
-import java.nio.channels.Selector;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.Statement;
-
-/**
- * IOUtils Copy org.apache.commons.io.IOUtils
- *
- * @author Caratacus
- * @since 2016-11-23
- */
-public class IOUtils {
-
-    private static final Log logger = LogFactory.getLog(IOUtils.class);
-
-    private IOUtils() {
-    }
-
-    /**
-     * Closes a URLConnection.
-     *
-     * @param conn the connection to close.
-     * @since 2.4
-     */
-    public static void close(final URLConnection conn) {
-        if (conn instanceof HttpURLConnection) {
-            ((HttpURLConnection) conn).disconnect();
-        }
-    }
-
-    /**
-     * Closes an <code>Reader</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * <p>
-     * Example code:
-     * <p>
-     * <pre>
-     * char[] data = new char[1024];
-     * Reader in = null;
-     * try {
-     * 	in = new FileReader(&quot;foo.txt&quot;);
-     * 	in.read(data);
-     * 	in.close(); // close errors are handled
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(in);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param input the Reader to close, may be null or already closed
-     */
-    public static void closeQuietly(final Reader input) {
-        closeQuietly((Closeable) input);
-    }
-
-    /**
-     * Closes an <code>Writer</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Writer#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Writer out = null;
-     * try {
-     * 	out = new StringWriter();
-     * 	out.write(&quot;Hello World&quot;);
-     * 	out.close(); // close errors are handled
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(out);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param output the Writer to close, may be null or already closed
-     */
-    public static void closeQuietly(final Writer output) {
-        closeQuietly((Closeable) output);
-    }
-
-    /**
-     * Closes an <code>InputStream</code> unconditionally.
-     * <p>
-     * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. This is typically used in
-     * finally blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * byte[] data = new byte[1024];
-     * InputStream in = null;
-     * try {
-     * 	in = new FileInputStream(&quot;foo.txt&quot;);
-     * 	in.read(data);
-     * 	in.close(); // close errors are handled
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(in);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param input the InputStream to close, may be null or already closed
-     */
-    public static void closeQuietly(final InputStream input) {
-        closeQuietly((Closeable) input);
-    }
-
-    /**
-     * Closes an <code>OutputStream</code> unconditionally.
-     * <p>
-     * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. This is typically used in
-     * finally blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * byte[] data = &quot;Hello, World&quot;.getBytes();
-     *
-     * OutputStream out = null;
-     * try {
-     * 	out = new FileOutputStream(&quot;foo.txt&quot;);
-     * 	out.write(data);
-     * 	out.close(); // close errors are handled
-     * } catch (IOException e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(out);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param output the OutputStream to close, may be null or already closed
-     */
-    public static void closeQuietly(final OutputStream output) {
-        closeQuietly((Closeable) output);
-    }
-
-    /**
-     * Closes a <code>Closeable</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Closeable closeable = null;
-     * try {
-     * 	closeable = new FileReader(&quot;foo.txt&quot;);
-     * 	// process closeable
-     * 	closeable.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(closeable);
-     * }
-     * </pre>
-     * </p>
-     * <p>
-     * Closing all streams:
-     * </p>
-     * <p>
-     * <pre>
-     * try {
-     * 	return IOUtils.copy(inputStream, outputStream);
-     * } finally {
-     * 	IOUtils.closeQuietly(inputStream);
-     * 	IOUtils.closeQuietly(outputStream);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param closeable the objects to close, may be null or already closed
-     * @since 2.0
-     */
-    public static void closeQuietly(final Closeable closeable) {
-        try {
-            if (closeable != null) {
-                closeable.close();
-            }
-        } catch (final IOException ioe) {
-            logger.error("error close io", ioe);
-        }
-    }
-
-    /**
-     * Closes a <code>Closeable</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored.
-     * </p>
-     * <p>
-     * This is typically used in finally blocks to ensure that the closeable is closed even if an Exception was thrown
-     * before the normal close statement was reached. <br>
-     * <b>It should not be used to replace the close statement(s) which should be present for the non-exceptional
-     * case.</b> <br>
-     * It is only intended to simplify tidying up where normal processing has already failed and reporting close failure
-     * as well is not necessary or useful.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Closeable closeable = null;
-     * try {
-     *     closeable = new FileReader(&quot;foo.txt&quot;);
-     *     // processing using the closeable; may throw an Exception
-     *     closeable.close(); // Normal close - exceptions not ignored
-     * } catch (Exception e) {
-     *     // error handling
-     * } finally {
-     *     <b>IOUtils.closeQuietly(closeable); // In case normal close was skipped due to Exception</b>
-     * }
-     * </pre>
-     * </p>
-     * <p>
-     * Closing all streams: <br>
-     * </p>
-     * <p>
-     * <pre>
-     * try {
-     * 	return IOUtils.copy(inputStream, outputStream);
-     * } finally {
-     * 	IOUtils.closeQuietly(inputStream, outputStream);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param closeables the objects to close, may be null or already closed
-     * @see #closeQuietly(Closeable)
-     * @since 2.5
-     */
-    public static void closeQuietly(final Closeable... closeables) {
-        if (closeables == null) {
-            return;
-        }
-        for (final Closeable closeable : closeables) {
-            closeQuietly(closeable);
-        }
-    }
-
-    /**
-     * Closes a <code>Socket</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Socket#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Socket socket = null;
-     * try {
-     * 	socket = new Socket(&quot;https://www.foo.com/&quot;, 443);
-     * 	// process socket
-     * 	socket.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(socket);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param sock the Socket to close, may be null or already closed
-     * @since 2.0
-     */
-    public static void closeQuietly(final Socket sock) {
-        if (sock != null) {
-            try {
-                sock.close();
-            } catch (final IOException ioe) {
-                logger.error("error close io", ioe);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>Selector</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Selector#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Selector selector = null;
-     * try {
-     * 	selector = Selector.open();
-     * 	// process socket
-     *
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(selector);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param selector the Selector to close, may be null or already closed
-     * @since 2.2
-     */
-    public static void closeQuietly(final Selector selector) {
-        if (selector != null) {
-            try {
-                selector.close();
-            } catch (final IOException ioe) {
-                logger.error("error close io", ioe);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>ServerSocket</code> unconditionally.
-     * <p>
-     * Equivalent to {@link ServerSocket#close()}, except any exceptions will be ignored. This is typically used in
-     * finally blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * ServerSocket socket = null;
-     * try {
-     * 	socket = new ServerSocket();
-     * 	// process socket
-     * 	socket.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(socket);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param sock the ServerSocket to close, may be null or already closed
-     * @since 2.2
-     */
-    public static void closeQuietly(final ServerSocket sock) {
-        if (sock != null) {
-            try {
-                sock.close();
-            } catch (final IOException ioe) {
-                logger.error("error close io", ioe);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>Connection</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Connection#close()}, except any exceptions will be ignored. This is typically used in
-     * finally blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * Connection conn = null;
-     * try {
-     * 	conn = new Connection();
-     * 	// process close
-     * 	conn.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(conn);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param conn the Connection to close, may be null or already closed
-     * @since 2.2
-     */
-    public static void closeQuietly(final Connection conn) {
-        if (conn != null) {
-            try {
-                conn.close();
-            } catch (Exception e) {
-                logger.error("error close conn", e);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>AutoCloseable</code> unconditionally.
-     * <p>
-     * Equivalent to {@link ResultSet#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * AutoCloseable statement = null;
-     * try {
-     * 	statement = new Connection();
-     * 	// process close
-     * 	statement.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(conn);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param resultSet the Connection to close, may be null or already closed
-     * @since 2.2
-     */
-    public static void closeQuietly(final ResultSet resultSet) {
-        if (resultSet != null) {
-            try {
-                resultSet.close();
-            } catch (Exception e) {
-                logger.error("error close resultSet", e);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>AutoCloseable</code> unconditionally.
-     * <p>
-     * Equivalent to {@link Statement#close()}, except any exceptions will be ignored. This is typically used in finally
-     * blocks.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * AutoCloseable statement = null;
-     * try {
-     * 	statement = new Connection();
-     * 	// process close
-     * 	statement.close();
-     * } catch (Exception e) {
-     * 	// error handling
-     * } finally {
-     * 	IOUtils.closeQuietly(conn);
-     * }
-     * </pre>
-     * </p>
-     *
-     * @param statement the Connection to close, may be null or already closed
-     * @since 2.2
-     */
-    public static void closeQuietly(final Statement statement) {
-        if (statement != null) {
-            try {
-                statement.close();
-            } catch (Exception e) {
-                logger.error("error close statement", e);
-            }
-        }
-    }
-
-    /**
-     * Closes a <code>AutoCloseable</code> unconditionally.
-     * <p>
-     * Equivalent to {@link AutoCloseable#close()}, except any exceptions will be ignored.
-     * </p>
-     * <p>
-     * This is typically used in finally blocks to ensure that the closeable is closed even if an Exception was thrown
-     * before the normal close statement was reached. <br>
-     * <b>It should not be used to replace the close statement(s) which should be present for the non-exceptional
-     * case.</b> <br>
-     * It is only intended to simplify tidying up where normal processing has already failed and reporting close failure
-     * as well is not necessary or useful.
-     * </p>
-     * <p>
-     * Example code:
-     * </p>
-     * <p>
-     * <pre>
-     * AutoCloseable closeable = null;
-     * try {
-     *     closeable = new AutoCloseable();
-     *     // processing using the closeable; may throw an Exception
-     *     closeable.close(); // Normal close - exceptions not ignored
-     * } catch (Exception e) {
-     *     // error handling
-     * } finally {
-     *     <b>IOUtils.closeQuietly(closeable); // In case normal close was skipped due to Exception</b>
-     * }
-     * </pre>
-     * </p>
-     * <p>
-     * Closing all streams: <br>
-     * </p>
-     *
-     * @param statements the objects to close, may be null or already closed
-     * @see #closeQuietly(Statement)
-     * @since 2.5
-     */
-    public static void closeQuietly(final Statement... statements) {
-        if (statements == null) {
-            return;
-        }
-        for (final Statement statement : statements) {
-            closeQuietly(statement);
-        }
-    }
-
-}

+ 27 - 47
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/ReflectionKit.java

@@ -28,15 +28,13 @@ import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toMap;
 
 /**
- * <p>
- * 反射工具类
- * </p>
+ * 反射工具类,提供反射相关的快捷操作
  *
  * @author Caratacus
+ * @author hcl
  * @since 2016-09-22
  */
-public class ReflectionKit {
-
+public final class ReflectionKit {
     private static final Log logger = LogFactory.getLog(ReflectionKit.class);
     /**
      * class field cache
@@ -56,35 +54,6 @@ public class ReflectionKit {
         PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
     }
 
-    /**
-     * <p>
-     * 反射 method 方法名,例如 getId
-     * </p>
-     *
-     * @param field
-     * @param str   属性字符串内容
-     */
-    public static String getMethodCapitalize(Field field, final String str) {
-        Class<?> fieldType = field.getType();
-        // fix #176
-        return StringUtils.concatCapitalize(boolean.class.equals(fieldType) ? "is" : "get", str);
-    }
-
-    /**
-     * <p>
-     * 反射 method 方法名,例如 setVersion
-     * </p>
-     *
-     * @param field Field
-     * @param str   String JavaBean类的version属性名
-     * @return version属性的setter方法名称,e.g. setVersion
-     * @deprecated 3.0.8
-     */
-    @Deprecated
-    public static String setMethodCapitalize(Field field, final String str) {
-        return StringUtils.concatCapitalize("set", str);
-    }
-
     /**
      * <p>
      * 获取 public get方法的值
@@ -99,7 +68,7 @@ public class ReflectionKit {
         Map<String, Field> fieldMaps = getFieldMap(cls);
         try {
             Assert.notEmpty(fieldMaps, "Error: NoSuchField in %s for %s.  Cause:", cls.getSimpleName(), str);
-            Method method = cls.getMethod(getMethodCapitalize(fieldMaps.get(str), str));
+            Method method = cls.getMethod(guessGetterName(fieldMaps.get(str), str));
             return method.invoke(entity);
         } catch (NoSuchMethodException e) {
             throw ExceptionUtils.mpe("Error: NoSuchMethod in %s.  Cause:", e, cls.getSimpleName());
@@ -110,6 +79,16 @@ public class ReflectionKit {
         }
     }
 
+    /**
+     * 猜测方法名
+     *
+     * @param field 字段
+     * @param str   属性字符串内容
+     */
+    private static String guessGetterName(Field field, final String str) {
+        return StringUtils.guessGetterName(str, field.getType());
+    }
+
     /**
      * <p>
      * 获取 public get方法的值
@@ -144,12 +123,12 @@ public class ReflectionKit {
         Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
         if (index >= params.length || index < 0) {
             logger.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index,
-                clazz.getSimpleName(), params.length));
+                    clazz.getSimpleName(), params.length));
             return Object.class;
         }
         if (!(params[index] instanceof Class)) {
             logger.warn(String.format("Warn: %s not set the actual class on superclass generic parameter",
-                clazz.getSimpleName()));
+                    clazz.getSimpleName()));
             return Object.class;
         }
         return (Class<?>) params[index];
@@ -199,8 +178,8 @@ public class ReflectionKit {
         if (clazz.getSuperclass() != null) {
             /* 排除重载属性 */
             Map<String, Field> fieldMap = excludeOverrideSuperField(clazz.getDeclaredFields(),
-                /* 处理父类字段 */
-                getFieldList(clazz.getSuperclass()));
+                    /* 处理父类字段 */
+                    getFieldList(clazz.getSuperclass()));
             List<Field> fieldList = new ArrayList<>();
             /*
              * 重写父类属性过滤后处理忽略部分,支持过滤父类属性功能
@@ -210,8 +189,8 @@ public class ReflectionKit {
             fieldMap.forEach((k, v) -> {
                 /* 过滤静态属性 */
                 if (!Modifier.isStatic(v.getModifiers())
-                    /* 过滤 transient关键字修饰的属性 */
-                    && !Modifier.isTransient(v.getModifiers())) {
+                        /* 过滤 transient关键字修饰的属性 */
+                        && !Modifier.isTransient(v.getModifiers())) {
                     fieldList.add(v);
                 }
             });
@@ -232,12 +211,12 @@ public class ReflectionKit {
     public static Map<String, Field> excludeOverrideSuperField(Field[] fields, List<Field> superFieldList) {
         // 子类属性
         Map<String, Field> fieldMap = Stream.of(fields).collect(toMap(Field::getName, identity(),
-            (u, v) -> {
-                throw new IllegalStateException(String.format("Duplicate key %s", u));
-            },
-            LinkedHashMap::new));
+                (u, v) -> {
+                    throw new IllegalStateException(String.format("Duplicate key %s", u));
+                },
+                LinkedHashMap::new));
         superFieldList.stream().filter(field -> !fieldMap.containsKey(field.getName()))
-            .forEach(f -> fieldMap.put(f.getName(), f));
+                .forEach(f -> fieldMap.put(f.getName(), f));
         return fieldMap;
     }
 
@@ -250,7 +229,7 @@ public class ReflectionKit {
      */
     public static Method getMethod(Class<?> cls, Field field) {
         try {
-            return cls.getDeclaredMethod(ReflectionKit.getMethodCapitalize(field, field.getName()));
+            return cls.getDeclaredMethod(ReflectionKit.guessGetterName(field, field.getName()));
         } catch (NoSuchMethodException e) {
             throw ExceptionUtils.mpe("Error: NoSuchMethod in %s.  Cause:", e, cls.getName());
         }
@@ -266,4 +245,5 @@ public class ReflectionKit {
         Assert.notNull(clazz, "Class must not be null");
         return (clazz.isPrimitive() || PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz));
     }
+
 }

+ 48 - 261
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/StringUtils.java

@@ -17,27 +17,22 @@ package com.baomidou.mybatisplus.core.toolkit;
 
 import com.baomidou.mybatisplus.core.toolkit.sql.StringEscape;
 import com.baomidou.mybatisplus.core.toolkit.support.BiIntFunction;
+import jdk.internal.vm.annotation.ForceInline;
 
-import java.nio.charset.StandardCharsets;
-import java.sql.Blob;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import static java.util.stream.Collectors.joining;
 
 /**
- * <p>
  * String 工具类
- * </p>
  *
  * @author D.Yang
+ * @author hcl
  * @since 2016-08-18
  */
-public class StringUtils {
+public final class StringUtils {
 
     /**
      * 空字符
@@ -66,7 +61,6 @@ public class StringUtils {
     private static final Pattern CAPITAL_MODE = Pattern.compile("^[0-9A-Z/_]+$");
 
     private StringUtils() {
-        // to do nothing
     }
 
     /**
@@ -76,54 +70,63 @@ public class StringUtils {
      * @param params format 参数
      * @return format 后的
      */
+    @ForceInline
     public static String format(String target, Object... params) {
-        if (target.contains("%s") && ArrayUtils.isNotEmpty(params)) {
-            return String.format(target, params);
-        }
-        return target;
+        return String.format(target, params);
     }
 
     /**
-     * Blob 转为 String 格式
+     * 判断字符串是否为空
      *
-     * @param blob Blob 对象
-     * @return 转换后的
+     * @param cs 需要判断字符串
+     * @return 判断结果
      */
-    public static String blob2String(Blob blob) {
-        if (null != blob) {
-            try {
-                byte[] returnValue = blob.getBytes(1, (int) blob.length());
-                return new String(returnValue, StandardCharsets.UTF_8);
-            } catch (Exception e) {
-                throw ExceptionUtils.mpe("Blob Convert To String Error!");
-            }
-        }
-        return null;
+    public static boolean isEmpty(CharSequence cs) {
+        return null == cs || 0 == cs.length();
     }
 
     /**
-     * 判断字符串是否为空
+     * 判断字符串是否不为空
      *
      * @param cs 需要判断字符串
      * @return 判断结果
      */
-    public static boolean isEmpty(final CharSequence cs) {
-        if (cs == null) {
-            return true;
+    @ForceInline
+    public static boolean isNotEmpty(final CharSequence cs) {
+        return !isEmpty(cs);
+    }
+
+    /**
+     * 猜测方法属性对应的 Getter 名称,具体规则请参考 JavaBeans 规范
+     *
+     * @param name 属性名称
+     * @param type 属性类型
+     * @return 返回猜测的名称
+     */
+    public static String guessGetterName(String name, Class<?> type) {
+        if (ClassUtils.isBoolean(type)) {
+            return name.startsWith("is") ? name : "is" + upperFirst(name);
         }
-        int l = cs.length();
-        if (l > 0) {
-            for (int i = 0; i < l; i++) {
-                if (!Character.isWhitespace(cs.charAt(i))) {
-                    return false;
-                }
-            }
+        return "get" + upperFirst(name);
+    }
+
+    /**
+     * 大写第一个字母
+     *
+     * @param src 源字符串
+     * @return 返回第一个大写后的字符串
+     */
+    public static String upperFirst(String src) {
+        if (Character.isLowerCase(src.charAt(0))) {
+            return 1 == src.length() ? src.toUpperCase() : Character.toUpperCase(src.charAt(0)) + src.substring(1);
         }
-        return true;
+        return src;
     }
 
+
     /**
      * 判断字符串是不是驼峰命名
+     *
      * <li> 包含 '_' 不算 </li>
      * <li> 首字母大写的不算 </li>
      *
@@ -137,15 +140,6 @@ public class StringUtils {
         return Character.isLowerCase(str.charAt(0));
     }
 
-    /**
-     * 判断字符串是否不为空
-     *
-     * @param cs 需要判断字符串
-     * @return 判断结果
-     */
-    public static boolean isNotEmpty(final CharSequence cs) {
-        return !isEmpty(cs);
-    }
 
     /**
      * 判断字符串是否符合数据库字段的命名
@@ -192,22 +186,6 @@ public class StringUtils {
         return sb.toString();
     }
 
-    /**
-     * 解析 getMethodName -> propertyName
-     *
-     * @param getMethodName 需要解析的
-     * @return 返回解析后的字段名称
-     */
-    public static String resolveFieldName(String getMethodName) {
-        if (getMethodName.startsWith("get")) {
-            getMethodName = getMethodName.substring(3);
-        } else if (getMethodName.startsWith(IS)) {
-            getMethodName = getMethodName.substring(2);
-        }
-        // 小写第一个字母
-        return StringUtils.firstToLowerCase(getMethodName);
-    }
-
     /**
      * 字符串下划线转驼峰格式
      *
@@ -247,16 +225,6 @@ public class StringUtils {
         return param.substring(0, 1).toLowerCase() + param.substring(1);
     }
 
-    /**
-     * 判断字符串是否为纯大写字母
-     *
-     * @param str 要匹配的字符串
-     * @return
-     */
-    public static boolean isUpperCase(String str) {
-        return matches("^[A-Z]+$", str);
-    }
-
     /**
      * 正则表达式匹配
      *
@@ -284,7 +252,8 @@ public class StringUtils {
     public static String sqlArgsFill(String content, Object... args) {
         if (StringUtils.isNotEmpty(content) && ArrayUtils.isNotEmpty(args)) {
             // 索引不能使用,因为 SQL 中的占位符数字与索引不相同
-            return replace(content, MP_SQL_PLACE_HOLDER, (m, i) -> sqlParam(args[Integer.parseInt(m.group("idx"))])).toString();
+            BiIntFunction<Matcher, CharSequence> handler = (m, i) -> sqlParam(args[Integer.parseInt(m.group("idx"))]);
+            return replace(content, MP_SQL_PLACE_HOLDER, handler).toString();
         }
         return content;
     }
@@ -357,7 +326,7 @@ public class StringUtils {
      */
     public static String quotaMarkList(Collection<?> coll) {
         return coll.stream().map(StringUtils::quotaMark)
-            .collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
+                .collect(joining(StringPool.COMMA, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET));
     }
 
     /**
@@ -380,16 +349,6 @@ public class StringUtils {
         return concatStr + Character.toTitleCase(firstChar) + str.substring(1);
     }
 
-    /**
-     * 字符串第一个字母大写
-     *
-     * @param str 被处理的字符串
-     * @return 首字母大写后的字符串
-     */
-    public static String capitalize(final String str) {
-        return concatCapitalize(null, str);
-    }
-
     /**
      * 判断对象是否为空
      *
@@ -476,34 +435,6 @@ public class StringUtils {
         return endsWith(str, suffix, false);
     }
 
-    /**
-     * Case insensitive check if a String ends with a specified suffix.
-     * <p>
-     * <code>null</code>s are handled without exceptions. Two <code>null</code>
-     * references are considered to be equal. The comparison is case
-     * insensitive.
-     * </p>
-     * <p>
-     * <pre>
-     * StringUtils.endsWithIgnoreCase(null, null)      = true
-     * StringUtils.endsWithIgnoreCase(null, "abcdef")  = false
-     * StringUtils.endsWithIgnoreCase("def", null)     = false
-     * StringUtils.endsWithIgnoreCase("def", "abcdef") = true
-     * StringUtils.endsWithIgnoreCase("def", "ABCDEF") = false
-     * </pre>
-     * </p>
-     *
-     * @param str    the String to check, may be null
-     * @param suffix the suffix to find, may be null
-     * @return <code>true</code> if the String ends with the suffix, case
-     * insensitive, or both <code>null</code>
-     * @see String#endsWith(String)
-     * @since 2.4
-     */
-    public static boolean endsWithIgnoreCase(String str, String suffix) {
-        return endsWith(str, suffix, true);
-    }
-
     /**
      * Check if a String ends with a specified suffix (optionally case
      * insensitive).
@@ -527,139 +458,6 @@ public class StringUtils {
         return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
     }
 
-    /**
-     * Splits the provided text into an array, separators specified. This is an
-     * alternative to using StringTokenizer.
-     * <p>
-     * The separator is not included in the returned String array. Adjacent
-     * separators are treated as one separator. For more control over the split
-     * use the StrTokenizer class.
-     * </p>
-     * <p>
-     * A {@code null} input String returns {@code null}. A {@code null}
-     * separatorChars splits on whitespace.
-     * </p>
-     * <p>
-     * <pre>
-     * StringUtils.split(null, *)         = null
-     * StringUtils.split("", *)           = []
-     * StringUtils.split("abc def", null) = ["abc", "def"]
-     * StringUtils.split("abc def", " ")  = ["abc", "def"]
-     * StringUtils.split("abc  def", " ") = ["abc", "def"]
-     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
-     * </pre>
-     * </p>
-     *
-     * @param str            the String to parse, may be null
-     * @param separatorChars the characters used as the delimiters, {@code null} splits on
-     *                       whitespace
-     * @return an array of parsed Strings, {@code null} if null String input
-     */
-    public static String[] split(final String str, final String separatorChars) {
-        List<String> strings = splitWorker(str, separatorChars, -1, false);
-        return strings.toArray(new String[0]);
-    }
-
-    /**
-     * Performs the logic for the {@code split} and
-     * {@code splitPreserveAllTokens} methods that return a maximum array
-     * length.
-     *
-     * @param str               the String to parse, may be {@code null}
-     * @param separatorChars    the separate character
-     * @param max               the maximum number of elements to include in the array. A zero
-     *                          or negative value implies no limit.
-     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty
-     *                          token separators; if {@code false}, adjacent separators are
-     *                          treated as one separator.
-     * @return an array of parsed Strings, {@code null} if null String input
-     */
-    public static List<String> splitWorker(final String str, final String separatorChars, final int max,
-                                           final boolean preserveAllTokens) {
-        // Performance tuned for 2.0 (JDK1.4)
-        // Direct code is quicker than StringTokenizer.
-        // Also, StringTokenizer uses isSpace() not isWhitespace()
-
-        if (str == null) {
-            return null;
-        }
-        final int len = str.length();
-        if (len == 0) {
-            return Collections.emptyList();
-        }
-        final List<String> list = new ArrayList<>();
-        int sizePlus1 = 1;
-        int i = 0, start = 0;
-        boolean match = false;
-        boolean lastMatch = false;
-        if (separatorChars == null) {
-            // Null separator means use whitespace
-            while (i < len) {
-                if (Character.isWhitespace(str.charAt(i))) {
-                    if (match || preserveAllTokens) {
-                        lastMatch = true;
-                        if (sizePlus1++ == max) {
-                            i = len;
-                            lastMatch = false;
-                        }
-                        list.add(str.substring(start, i));
-                        match = false;
-                    }
-                    start = ++i;
-                    continue;
-                }
-                lastMatch = false;
-                match = true;
-                i++;
-            }
-        } else if (separatorChars.length() == 1) {
-            // Optimise 1 character case
-            final char sep = separatorChars.charAt(0);
-            while (i < len) {
-                if (str.charAt(i) == sep) {
-                    if (match || preserveAllTokens) {
-                        lastMatch = true;
-                        if (sizePlus1++ == max) {
-                            i = len;
-                            lastMatch = false;
-                        }
-                        list.add(str.substring(start, i));
-                        match = false;
-                    }
-                    start = ++i;
-                    continue;
-                }
-                lastMatch = false;
-                match = true;
-                i++;
-            }
-        } else {
-            // standard case
-            while (i < len) {
-                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
-                    if (match || preserveAllTokens) {
-                        lastMatch = true;
-                        if (sizePlus1++ == max) {
-                            i = len;
-                            lastMatch = false;
-                        }
-                        list.add(str.substring(start, i));
-                        match = false;
-                    }
-                    start = ++i;
-                    continue;
-                }
-                lastMatch = false;
-                match = true;
-                i++;
-            }
-        }
-        if (match || preserveAllTokens && lastMatch) {
-            list.add(str.substring(start, i));
-        }
-        return list;
-    }
-
     /**
      * 是否为CharSequence类型
      *
@@ -677,7 +475,7 @@ public class StringUtils {
      * @param propertyType 字段类型
      */
     public static String removeIsPrefixIfBoolean(String propertyName, Class<?> propertyType) {
-        if (isBoolean(propertyType) && propertyName.startsWith(IS)) {
+        if (ClassUtils.isBoolean(propertyType) && propertyName.startsWith(IS)) {
             String property = propertyName.replaceFirst(IS, EMPTY);
             if (isEmpty(property)) {
                 return propertyName;
@@ -689,16 +487,6 @@ public class StringUtils {
         return propertyName;
     }
 
-    /**
-     * 是否为Boolean类型(包含普通类型)
-     *
-     * @param propertyCls ignore
-     * @return ignore
-     */
-    public static boolean isBoolean(Class<?> propertyCls) {
-        return propertyCls != null && (boolean.class.isAssignableFrom(propertyCls) || Boolean.class.isAssignableFrom(propertyCls));
-    }
-
     /**
      * 第一个首字母小写,之后字符大小写的不变
      * <p>StringUtils.firstCharToLower( "UserService" )     = userService</p>
@@ -763,8 +551,7 @@ public class StringUtils {
             boolean previousIsWhitespace = Character.isWhitespace(previousChar);
             boolean lastOneIsNotUnderscore = (buf.length() > 0) && (buf.charAt(buf.length() - 1) != '_');
             boolean isNotUnderscore = c != '_';
-            if (lastOneIsNotUnderscore && (isUpperCaseAndPreviousIsLowerCase || previousIsWhitespace
-                || (betweenUpperCases && containsLowerCase && isUpperCaseAndPreviousIsUpperCase))) {
+            if (lastOneIsNotUnderscore && (isUpperCaseAndPreviousIsLowerCase || previousIsWhitespace)) {
                 buf.append(StringPool.UNDERSCORE);
             } else if ((Character.isDigit(previousChar) && Character.isLetter(c))) {
                 buf.append('_');
@@ -800,8 +587,8 @@ public class StringUtils {
         char lastChar = 'a';
         for (char c : s.toCharArray()) {
             if ((Character.isWhitespace(lastChar)) && (!Character.isWhitespace(c))
-                && ('-' != c) && (buf.length() > 0)
-                && (buf.charAt(buf.length() - 1) != '-')) {
+                    && ('-' != c) && (buf.length() > 0)
+                    && (buf.charAt(buf.length() - 1) != '-')) {
                 buf.append(StringPool.DASH);
             }
             if ('_' == c) {

+ 15 - 38
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/LambdaUtilsTest.java

@@ -15,35 +15,26 @@
  */
 package com.baomidou.mybatisplus.core.toolkit;
 
-import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
 import lombok.Getter;
 import org.apache.ibatis.reflection.property.PropertyNamer;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+/**
+ * 测试 Lambda 解析类
+ */
 class LambdaUtilsTest {
 
+    /**
+     * 测试解析
+     */
     @Test
     void testResolve() {
-        SerializedLambda lambda = LambdaUtils.resolve(TestPojo::getId);
-        Assertions.assertEquals(TestPojo.class.getName(), lambda.getImplClassName());
+        SerializedLambda lambda = LambdaUtils.resolve(TestModel::getId);
+        Assertions.assertEquals(TestModel.class.getName(), lambda.getImplClassName());
         Assertions.assertEquals("getId", lambda.getImplMethodName());
         Assertions.assertEquals("id", PropertyNamer.methodToProperty(lambda.getImplMethodName()));
-
-        Cond<TestPojo> cond = new Cond<>();
-        System.out.println(cond.eq(TestPojo::getId, 123).toString());
-
-        // 如果连着写,必须指定后者的泛型
-        new Cond<>().eq(TestPojo::getId, 123)
-            .eq(TestPojo::getId, 123)
-            .eq(TestPojo::getId, 123);
-
-        new Cond<TestPojo>() {{
-            eq(TestPojo::getId, 123);
-            eq(TestPojo::getId, 123);
-            eq(TestPojo::getId, 456);
-        }};
     }
 
     /**
@@ -51,36 +42,22 @@ class LambdaUtilsTest {
      */
     @Test
     void test() {
-        assertInstantiatedMethodTypeIsReference(LambdaUtils.resolve(TestPojo::getId));
+        assertInstantiatedMethodTypeIsReference(LambdaUtils.resolve(TestModel::getId));
         assertInstantiatedMethodTypeIsReference(LambdaUtils.resolve(Integer::byteValue));
     }
 
+    /**
+     * 断言当前方法所在实例的方法类型为引用类型
+     *
+     * @param lambda 解析后的 lambda
+     */
     private void assertInstantiatedMethodTypeIsReference(SerializedLambda lambda) {
         Assertions.assertNotNull(lambda.getInstantiatedMethodType());
     }
 
-
     @Getter
-    private class TestPojo {
-
+    private static class TestModel {
         private int id;
     }
 
-    public class Cond<T> {
-
-        private StringBuilder sb = new StringBuilder();
-
-        // 这个 TYPE 类型和 T 就没有关系了 ;
-        // 如果有需要的话,使用 extends 来建立关系,保证class一致,稍微做点编写检查
-        <TYPE extends T> Cond<T> eq(SFunction<TYPE, ?> prop, Object val) {
-            SerializedLambda lambda = LambdaUtils.resolve(prop);
-            this.sb.append(lambda.getImplMethodName()).append(" = ").append(val);
-            return this;
-        }
-
-        @Override
-        public String toString() {
-            return sb.toString();
-        }
-    }
 }

+ 2 - 15
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/toolkit/ReflectionKitTest.java

@@ -37,7 +37,7 @@ class ReflectionKitTest {
         private transient String test;
 
         @SuppressWarnings("unused")
-		private static String testStatic;
+        private static String testStatic;
 
         private String name;
 
@@ -78,19 +78,6 @@ class ReflectionKitTest {
         Assertions.assertEquals(fieldMap.get("name"), A.class.getDeclaredField("name"));
     }
 
-    @Test
-    void testGetMethodCapitalize() throws NoSuchFieldException {
-        Field field = C.class.getDeclaredField("sex");
-        String getMethod = ReflectionKit.getMethodCapitalize(field, "sex");
-        Assertions.assertEquals("getSex", getMethod);
-        field = A.class.getDeclaredField("testWrap");
-        getMethod = ReflectionKit.getMethodCapitalize(field, "testWrap");
-        Assertions.assertEquals("getTestWrap", getMethod);
-        field = A.class.getDeclaredField("testSimple");
-        getMethod = ReflectionKit.getMethodCapitalize(field, "testSimple");
-        Assertions.assertEquals("isTestSimple", getMethod);
-    }
-
     @Test
     void testGetMethodValue() {
         C c = new C();
@@ -102,7 +89,7 @@ class ReflectionKitTest {
     }
 
     @Test
-    void testIsPrimitiveOrWrapper(){
+    void testIsPrimitiveOrWrapper() {
         Assertions.assertFalse(ReflectionKit.isPrimitiveOrWrapper(String.class));
         Assertions.assertTrue(ReflectionKit.isPrimitiveOrWrapper(Boolean.class));
         Assertions.assertTrue(ReflectionKit.isPrimitiveOrWrapper(boolean.class));