From 18784f37dd221d41a8ff172d66aff91015385acb Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 20 May 2023 00:29:28 +0800 Subject: [PATCH] fix code --- .../dromara/hutool/core/array/ArrayUtil.java | 26 ++- .../dromara/hutool/core/bean/BeanDesc.java | 196 ++++++++++-------- .../hutool/core/text/CharSequenceUtil.java | 26 ++- 3 files changed, 143 insertions(+), 105 deletions(-) diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/array/ArrayUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/array/ArrayUtil.java index dcad79b6a..631ca9b85 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/array/ArrayUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/array/ArrayUtil.java @@ -103,6 +103,7 @@ public class ArrayUtil extends PrimitiveArrayUtil { // ---------------------------------------------------------------------- isBlank + /** *

指定字符串数组中,是否包含空字符串。

*

如果指定的字符串数组的长度为 0,或者其中的任意一个元素是空字符串,则返回 true。

@@ -1186,6 +1187,23 @@ public class ArrayUtil extends PrimitiveArrayUtil { return (E) ArrayWrapper.of(array).get(index); } + /** + * 获取满足条件的第一个元素 + * + * @param array 数组 + * @param predicate 条件 + * @param 元素类型 + * @return 满足条件的第一个元素,未找到返回{@code null} + */ + public static E get(final E[] array, final Predicate predicate) { + for (final E e : array) { + if (predicate.test(e)) { + return e; + } + } + return null; + } + /** * 获取数组中所有指定位置的元素值,组成新数组 * @@ -1249,12 +1267,12 @@ public class ArrayUtil extends PrimitiveArrayUtil { * @param array 数组 * @param beginInclude 开始位置(包括) * @param endExclude 结束位置(不包括) + * @param 数组类型 * @return 新的数组 * @since 4.0.6 - * @param 数组类型 */ public static A sub(final A array, - final int beginInclude, final int endExclude) { + final int beginInclude, final int endExclude) { return ArrayWrapper.of(array).getSub(beginInclude, endExclude); } @@ -1265,12 +1283,12 @@ public class ArrayUtil extends PrimitiveArrayUtil { * @param beginInclude 开始位置(包括) * @param endExclude 结束位置(不包括) * @param step 步进 + * @param 数组类型 * @return 新的数组 * @since 4.0.6 - * @param 数组类型 */ public static A sub(final A array, - final int beginInclude, final int endExclude, final int step) { + final int beginInclude, final int endExclude, final int step) { return ArrayWrapper.of(array).getSub(beginInclude, endExclude, step); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDesc.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDesc.java index d03c27233..3a606bc41 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDesc.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/BeanDesc.java @@ -12,6 +12,7 @@ package org.dromara.hutool.core.bean; +import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.map.CaseInsensitiveMap; import org.dromara.hutool.core.reflect.FieldUtil; @@ -149,7 +150,6 @@ public class BeanDesc implements Serializable { /** * 初始化
* 只有与属性关联的相关Getter和Setter方法才会被读取,无关的getXXX和setXXX都被忽略 - * */ private void init() { final Method[] gettersAndSetters = MethodUtil.getPublicMethods(this.beanClass, MethodUtil::isGetterOrSetterIgnoreCase); @@ -209,22 +209,57 @@ public class BeanDesc implements Serializable { final Class fieldType = field.getType(); final boolean isBooleanField = BooleanUtil.isBoolean(fieldType); + // Getter: name -> getName, Setter: name -> setName + final Method[] getterAndSetter = findGetterAndSetter(fieldName, fieldType, gettersOrSetters, ignoreCase); + + if (isBooleanField) { + if (null == getterAndSetter[0]) { + // isName -> isName or isIsName + // name -> isName + getterAndSetter[0] = findGetterForBoolean(fieldName, gettersOrSetters, ignoreCase); + } + if (null == getterAndSetter[1]) { + // isName -> setName + getterAndSetter[1] = findSetterForBoolean(fieldName, gettersOrSetters, ignoreCase); + } + } + + return new PropDesc(field, getterAndSetter[0], getterAndSetter[1]); + } + + /** + * 查找字段对应的Getter和Setter方法
+ * 此方法不区分是否为boolean字段,查找规则为: + *
    + *
  • Getter要求无参数且返回值是字段类型或字段的父类
  • + *
  • Getter中,如果字段为name,匹配getName
  • + *
  • Setter要求一个参数且参数必须为字段类型或字段的子类
  • + *
  • Setter中,如果字段为name,匹配setName
  • + *
+ * + * @param fieldName 字段名 + * @param fieldType 字段类型 + * @param gettersOrSetters 类中所有的Getter或Setter方法 + * @return PropDesc + */ + private Method[] findGetterAndSetter(final String fieldName, final Class fieldType, + final Method[] gettersOrSetters, final boolean ignoreCase) { Method getter = null; Method setter = null; String methodName; for (final Method method : gettersOrSetters) { methodName = method.getName(); - if (method.getParameterCount() == 0) { + if (0 == method.getParameterCount()) { // 无参数,可能为Getter方法 - if (isMatchGetter(methodName, fieldName, isBooleanField, ignoreCase)) { - // 方法名与字段名匹配,则为Getter方法 + if (StrUtil.equals(methodName, StrUtil.genGetter(fieldName), ignoreCase) && + method.getReturnType().isAssignableFrom(fieldType)) { + // getter的返回类型必须为字段类型或字段的父类 getter = method; } - } else if (isMatchSetter(methodName, fieldName, isBooleanField, ignoreCase)) { - // setter方法的参数类型和字段类型必须一致,或参数类型是字段类型的子类 - if(fieldType.isAssignableFrom(method.getParameterTypes()[0])){ - setter = method; - } + } else if (StrUtil.equals(methodName, StrUtil.genSetter(fieldName), ignoreCase) && + fieldType.isAssignableFrom(method.getParameterTypes()[0])) { + // setter方法的参数必须为字段类型或字段的子类 + setter = method; } if (null != getter && null != setter) { // 如果Getter和Setter方法都找到了,不再继续寻找 @@ -232,104 +267,85 @@ public class BeanDesc implements Serializable { } } - return new PropDesc(field, getter, setter); + return new Method[]{getter, setter}; } /** - * 方法是否为Getter方法
- * 匹配规则如下(忽略大小写): + * 针对Boolean或boolean类型字段,查找其对应的Getter方法,规则为: + *
    + *
  • 方法必须无参数且返回boolean或Boolean
  • + *
  • 如果字段为isName, 匹配isName、isIsName方法,两个方法均存在,则按照提供的方法数组优先匹配。
  • + *
  • 如果字段为name, 匹配isName方法
  • + *
+ *

+ * 需要注意的是,以下两种格式不匹配,由{@link #findGetterAndSetter(String, Class, Method[], boolean)}完成: + *

    + *
  • 如果字段为name, 匹配getName
  • + *
  • 如果字段为isName, 匹配getIsName
  • + *
* - *
-	 * 字段名    -》 方法名
-	 * isName  -》 isName
-	 * isName  -》 isIsName
-	 * isName  -》 getIsName
-	 * name     -》 isName
-	 * name     -》 getName
-	 * 
- * - * @param methodName 方法名 - * @param fieldName 字段名 - * @param isBooleanField 是否为Boolean类型字段 - * @param ignoreCase 匹配是否忽略大小写 - * @return 是否匹配 + * @param fieldName 字段名 + * @param gettersOrSetters 所有方法 + * @param ignoreCase 是否忽略大小写 + * @return 查找到的方法,{@code null}表示未找到 */ - private boolean isMatchGetter(String methodName, String fieldName, final boolean isBooleanField, final boolean ignoreCase) { - final String handledFieldName; - if (ignoreCase) { - // 全部转为小写,忽略大小写比较 - methodName = methodName.toLowerCase(); - handledFieldName = fieldName.toLowerCase(); - fieldName = handledFieldName; - } else { - handledFieldName = StrUtil.upperFirst(fieldName); - } + private Method findGetterForBoolean(final String fieldName, final Method[] gettersOrSetters, final boolean ignoreCase) { + // 查找isXXX + return ArrayUtil.get(gettersOrSetters, m -> { + if (0 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getReturnType())) { + // getter方法要求无参数且返回boolean或Boolean + return false; + } - // 针对Boolean类型特殊检查 - if (isBooleanField) { - if (fieldName.startsWith("is")) { - // 字段已经是is开头 - if (methodName.equals(fieldName) // isName -》 isName - || ("get" + handledFieldName).equals(methodName)// isName -》 getIsName - || ("is" + handledFieldName).equals(methodName)// isName -》 isIsName - ) { + if (StrUtil.startWith(fieldName, "is", ignoreCase)) { + // isName -》 isName + if(StrUtil.equals(fieldName, m.getName(), ignoreCase)){ return true; } - } else if (("is" + handledFieldName).equals(methodName)) { - // 字段非is开头, name -》 isName - return true; } - } - // 包括boolean的任何类型只有一种匹配情况:name -》 getName - return ("get" + handledFieldName).equals(methodName); + // name -》 isName + // isName -》 isIsName + return StrUtil.equals(StrUtil.upperFirstAndAddPre(fieldName, "is"), m.getName(), ignoreCase); + }); } /** - * 方法是否为Setter方法
- * 匹配规则如下(忽略大小写): + * 针对Boolean或boolean类型字段,查找其对应的Setter方法,规则为: + *
    + *
  • 方法必须为1个boolean或Boolean参数
  • + *
  • 如果字段为isName,匹配setName
  • + *
+ *

+ * 需要注意的是,以下两种格式不匹配,由{@link #findGetterAndSetter(String, Class, Method[], boolean)}完成: + *

    + *
  • 如果字段为name, 匹配setName
  • + *
  • 如果字段为isName, 匹配setIsName
  • + *
* - *
-	 * 字段名    -》 方法名
-	 * isName  -》 setName
-	 * isName  -》 setIsName
-	 * name     -》 setName
-	 * 
- * - * @param methodName 方法名 - * @param fieldName 字段名 - * @param isBooleanField 是否为Boolean类型字段 - * @param ignoreCase 匹配是否忽略大小写 - * @return 是否匹配 + * @param fieldName 字段名 + * @param gettersOrSetters 所有方法 + * @param ignoreCase 是否忽略大小写 + * @return 查找到的方法,{@code null}表示未找到 */ - private boolean isMatchSetter(String methodName, String fieldName, final boolean isBooleanField, final boolean ignoreCase) { - final String handledFieldName; - if (ignoreCase) { - // 全部转为小写,忽略大小写比较 - methodName = methodName.toLowerCase(); - handledFieldName = fieldName.toLowerCase(); - fieldName = handledFieldName; - } else { - handledFieldName = StrUtil.upperFirst(fieldName); - } - - // 非标准Setter方法跳过 - if (!methodName.startsWith("set")) { - return false; - } - - // 针对Boolean类型特殊检查 - if (isBooleanField && fieldName.startsWith("is")) { - // 字段是is开头 - if (("set" + StrUtil.removePrefix(fieldName, "is")).equals(methodName)// isName -》 setName - || ("set" + handledFieldName).equals(methodName)// isName -》 setIsName - ) { - return true; + private Method findSetterForBoolean(final String fieldName, final Method[] gettersOrSetters, final boolean ignoreCase) { + // 查找isXXX + return ArrayUtil.get(gettersOrSetters, m -> { + if (1 != m.getParameterCount() || false == BooleanUtil.isBoolean(m.getParameterTypes()[0])) { + // setter方法要求1个boolean或Boolean参数 + return false; } - } - // 包括boolean的任何类型只有一种匹配情况:name -》 setName - return ("set" + handledFieldName).equals(methodName); + if (StrUtil.startWith(fieldName, "is", ignoreCase)) { + // isName -》 setName + return StrUtil.equals( + "set" + StrUtil.removePrefix(fieldName, "is", ignoreCase), + m.getName(), ignoreCase); + } + + // 其它不匹配 + return false; + }); } // ------------------------------------------------------------------------------------------------------ Private method end } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java index 7815bafac..0b129c06d 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java @@ -1113,18 +1113,10 @@ public class CharSequenceUtil extends StrValidator { * * @param str 字符串 * @param prefix 前缀 - * @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串 + * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 */ public static String removePrefix(final CharSequence str, final CharSequence prefix) { - if (isEmpty(str) || isEmpty(prefix)) { - return str(str); - } - - final String str2 = str.toString(); - if (str2.startsWith(prefix.toString())) { - return subSuf(str2, prefix.length());// 截取后半段 - } - return str2; + return removePrefix(str, prefix, false); } /** @@ -1135,12 +1127,24 @@ public class CharSequenceUtil extends StrValidator { * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 */ public static String removePrefixIgnoreCase(final CharSequence str, final CharSequence prefix) { + return removePrefix(str, prefix, true); + } + + /** + * 去掉指定前缀 + * + * @param str 字符串 + * @param prefix 前缀 + * @param ignoreCase 是否忽略大小写 + * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串 + */ + public static String removePrefix(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { if (isEmpty(str) || isEmpty(prefix)) { return str(str); } final String str2 = str.toString(); - if (startWithIgnoreCase(str, prefix)) { + if (startWith(str, prefix, ignoreCase)) { return subSuf(str2, prefix.length());// 截取后半段 } return str2;