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;
+ }
+
+ }
}