add method

This commit is contained in:
Looly 2020-08-06 15:50:23 +08:00
parent 7b4e1c775a
commit 7b0e6dddc0
8 changed files with 123 additions and 50 deletions

View File

@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.4.0 (2020-08-04) # 5.4.0 (2020-08-06)
### 新特性 ### 新特性
* 【socket】 对NioServer和NioClient改造pr#992@Github * 【socket】 对NioServer和NioClient改造pr#992@Github
@ -12,11 +12,13 @@
* 【core 】 将有歧义的BeanUtil.mapToBean方法置为过期使用toBean方法 * 【core 】 将有歧义的BeanUtil.mapToBean方法置为过期使用toBean方法
* 【core 】 添加WatchAction对Watcher的抽象 * 【core 】 添加WatchAction对Watcher的抽象
* 【core 】 修改UUID正则更加严谨issue#I1Q1IW@Gitee * 【core 】 修改UUID正则更加严谨issue#I1Q1IW@Gitee
* 【core 】 ArrayUtil增加isAllNull方法issue#1004@Github
### Bug修复# ### Bug修复#
* 【core 】 修复原始类型转换时,转换失败没有抛出异常的问题 * 【core 】 修复原始类型转换时,转换失败没有抛出异常的问题
* 【core 】 修复BeanUtil.mapToBean中bean的class非空构造无法实例化问题 * 【core 】 修复BeanUtil.mapToBean中bean的class非空构造无法实例化问题
* 【core 】 修复NamedSql多个连续变量出现替换问题 * 【core 】 修复NamedSql多个连续变量出现替换问题
* 【core 】 修复Bean重名字段大小写区别获取数据出错的问题issue#I1QBQ4@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -145,10 +145,13 @@ public class BeanDesc implements Serializable {
* @return this * @return this
*/ */
private BeanDesc init() { private BeanDesc init() {
final Method[] methods = ReflectUtil.getMethods(this.beanClass);
PropDesc prop;
for (Field field : ReflectUtil.getFields(this.beanClass)) { for (Field field : ReflectUtil.getFields(this.beanClass)) {
if (false == ModifierUtil.isStatic(field)) { if (false == ModifierUtil.isStatic(field)) {
//只针对非static属性 //只针对非static属性
this.propMap.put(ReflectUtil.getFieldName(field), createProp(field)); prop = createProp(field, methods);
this.propMap.put(prop.getFieldName(), prop);
} }
} }
return this; return this;
@ -165,21 +168,45 @@ public class BeanDesc implements Serializable {
* 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的 * 4. Setter忽略参数值与字段值不匹配的情况因此有多个参数类型的重载时会调用首次匹配的
* </pre> * </pre>
* *
* @param field 字段 * @param field 字段
* @param methods 类中所有的方法
* @return {@link PropDesc} * @return {@link PropDesc}
* @since 4.0.2 * @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 String fieldName = field.getName();
final Class<?> fieldType = field.getType(); final Class<?> fieldType = field.getType();
final boolean isBooeanField = BooleanUtil.isBoolean(fieldType); final boolean isBooleanField = BooleanUtil.isBoolean(fieldType);
Method getter = null; Method getter = null;
Method setter = null; Method setter = null;
String methodName; String methodName;
Class<?>[] parameterTypes; Class<?>[] parameterTypes;
for (Method method : ReflectUtil.getMethods(this.beanClass)) { for (Method method : methods) {
parameterTypes = method.getParameterTypes(); parameterTypes = method.getParameterTypes();
if (parameterTypes.length > 1) { if (parameterTypes.length > 1) {
// 多于1个参数说明非Getter或Setter // 多于1个参数说明非Getter或Setter
@ -189,11 +216,11 @@ public class BeanDesc implements Serializable {
methodName = method.getName(); methodName = method.getName();
if (parameterTypes.length == 0) { if (parameterTypes.length == 0) {
// 无参数可能为Getter方法 // 无参数可能为Getter方法
if (isMatchGetter(methodName, fieldName, isBooeanField)) { if (isMatchGetter(methodName, fieldName, isBooleanField, ignoreCase)) {
// 方法名与字段名匹配则为Getter方法 // 方法名与字段名匹配则为Getter方法
getter = method; getter = method;
} }
} else if (isMatchSetter(methodName, fieldName, isBooeanField)) { } else if (isMatchSetter(methodName, fieldName, isBooleanField, ignoreCase)) {
// 只有一个参数的情况下方法名与字段名对应匹配则为Setter方法 // 只有一个参数的情况下方法名与字段名对应匹配则为Setter方法
setter = method; setter = method;
} }
@ -202,6 +229,7 @@ public class BeanDesc implements Serializable {
break; break;
} }
} }
return new PropDesc(field, getter, setter); return new PropDesc(field, getter, setter);
} }
@ -218,15 +246,20 @@ public class BeanDesc implements Serializable {
* name - getName * name - getName
* </pre> * </pre>
* *
* @param methodName 方法名 * @param methodName 方法名
* @param fieldName 字段名 * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段 * @param isBooleanField 是否为Boolean类型字段
* @param ignoreCase 匹配是否忽略大小写
* @return 是否匹配 * @return 是否匹配
*/ */
private boolean isMatchGetter(String methodName, String fieldName, boolean isBooeanField) { private boolean isMatchGetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) {
// 全部转为小写忽略大小写比较 // 全部转为小写忽略大小写比较
methodName = methodName.toLowerCase(); if (ignoreCase) {
fieldName = fieldName.toLowerCase(); methodName = methodName.toLowerCase();
fieldName = fieldName.toLowerCase();
} else {
fieldName = StrUtil.upperFirst(fieldName);
}
if (false == methodName.startsWith("get") && false == methodName.startsWith("is")) { if (false == methodName.startsWith("get") && false == methodName.startsWith("is")) {
// 非标准Getter方法 // 非标准Getter方法
@ -238,7 +271,7 @@ public class BeanDesc implements Serializable {
} }
// 针对Boolean类型特殊检查 // 针对Boolean类型特殊检查
if (isBooeanField) { if (isBooleanField) {
if (fieldName.startsWith("is")) { if (fieldName.startsWith("is")) {
// 字段已经是is开头 // 字段已经是is开头
if (methodName.equals(fieldName) // isName - isName if (methodName.equals(fieldName) // isName - isName
@ -268,12 +301,13 @@ public class BeanDesc implements Serializable {
* name - setName * name - setName
* </pre> * </pre>
* *
* @param methodName 方法名 * @param methodName 方法名
* @param fieldName 字段名 * @param fieldName 字段名
* @param isBooeanField 是否为Boolean类型字段 * @param isBooleanField 是否为Boolean类型字段
* @param ignoreCase 匹配是否忽略大小写
* @return 是否匹配 * @return 是否匹配
*/ */
private boolean isMatchSetter(String methodName, String fieldName, boolean isBooeanField) { private boolean isMatchSetter(String methodName, String fieldName, boolean isBooleanField, boolean ignoreCase) {
// 全部转为小写忽略大小写比较 // 全部转为小写忽略大小写比较
methodName = methodName.toLowerCase(); methodName = methodName.toLowerCase();
fieldName = fieldName.toLowerCase(); fieldName = fieldName.toLowerCase();
@ -284,7 +318,7 @@ public class BeanDesc implements Serializable {
} }
// 针对Boolean类型特殊检查 // 针对Boolean类型特殊检查
if (isBooeanField && fieldName.startsWith("is")) { if (isBooleanField && fieldName.startsWith("is")) {
// 字段是is开头 // 字段是is开头
if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is"))// isName - setName if (methodName.equals("set" + StrUtil.removePrefix(fieldName, "is"))// isName - setName
|| methodName.equals("set" + fieldName)// isName - setIsName || methodName.equals("set" + fieldName)// isName - setIsName
@ -312,11 +346,11 @@ public class BeanDesc implements Serializable {
/** /**
* Getter方法 * Getter方法
*/ */
private final Method getter; private Method getter;
/** /**
* Setter方法 * Setter方法
*/ */
private final Method setter; private Method setter;
/** /**
* 构造<br> * 构造<br>
@ -449,11 +483,11 @@ public class BeanDesc implements Serializable {
boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT); boolean isTransient = ModifierUtil.hasModifier(this.field, ModifierUtil.ModifierType.TRANSIENT);
// 检查Getter方法 // 检查Getter方法
if(false == isTransient && null != this.getter){ if (false == isTransient && null != this.getter) {
isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT); isTransient = ModifierUtil.hasModifier(this.getter, ModifierUtil.ModifierType.TRANSIENT);
// 检查注解 // 检查注解
if(false == isTransient){ if (false == isTransient) {
isTransient = null != AnnotationUtil.getAnnotation(this.getter, Transient.class); isTransient = null != AnnotationUtil.getAnnotation(this.getter, Transient.class);
} }
} }

View File

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

View File

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

View File

@ -391,6 +391,14 @@ public class DateUtilTest {
Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString()); 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 @Test
public void parseAndOffsetTest() { public void parseAndOffsetTest() {
// 检查UTC时间偏移是否准确 // 检查UTC时间偏移是否准确

View File

@ -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);
}
}

View File

@ -22,7 +22,7 @@ public class StrUtilTest {
@Test @Test
public void isBlankTest2() { public void isBlankTest2() {
String blank = "\u202a"; String blank = "你看不见\u202a";
Assert.assertTrue(StrUtil.isBlank(blank)); Assert.assertTrue(StrUtil.isBlank(blank));
} }

View File

@ -50,6 +50,7 @@ public class JSONObjectTest {
@Test @Test
public void toStringTest2() { public void toStringTest2() {
String str = "{\"test\":\"关于开展2018年度“文明集体”、“文明职工”评选表彰活动的通知\"}"; String str = "{\"test\":\"关于开展2018年度“文明集体”、“文明职工”评选表彰活动的通知\"}";
//noinspection MismatchedQueryAndUpdateOfCollection
JSONObject json = new JSONObject(str); JSONObject json = new JSONObject(str);
Assert.assertEquals(str, json.toString()); Assert.assertEquals(str, json.toString());
} }
@ -112,6 +113,7 @@ public class JSONObjectTest {
@Test @Test
public void parseStringTest2() { 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\"}"; 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); JSONObject json = new JSONObject(jsonStr);
Assert.assertEquals("F140", json.getStr("error_code")); Assert.assertEquals("F140", json.getStr("error_code"));
Assert.assertEquals("最早发送时间格式错误该字段可以为空当不为空时正确填写格式为“YYYYMMDDHHMISS”", json.getStr("error_info")); Assert.assertEquals("最早发送时间格式错误该字段可以为空当不为空时正确填写格式为“YYYYMMDDHHMISS”", json.getStr("error_info"));
@ -120,6 +122,7 @@ public class JSONObjectTest {
@Test @Test
public void parseStringTest3() { public void parseStringTest3() {
String jsonStr = "{\"test\":\"体”、“文\"}"; String jsonStr = "{\"test\":\"体”、“文\"}";
//noinspection MismatchedQueryAndUpdateOfCollection
JSONObject json = new JSONObject(jsonStr); JSONObject json = new JSONObject(jsonStr);
Assert.assertEquals("体”、“文", json.getStr("test")); Assert.assertEquals("体”、“文", json.getStr("test"));
} }
@ -127,6 +130,7 @@ public class JSONObjectTest {
@Test @Test
public void parseStringTest4() { public void parseStringTest4() {
String jsonStr = "{'msg':'这里还没有内容','data':{'cards':[]},'ok':0}"; String jsonStr = "{'msg':'这里还没有内容','data':{'cards':[]},'ok':0}";
//noinspection MismatchedQueryAndUpdateOfCollection
JSONObject json = new JSONObject(jsonStr); JSONObject json = new JSONObject(jsonStr);
Assert.assertEquals(new Integer(0), json.getInt("ok")); Assert.assertEquals(new Integer(0), json.getInt("ok"));
Assert.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); Assert.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards"));
@ -146,6 +150,7 @@ public class JSONObjectTest {
public void parseStringWithSlashTest() { public void parseStringWithSlashTest() {
//在5.3.2之前</div>中的/会被转义修复此bug的单元测试 //在5.3.2之前</div>中的/会被转义修复此bug的单元测试
String jsonStr = "{\"a\":\"<div>aaa</div>\"}"; String jsonStr = "{\"a\":\"<div>aaa</div>\"}";
//noinspection MismatchedQueryAndUpdateOfCollection
JSONObject json = new JSONObject(jsonStr); JSONObject json = new JSONObject(jsonStr);
Assert.assertEquals("<div>aaa</div>", json.get("a")); Assert.assertEquals("<div>aaa</div>", json.get("a"));
Assert.assertEquals(jsonStr, json.toString()); Assert.assertEquals(jsonStr, json.toString());
@ -454,4 +459,32 @@ public class JSONObjectTest {
@Alias("age") @Alias("age")
private Integer value2; 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;
}
}
} }