fix bug and add method

This commit is contained in:
Looly 2020-04-13 10:41:59 +08:00
parent d15ec3c647
commit efedd36696
15 changed files with 183 additions and 61 deletions

View File

@ -6,7 +6,11 @@
## 5.3.1 (2020-04-11)
### 新特性
* 【core 】 ListUtil、MapUtil、CollUtil增加empty方法
### Bug修复
* 【json 】 修复解析JSON字符串时配置无法传递问题
* 【core 】 修复ServletUtil.readCookieMap空指针问题issue#827@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -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} 接受遍历的每条数据并针对每条数据做处理<br>
* 和JDK8中的map.forEach不同的是此方法支持index
*
* @param <K> Key类型
* @param <V> Value类型
* @param map {@link Map}
* @param kvConsumer {@link KVConsumer} 遍历的每条数据处理器
* @deprecated JDK8+中使用map.forEach
*/
@Deprecated
public static <K, V> void forEach(Map<K, V> map, KVConsumer<K, V> kvConsumer) {
int index = 0;
for (Entry<K, V> entry : map.entrySet()) {
@ -2561,6 +2562,43 @@ public class CollUtil {
return Collections.unmodifiableCollection(c);
}
/**
* 根据给定的集合类型返回对应的空集合支持类型包括
* *
* <pre>
* 1. NavigableSet
* 2. SortedSet
* 3. Set
* 4. List
* </pre>
*
* @param <E> 元素类型
* @param <T> 集合类型
* @return 空集合
* @since 5.3.1
*/
@SuppressWarnings("unchecked")
public static <E, T extends Collection<E>> 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
/**

View File

@ -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 <T> 元素类型
* @return 空Iterator
* @see Collections#emptyIterator()
* @since 5.3.1
*/
public static <T> Iterator<T> empty() {
return Collections.emptyIterator();
}
}

View File

@ -425,13 +425,13 @@ public class ListUtil {
/**
* 获取匹配规则定义中匹配到元素的所有位置
*
* @param <T> 元素类型
* @param list 列表
* @param <T> 元素类型
* @param list 列表
* @param matcher 匹配器为空则全部匹配
* @return 位置数组
* @since 5.2.5
*/
public static <T> int[] indexOfAll(List<T> list, Matcher<T> matcher){
public static <T> int[] indexOfAll(List<T> list, Matcher<T> matcher) {
final List<Integer> indexList = new ArrayList<>();
if (null != list) {
int index = 0;
@ -448,12 +448,23 @@ public class ListUtil {
/**
* 将对应List转换为不可修改的List
*
* @param list Map
* @param <T> 元素类型
* @return 修改Map
* @param list List
* @param <T> 元素类型
* @return 可修改List
* @since 5.2.6
*/
public static <T> List<T> unmodifiable(List<T> list) {
return Collections.unmodifiableList(list);
}
/**
* 获取一个空List
*
* @param <T> 元素类型
* @return 空的List
* @since 5.2.6
*/
public static <T> List<T> empty() {
return Collections.emptyList();
}
}

View File

@ -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 <T> 键和值类型
* @param map Map对象键值类型必须一致
* @return 互换后的Map
* @since 3.2.2
* @see #inverse(Map)
* @since 3.2.2
*/
public static <T> Map<T, T> reverse(Map<T, T> map) {
return filter(map, (Editor<Entry<T, T>>) t -> new Entry<T, T>() {
@ -1067,4 +1069,50 @@ public class MapUtil {
return map;
}
/**
* 返回一个空Map
*
* @param <K> 键类型
* @param <V> 值类型
* @return 空Map
* @see Collections#emptyMap()
* @since 5.3.1
*/
public static <K, V> Map<K, V> empty() {
return Collections.emptyMap();
}
/**
* 根据传入的Map类型不同返回对应类型的空Map支持类型包括
*
* <pre>
* 1. NavigableMap
* 2. SortedMap
* 3. Map
* </pre>
*
* @param <K> 键类型
* @param <V> 值类型
* @param <T> Map类型
* @param mapClass Map类型null返回默认的Map
* @return 空Map
* @since 5.3.1
*/
@SuppressWarnings("unchecked")
public static <K, V, T extends Map<K, V>> 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));
}
}

View File

@ -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<HttpCookie> parseCookies(String cookieStr){
if(StrUtil.isBlank(cookieStr)){
return CollUtil.newArrayList();
return Collections.emptyList();
}
return HttpCookie.parse(cookieStr);
}

View File

@ -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<String> emptySortedSet = CollUtil.empty(SortedSet.class);
Assert.assertEquals(Collections.emptySortedSet(), emptySortedSet);
final Set<String> emptySet = CollUtil.empty(Set.class);
Assert.assertEquals(Collections.emptySet(), emptySet);
final List<String> 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

View File

@ -87,7 +87,8 @@ public class CRUDTest {
@Test
public void findInTest2() throws SQLException {
List<Entity> results = db.findAll(Entity.create("user").set("id", new Condition("id", new long[]{1, 2, 3})));
List<Entity> results = db.findAll(Entity.create("user")
.set("id", new Condition("id", new long[]{1, 2, 3})));
Assert.assertEquals(2, results.size());
}

View File

@ -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<String, Cookie> readCookieMap(HttpServletRequest httpServletRequest) {
final Cookie[] cookies = httpServletRequest.getCookies();
if(ArrayUtil.isEmpty(cookies)){
return MapUtil.empty();
}
return IterUtil.toMap(
new ArrayIter<>(httpServletRequest.getCookies()),
new CaseInsensitiveMap<>(),

View File

@ -206,8 +206,13 @@ final class InternalJSONUtil {
}
/**
* 默认情况下是否忽略null值的策略选择<br>
* JavaBean默认忽略null值其它对象不忽略
* 默认情况下是否忽略null值的策略选择以下对象不忽略null值其它对象忽略
*
* <pre>
* 1. CharSequence
* 2. JSONTokener
* 3. Map
* </pre>
*
* @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);

View File

@ -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数组<br>

View File

@ -124,7 +124,8 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
* <li>value为Map将键值对加入JSON对象</li>
* <li>value为JSON字符串CharSequence使用JSONTokener解析</li>
* <li>value为JSONTokener直接解析</li>
* <li>value为普通JavaBean如果为普通的JavaBean调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* <li>value为普通JavaBean如果为普通的JavaBean调用其getters方法getXXX或者isXXX获得值加入到JSON对象
* 例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ol>
*
* @param source JavaBean或者Map对象或者String

View File

@ -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;
}
/**

View File

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

View File

@ -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