Browse Source

add method

Looly 5 years ago
parent
commit
7b0e6dddc0

+ 3 - 1
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)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 58 - 24
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忽略参数值与字段值不匹配的情况,因此有多个参数类型的重载时,会调用首次匹配的
 	 * </pre>
 	 *
-	 * @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
 	 * </pre>
 	 *
-	 * @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
 	 * </pre>
 	 *
-	 * @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;
 
 		/**
 		 * 构造<br>
@@ -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);
 				}
 			}

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java

@@ -52,7 +52,7 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
 	 * @param targetType 目标类型
 	 */
 	public TemporalAccessorConverter(Class<?> targetType) {
-		this.targetType = targetType;
+		this(targetType, null);
 	}
 
 	/**

+ 2 - 23
hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java

@@ -278,33 +278,12 @@ public class ArrayUtil {
 	 * @param <T> 数组元素类型
 	 * @param array 被检查的数组
 	 * @return 多个字段是否全为null
-	 * @since 5.3.11
-	 * @author dahuoyzs
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T> boolean allNull(T... array) {
-		if (isNotEmpty(array)) {
-			for (T element : array) {
-				if (null != element) {
-					return false;
-				}
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * 多个字段是否全为null
-	 *
-	 * @param <T> 数组元素类型
-	 * @param array 被检查的数组
-	 * @return 多个字段是否全为null
-	 * @since 5.3.11
+	 * @since 5.4.0
 	 * @author dahuoyzs
 	 */
 	@SuppressWarnings("unchecked")
 	public static <T> boolean isAllNull(T... array) {
-		return allNull(array);
+		return null == firstNonNull(array);
 	}
 
 	/**

+ 8 - 0
hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java

@@ -392,6 +392,14 @@ public class DateUtilTest {
 	}
 
 	@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时间偏移是否准确
 		String str = "2019-09-17T13:26:17.948Z";

+ 17 - 0
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);
+	}
+}

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

+ 33 - 0
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之前,</div>中的/会被转义,修复此bug的单元测试
 		String jsonStr = "{\"a\":\"<div>aaa</div>\"}";
+		//noinspection MismatchedQueryAndUpdateOfCollection
 		JSONObject json = new JSONObject(jsonStr);
 		Assert.assertEquals("<div>aaa</div>", 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;
+		}
+
+	}
 }