From 7b0e6dddc06e9cffb7d3ab626ee1a9e93e8b136f Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 6 Aug 2020 15:50:23 +0800 Subject: [PATCH] add method --- CHANGELOG.md | 4 +- .../java/cn/hutool/core/bean/BeanDesc.java | 82 +++++++++++++------ .../impl/TemporalAccessorConverter.java | 2 +- .../java/cn/hutool/core/util/ArrayUtil.java | 25 +----- .../cn/hutool/core/date/DateUtilTest.java | 8 ++ .../java/cn/hutool/core/lang/TupleTest.java | 17 ++++ .../java/cn/hutool/core/util/StrUtilTest.java | 2 +- .../java/cn/hutool/json/JSONObjectTest.java | 33 ++++++++ 8 files changed, 123 insertions(+), 50 deletions(-) create mode 100644 hutool-core/src/test/java/cn/hutool/core/lang/TupleTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 74c8165d5..d8b85edf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.4.0 (2020-08-04) +# 5.4.0 (2020-08-06) ### 新特性 * 【socket】 对NioServer和NioClient改造(pr#992@Github) @@ -12,11 +12,13 @@ * 【core 】 将有歧义的BeanUtil.mapToBean方法置为过期(使用toBean方法) * 【core 】 添加WatchAction(对Watcher的抽象) * 【core 】 修改UUID正则,更加严谨(issue#I1Q1IW@Gitee) +* 【core 】 ArrayUtil增加isAllNull方法(issue#1004@Github) ### Bug修复# * 【core 】 修复原始类型转换时,转换失败没有抛出异常的问题 * 【core 】 修复BeanUtil.mapToBean中bean的class非空构造无法实例化问题 * 【core 】 修复NamedSql多个连续变量出现替换问题 +* 【core 】 修复Bean重名字段(大小写区别)获取数据出错的问题(issue#I1QBQ4@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java index c843bec87..493b19309 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanDesc.java @@ -145,10 +145,13 @@ public class BeanDesc implements Serializable { * @return this */ private BeanDesc init() { + final Method[] methods = ReflectUtil.getMethods(this.beanClass); + PropDesc prop; for (Field field : ReflectUtil.getFields(this.beanClass)) { if (false == ModifierUtil.isStatic(field)) { //只针对非static属性 - this.propMap.put(ReflectUtil.getFieldName(field), createProp(field)); + prop = createProp(field, methods); + this.propMap.put(prop.getFieldName(), prop); } } return this; @@ -165,21 +168,45 @@ public class BeanDesc implements Serializable { * 4. Setter忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的 * * - * @param field 字段 + * @param field 字段 + * @param methods 类中所有的方法 * @return {@link PropDesc} * @since 4.0.2 */ - private PropDesc createProp(Field field) { + private PropDesc createProp(Field field, Method[] methods) { + final PropDesc prop = findProp(field, methods, false); + // 忽略大小写重新匹配一次 + if (null == prop.getter || null == prop.setter) { + final PropDesc propIgnoreCase = findProp(field, methods, true); + if (null == prop.getter) { + prop.getter = propIgnoreCase.getter; + } + if (null == prop.setter) { + prop.setter = propIgnoreCase.setter; + } + } + + return prop; + } + + /** + * 查找字段对应的Getter和Setter方法 + * + * @param field 字段 + * @param methods 类中所有的方法 + * @param ignoreCase 是否忽略大小写匹配 + * @return PropDesc + */ + private PropDesc findProp(Field field, Method[] methods, boolean ignoreCase) { final String fieldName = field.getName(); final Class fieldType = field.getType(); - final boolean isBooeanField = BooleanUtil.isBoolean(fieldType); + final boolean isBooleanField = BooleanUtil.isBoolean(fieldType); Method getter = null; Method setter = null; - String methodName; Class[] parameterTypes; - for (Method method : ReflectUtil.getMethods(this.beanClass)) { + for (Method method : methods) { parameterTypes = method.getParameterTypes(); if (parameterTypes.length > 1) { // 多于1个参数说明非Getter或Setter @@ -189,11 +216,11 @@ public class BeanDesc implements Serializable { methodName = method.getName(); if (parameterTypes.length == 0) { // 无参数,可能为Getter方法 - if (isMatchGetter(methodName, fieldName, isBooeanField)) { + if (isMatchGetter(methodName, fieldName, isBooleanField, ignoreCase)) { // 方法名与字段名匹配,则为Getter方法 getter = method; } - } else if (isMatchSetter(methodName, fieldName, isBooeanField)) { + } else if (isMatchSetter(methodName, fieldName, isBooleanField, ignoreCase)) { // 只有一个参数的情况下方法名与字段名对应匹配,则为Setter方法 setter = method; } @@ -202,6 +229,7 @@ public class BeanDesc implements Serializable { break; } } + return new PropDesc(field, getter, setter); } @@ -218,15 +246,20 @@ public class BeanDesc implements Serializable { * name -》 getName * * - * @param methodName 方法名 - * @param fieldName 字段名 - * @param isBooeanField 是否为Boolean类型字段 + * @param methodName 方法名 + * @param fieldName 字段名 + * @param isBooleanField 是否为Boolean类型字段 + * @param ignoreCase 匹配是否忽略大小写 * @return 是否匹配 */ - private boolean isMatchGetter(String methodName, String fieldName, boolean isBooeanField) { + private boolean isMatchGetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) { // 全部转为小写,忽略大小写比较 - methodName = methodName.toLowerCase(); - fieldName = fieldName.toLowerCase(); + if (ignoreCase) { + methodName = methodName.toLowerCase(); + fieldName = fieldName.toLowerCase(); + } else { + fieldName = StrUtil.upperFirst(fieldName); + } if (false == methodName.startsWith("get") && false == methodName.startsWith("is")) { // 非标准Getter方法 @@ -238,7 +271,7 @@ public class BeanDesc implements Serializable { } // 针对Boolean类型特殊检查 - if (isBooeanField) { + if (isBooleanField) { if (fieldName.startsWith("is")) { // 字段已经是is开头 if (methodName.equals(fieldName) // isName -》 isName @@ -268,12 +301,13 @@ public class BeanDesc implements Serializable { * name -》 setName * * - * @param methodName 方法名 - * @param fieldName 字段名 - * @param isBooeanField 是否为Boolean类型字段 + * @param methodName 方法名 + * @param fieldName 字段名 + * @param isBooleanField 是否为Boolean类型字段 + * @param ignoreCase 匹配是否忽略大小写 * @return 是否匹配 */ - private boolean isMatchSetter(String methodName, String fieldName, boolean isBooeanField) { + private boolean isMatchSetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) { // 全部转为小写,忽略大小写比较 methodName = methodName.toLowerCase(); fieldName = fieldName.toLowerCase(); @@ -284,7 +318,7 @@ public class BeanDesc implements Serializable { } // 针对Boolean类型特殊检查 - if (isBooeanField && fieldName.startsWith("is")) { + if (isBooleanField && fieldName.startsWith("is")) { // 字段是is开头 if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is"))// isName -》 setName || methodName.equals("set" + fieldName)// isName -》 setIsName @@ -312,11 +346,11 @@ public class BeanDesc implements Serializable { /** * Getter方法 */ - private final Method getter; + private Method getter; /** * Setter方法 */ - private final Method setter; + private Method setter; /** * 构造
@@ -449,11 +483,11 @@ public class BeanDesc implements Serializable { boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT); // 检查Getter方法 - if(false == isTransient && null != this.getter){ + if (false == isTransient && null != this.getter) { isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT); // 检查注解 - if(false == isTransient){ + if (false == isTransient) { isTransient = null != AnnotationUtil.getAnnotation(this.getter, Transient.class); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java index 02bfe6a22..9f2ef2189 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java @@ -52,7 +52,7 @@ public class TemporalAccessorConverter extends AbstractConverter targetType) { - this.targetType = targetType; + this(targetType, null); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index 32d98ada9..06046dbf5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -278,33 +278,12 @@ public class ArrayUtil { * @param 数组元素类型 * @param array 被检查的数组 * @return 多个字段是否全为null - * @since 5.3.11 - * @author dahuoyzs - */ - @SuppressWarnings("unchecked") - public static boolean allNull(T... array) { - if (isNotEmpty(array)) { - for (T element : array) { - if (null != element) { - return false; - } - } - } - return true; - } - - /** - * 多个字段是否全为null - * - * @param 数组元素类型 - * @param array 被检查的数组 - * @return 多个字段是否全为null - * @since 5.3.11 + * @since 5.4.0 * @author dahuoyzs */ @SuppressWarnings("unchecked") public static boolean isAllNull(T... array) { - return allNull(array); + return null == firstNonNull(array); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index b2d3b9d81..8d8d00213 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -391,6 +391,14 @@ public class DateUtilTest { Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString()); } + @Test + public void parseTest8() { + String str = "2020-06-28T02:14:13.000Z"; + DateTime dateTime = DateUtil.parse(str); + assert dateTime != null; + Assert.assertEquals("2020-06-28 02:14:13", dateTime.toString()); + } + @Test public void parseAndOffsetTest() { // 检查UTC时间偏移是否准确 diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/TupleTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/TupleTest.java new file mode 100644 index 000000000..68e9d5298 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/lang/TupleTest.java @@ -0,0 +1,17 @@ +package cn.hutool.core.lang; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Locale; +import java.util.TimeZone; + +public class TupleTest { + + @Test + public void hashCodeTest(){ + final Tuple tuple = new Tuple(Locale.getDefault(), TimeZone.getDefault()); + final Tuple tuple2 = new Tuple(Locale.getDefault(), TimeZone.getDefault()); + Assert.assertEquals(tuple, tuple2); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index eac87d08c..178d28bf9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java @@ -22,7 +22,7 @@ public class StrUtilTest { @Test public void isBlankTest2() { - String blank = "\u202a"; + String blank = "你看不见\u202a"; Assert.assertTrue(StrUtil.isBlank(blank)); } diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java index d9e7ee901..3224ccf21 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -50,6 +50,7 @@ public class JSONObjectTest { @Test public void toStringTest2() { String str = "{\"test\":\"关于开展2018年度“文明集体”、“文明职工”评选表彰活动的通知\"}"; + //noinspection MismatchedQueryAndUpdateOfCollection JSONObject json = new JSONObject(str); Assert.assertEquals(str, json.toString()); } @@ -112,6 +113,7 @@ public class JSONObjectTest { @Test public void parseStringTest2() { String jsonStr = "{\"file_name\":\"RMM20180127009_731.000\",\"error_data\":\"201121151350701001252500000032 18973908335 18973908335 13601893517 201711211700152017112115135420171121 6594000000010100000000000000000000000043190101701001910072 100001100 \",\"error_code\":\"F140\",\"error_info\":\"最早发送时间格式错误,该字段可以为空,当不为空时正确填写格式为“YYYYMMDDHHMISS”\",\"app_name\":\"inter-pre-check\"}"; + //noinspection MismatchedQueryAndUpdateOfCollection JSONObject json = new JSONObject(jsonStr); Assert.assertEquals("F140", json.getStr("error_code")); Assert.assertEquals("最早发送时间格式错误,该字段可以为空,当不为空时正确填写格式为“YYYYMMDDHHMISS”", json.getStr("error_info")); @@ -120,6 +122,7 @@ public class JSONObjectTest { @Test public void parseStringTest3() { String jsonStr = "{\"test\":\"体”、“文\"}"; + //noinspection MismatchedQueryAndUpdateOfCollection JSONObject json = new JSONObject(jsonStr); Assert.assertEquals("体”、“文", json.getStr("test")); } @@ -127,6 +130,7 @@ public class JSONObjectTest { @Test public void parseStringTest4() { String jsonStr = "{'msg':'这里还没有内容','data':{'cards':[]},'ok':0}"; + //noinspection MismatchedQueryAndUpdateOfCollection JSONObject json = new JSONObject(jsonStr); Assert.assertEquals(new Integer(0), json.getInt("ok")); Assert.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); @@ -146,6 +150,7 @@ public class JSONObjectTest { public void parseStringWithSlashTest() { //在5.3.2之前,中的/会被转义,修复此bug的单元测试 String jsonStr = "{\"a\":\"
aaa
\"}"; + //noinspection MismatchedQueryAndUpdateOfCollection JSONObject json = new JSONObject(jsonStr); Assert.assertEquals("
aaa
", json.get("a")); Assert.assertEquals(jsonStr, json.toString()); @@ -454,4 +459,32 @@ public class JSONObjectTest { @Alias("age") private Integer value2; } + + @Test + public void parseBeanSameNameTest(){ + final SameNameBean sameNameBean = new SameNameBean(); + final JSONObject parse = JSONUtil.parseObj(sameNameBean); + Assert.assertEquals("123", parse.getStr("username")); + Assert.assertEquals("abc", parse.getStr("userName")); + } + + /** + * 测试子Bean + * + * @author Looly + */ + @SuppressWarnings("FieldCanBeLocal") + public static class SameNameBean { + private final String username = "123"; + private final String userName = "abc"; + + public String getUsername() { + return username; + } + + public String getUserName() { + return userName; + } + + } }