From efedd36696708136e5ee4813c78df17c0e4753bb Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 13 Apr 2020 10:41:59 +0800 Subject: [PATCH] fix bug and add method --- CHANGELOG.md | 4 ++ .../cn/hutool/core/collection/CollUtil.java | 44 +++++++++++++-- .../cn/hutool/core/collection/IterUtil.java | 13 +++++ .../cn/hutool/core/collection/ListUtil.java | 23 +++++--- .../main/java/cn/hutool/core/map/MapUtil.java | 50 ++++++++++++++++- .../main/java/cn/hutool/core/net/NetUtil.java | 3 +- .../hutool/core/collection/CollUtilTest.java | 54 +++++++------------ .../src/test/java/cn/hutool/db/CRUDTest.java | 3 +- .../cn/hutool/extra/servlet/ServletUtil.java | 6 +++ .../java/cn/hutool/json/InternalJSONUtil.java | 19 ++++--- .../main/java/cn/hutool/json/JSONArray.java | 2 +- .../main/java/cn/hutool/json/JSONObject.java | 3 +- .../main/java/cn/hutool/json/JSONTokener.java | 3 +- .../java/cn/hutool/json/JSONArrayTest.java | 11 ++++ .../java/cn/hutool/json/JSONObjectTest.java | 6 +-- 15 files changed, 183 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863b31606..4e0cee698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,11 @@ ## 5.3.1 (2020-04-11) ### 新特性 +* 【core 】 ListUtil、MapUtil、CollUtil增加empty方法 + ### Bug修复 +* 【json 】 修复解析JSON字符串时配置无法传递问题 +* 【core 】 修复ServletUtil.readCookieMap空指针问题(issue#827@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index 744a5df93..b80714da4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -38,8 +38,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.NavigableSet; import java.util.Objects; import java.util.Set; +import java.util.SortedSet; import java.util.Stack; import java.util.TreeMap; import java.util.TreeSet; @@ -2362,15 +2364,14 @@ public class CollUtil { } /** - * 循环遍历Map,使用{@link KVConsumer} 接受遍历的每条数据,并针对每条数据做处理 + * 循环遍历Map,使用{@link KVConsumer} 接受遍历的每条数据,并针对每条数据做处理
+ * 和JDK8中的map.forEach不同的是,此方法支持index * * @param Key类型 * @param Value类型 * @param map {@link Map} * @param kvConsumer {@link KVConsumer} 遍历的每条数据处理器 - * @deprecated JDK8+中使用map.forEach */ - @Deprecated public static void forEach(Map map, KVConsumer kvConsumer) { int index = 0; for (Entry entry : map.entrySet()) { @@ -2561,6 +2562,43 @@ public class CollUtil { return Collections.unmodifiableCollection(c); } + /** + * 根据给定的集合类型,返回对应的空集合,支持类型包括: + * * + *
+	 *     1. NavigableSet
+	 *     2. SortedSet
+	 *     3. Set
+	 *     4. List
+	 * 
+ * + * @param 元素类型 + * @param 集合类型 + * @return 空集合 + * @since 5.3.1 + */ + @SuppressWarnings("unchecked") + public static > T empty(Class collectionClass) { + if (null == collectionClass) { + return (T) Collections.emptyList(); + } + + if (Set.class.isAssignableFrom(collectionClass)) { + if (NavigableSet.class == collectionClass) { + return (T) Collections.emptyNavigableSet(); + } else if (SortedSet.class == collectionClass) { + return (T) Collections.emptySortedSet(); + } else { + return (T) Collections.emptySet(); + } + } else if (List.class.isAssignableFrom(collectionClass)) { + return (T) Collections.emptyList(); + } + + // 不支持空集合的集合类型 + throw new IllegalArgumentException(StrUtil.format("[{}] is not support to get empty!", collectionClass)); + } + // ---------------------------------------------------------------------------------------------- Interface start /** diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java index aa2537d65..23675e37b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java @@ -9,6 +9,7 @@ import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; @@ -676,4 +677,16 @@ public class IterUtil { } return map; } + + /** + * 返回一个空Iterator + * + * @param 元素类型 + * @return 空Iterator + * @see Collections#emptyIterator() + * @since 5.3.1 + */ + public static Iterator empty() { + return Collections.emptyIterator(); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java index 104f7c9eb..babe5f555 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java @@ -425,13 +425,13 @@ public class ListUtil { /** * 获取匹配规则定义中匹配到元素的所有位置 * - * @param 元素类型 - * @param list 列表 + * @param 元素类型 + * @param list 列表 * @param matcher 匹配器,为空则全部匹配 * @return 位置数组 * @since 5.2.5 */ - public static int[] indexOfAll(List list, Matcher matcher){ + public static int[] indexOfAll(List list, Matcher matcher) { final List indexList = new ArrayList<>(); if (null != list) { int index = 0; @@ -448,12 +448,23 @@ public class ListUtil { /** * 将对应List转换为不可修改的List * - * @param list Map - * @param 元素类型 - * @return 不修改Map + * @param list List + * @param 元素类型 + * @return 不可修改List * @since 5.2.6 */ public static List unmodifiable(List list) { return Collections.unmodifiableList(list); } + + /** + * 获取一个空List + * + * @param 元素类型 + * @return 空的List + * @since 5.2.6 + */ + public static List empty() { + return Collections.emptyList(); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java index 256b3d346..c649a1177 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -22,7 +22,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.NavigableMap; import java.util.Set; +import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; @@ -687,8 +689,8 @@ public class MapUtil { * @param 键和值类型 * @param map Map对象,键值类型必须一致 * @return 互换后的Map - * @since 3.2.2 * @see #inverse(Map) + * @since 3.2.2 */ public static Map reverse(Map map) { return filter(map, (Editor>) t -> new Entry() { @@ -1067,4 +1069,50 @@ public class MapUtil { return map; } + + /** + * 返回一个空Map + * + * @param 键类型 + * @param 值类型 + * @return 空Map + * @see Collections#emptyMap() + * @since 5.3.1 + */ + public static Map empty() { + return Collections.emptyMap(); + } + + /** + * 根据传入的Map类型不同,返回对应类型的空Map,支持类型包括: + * + *
+	 *     1. NavigableMap
+	 *     2. SortedMap
+	 *     3. Map
+	 * 
+ * + * @param 键类型 + * @param 值类型 + * @param Map类型 + * @param mapClass Map类型,null返回默认的Map + * @return 空Map + * @since 5.3.1 + */ + @SuppressWarnings("unchecked") + public static > T empty(Class mapClass) { + if (null == mapClass) { + return (T) Collections.emptyMap(); + } + if (NavigableMap.class == mapClass) { + return (T) Collections.emptyNavigableMap(); + } else if (SortedMap.class == mapClass) { + return (T) Collections.emptySortedMap(); + } else if (Map.class == mapClass) { + return (T) Collections.emptyMap(); + } + + // 不支持空集合的集合类型 + throw new IllegalArgumentException(StrUtil.format("[{}] is not support to get empty!", mapClass)); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java index 74a355455..6709c719e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java @@ -28,6 +28,7 @@ import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.List; @@ -715,7 +716,7 @@ public class NetUtil { */ public static List parseCookies(String cookieStr){ if(StrUtil.isBlank(cookieStr)){ - return CollUtil.newArrayList(); + return Collections.emptyList(); } return HttpCookie.parse(cookieStr); } diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java index c6f6190fe..bb23a8678 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/CollUtilTest.java @@ -5,11 +5,14 @@ import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Editor; import cn.hutool.core.lang.Filter; import cn.hutool.core.map.MapUtil; +import lombok.AllArgsConstructor; +import lombok.Data; import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; @@ -20,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.SortedSet; /** * 集合工具类单元测试 @@ -179,7 +183,6 @@ public class CollUtilTest { map.put("c", "3"); final String[] result = new String[1]; - //noinspection deprecation CollUtil.forEach(map, (key, value, index) -> { if (key.equals("a")) { result[0] = value; @@ -304,6 +307,20 @@ public class CollUtilTest { Assert.assertEquals(new Integer(14), map.get("王五")); } + @Test + public void emptyTest() { + final SortedSet emptySortedSet = CollUtil.empty(SortedSet.class); + Assert.assertEquals(Collections.emptySortedSet(), emptySortedSet); + + final Set emptySet = CollUtil.empty(Set.class); + Assert.assertEquals(Collections.emptySet(), emptySet); + + final List emptyList = CollUtil.empty(List.class); + Assert.assertEquals(Collections.emptyList(), emptyList); + } + + @Data + @AllArgsConstructor public static class TestBean { private String name; private int age; @@ -313,41 +330,6 @@ public class CollUtilTest { this.name = name; this.age = age; } - - public TestBean(String name, int age, Date createTime) { - this.name = name; - this.age = age; - this.createTime = createTime; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public Date getCreateTime() { - return createTime; - } - - public void setCreateTime(Date createTime) { - this.createTime = createTime; - } - - @Override - public String toString() { - return "TestBeans [name=" + name + ", age=" + age + "]"; - } } @Test diff --git a/hutool-db/src/test/java/cn/hutool/db/CRUDTest.java b/hutool-db/src/test/java/cn/hutool/db/CRUDTest.java index f86c90a67..671c98069 100644 --- a/hutool-db/src/test/java/cn/hutool/db/CRUDTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/CRUDTest.java @@ -87,7 +87,8 @@ public class CRUDTest { @Test public void findInTest2() throws SQLException { - List results = db.findAll(Entity.create("user").set("id", new Condition("id", new long[]{1, 2, 3}))); + List results = db.findAll(Entity.create("user") + .set("id", new Condition("id", new long[]{1, 2, 3}))); Assert.assertEquals(2, results.size()); } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java index b7bb02aa3..1f2ffd4d1 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java @@ -10,6 +10,7 @@ import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.CaseInsensitiveMap; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.net.NetUtil; import cn.hutool.core.net.multipart.MultipartFormData; import cn.hutool.core.net.multipart.UploadSetting; @@ -418,6 +419,11 @@ public class ServletUtil { * @return Cookie map */ public static Map readCookieMap(HttpServletRequest httpServletRequest) { + final Cookie[] cookies = httpServletRequest.getCookies(); + if(ArrayUtil.isEmpty(cookies)){ + return MapUtil.empty(); + } + return IterUtil.toMap( new ArrayIter<>(httpServletRequest.getCookies()), new CaseInsensitiveMap<>(), diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java index b3be2fee6..0d5501c24 100644 --- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java @@ -206,8 +206,13 @@ final class InternalJSONUtil { } /** - * 默认情况下是否忽略null值的策略选择
- * JavaBean默认忽略null值,其它对象不忽略 + * 默认情况下是否忽略null值的策略选择,以下对象不忽略null值,其它对象忽略: + * + *
+	 *     1. CharSequence
+	 *     2. JSONTokener
+	 *     3. Map
+	 * 
* * @param obj 需要检查的对象 * @return 是否忽略null值 @@ -234,13 +239,13 @@ final class InternalJSONUtil { //默认使用时间戳 long timeMillis; - if(dateObj instanceof TemporalAccessor){ - timeMillis = DateUtil.toInstant((TemporalAccessor)dateObj).toEpochMilli(); - } else if(dateObj instanceof Date){ + if (dateObj instanceof TemporalAccessor) { + timeMillis = DateUtil.toInstant((TemporalAccessor) dateObj).toEpochMilli(); + } else if (dateObj instanceof Date) { timeMillis = ((Date) dateObj).getTime(); - } else if(dateObj instanceof Calendar){ + } else if (dateObj instanceof Calendar) { timeMillis = ((Calendar) dateObj).getTimeInMillis(); - } else{ + } else { throw new UnsupportedOperationException("Unsupported Date type: " + dateObj.getClass()); } return String.valueOf(timeMillis); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java index f19764969..48cae3772 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.ListIterator; import java.util.RandomAccess; -import static cn.hutool.json.JSONConverter.*; +import static cn.hutool.json.JSONConverter.jsonConvert; /** * JSON数组
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index fdfd36098..ea5f6c000 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -124,7 +124,8 @@ public class JSONObject implements JSON, JSONGetter, Map *
  • value为Map,将键值对加入JSON对象
  • *
  • value为JSON字符串(CharSequence),使用JSONTokener解析
  • *
  • value为JSONTokener,直接解析
  • - *
  • value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"
  • + *
  • value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。 + * 例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"
  • * * * @param source JavaBean或者Map对象或者String diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java index 30a940f25..086c941d4 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java @@ -45,7 +45,7 @@ public class JSONTokener { /** * JSON配置 */ - private JSONConfig config; + private final JSONConfig config; // ------------------------------------------------------------------------------------ Constructor start @@ -63,6 +63,7 @@ public class JSONTokener { this.index = 0; this.character = 1; this.line = 1; + this.config = config; } /** diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java index b6d0f0c51..f766bb2e3 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java @@ -45,6 +45,17 @@ public class JSONArrayTest { Assert.assertEquals(array.get(0), "value1"); } + @Test + public void parseWithNullTest() { + String jsonStr = "[{\"grep\":\"4.8\",\"result\":\"右\"},{\"grep\":\"4.8\",\"result\":null}]"; + JSONArray jsonArray = JSONUtil.parseArray(jsonStr); + Assert.assertFalse(jsonArray.getJSONObject(1).containsKey("result")); + + // 不忽略null,则null的键值对被保留 + jsonArray = new JSONArray(jsonStr, false); + Assert.assertTrue(jsonArray.getJSONObject(1).containsKey("result")); + } + @Test public void parseFileTest() { JSONArray array = JSONUtil.readJSONArray(FileUtil.file("exam_test.json"), CharsetUtil.CHARSET_UTF_8); 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 b6cdf73ea..297e67bc0 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java @@ -186,11 +186,11 @@ public class JSONObjectTest { } @Test - public void toBeanTest3() { + public void toBeanWithNullTest() { String jsonStr = "{'data':{'userName':'ak','password': null}}"; + Console.log(JSONUtil.parseObj(jsonStr)); UserWithMap user = JSONUtil.toBean(JSONUtil.parseObj(jsonStr), UserWithMap.class); - // Bean默认忽略null - Assert.assertFalse(user.getData().containsKey("password")); + Assert.assertTrue(user.getData().containsKey("password")); } @Test