This commit is contained in:
Looly 2022-02-13 22:51:58 +08:00
parent 0189de2dad
commit 0344982767
9 changed files with 172 additions and 8 deletions

View File

@ -23,6 +23,7 @@
* 【core 】 DateUtil增加rangeContains、rangeNotContains(pr#537@Gitee)
* 【core 】 Resource增加isModified默认方法
* 【core 】 增加VfsResource
* 【json 】 JSONConfig增加setKeyComparator、setNatureKeyComparator方法支持自定义排序issue#I4RBZ4@Gitee
### 🐞Bug修复
* 【core 】 修复ChineseDate农历获取正月出现数组越界BUGissue#2112@Github

View File

@ -11,6 +11,18 @@ import java.util.function.Function;
*/
public class CompareUtil {
/**
* 获取自然排序器即默认排序器
*
* @param <E> 排序节点类型
* @return 默认排序器
* @since 5.7.21
*/
@SuppressWarnings("unchecked")
public static <E extends Comparable<? super E>> Comparator<E> naturalComparator() {
return ComparableComparator.INSTANCE;
}
/**
* 对象比较比较结果取决于comparator如果被比较对象为null传入的comparator对象应处理此情况<br>
* 如果传入comparator为null则使用默认规则比较此时被比较对象必须实现Comparable接口

View File

@ -0,0 +1,73 @@
package cn.hutool.core.map;
import java.util.Comparator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* 忽略大小写的{@link TreeMap}<br>
* 对KEY忽略大小写get("Value")和get("value")获得的值相同put进入的值也会被覆盖
*
* @author Looly
*
* @param <K> 键类型
* @param <V> 值类型
* @since 3.3.1
*/
public class CaseInsensitiveTreeMap<K, V> extends CustomKeyMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start
/**
* 构造
*/
public CaseInsensitiveTreeMap() {
this((Comparator<? super K>) null);
}
/**
* 构造
*
* @param m Map
* @since 3.1.2
*/
public CaseInsensitiveTreeMap(Map<? extends K, ? extends V> m) {
this();
this.putAll(m);
}
/**
* 构造
*
* @param m Map
* @since 3.1.2
*/
public CaseInsensitiveTreeMap(SortedMap<? extends K, ? extends V> m) {
super(new TreeMap<K, V>(m));
}
/**
* 构造
*
* @param comparator 比较器{@code null}表示使用默认比较器
*/
public CaseInsensitiveTreeMap(Comparator<? super K> comparator) {
super(new TreeMap<>(comparator));
}
// ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为小写
*
* @param key KEY
* @return 小写KEY
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = key.toString().toLowerCase();
}
return key;
}
}

View File

@ -1,6 +1,9 @@
package cn.hutool.json;
import cn.hutool.core.comparator.CompareUtil;
import java.io.Serializable;
import java.util.Comparator;
/**
* JSON配置项
@ -15,6 +18,10 @@ public class JSONConfig implements Serializable {
* 是否有序顺序按照加入顺序排序只针对JSONObject有效
*/
private boolean order;
/**
* 键排序规则{@code null}表示不排序不排序情况下如果{@link #order}{@code true}按照加入顺序排序否则按照hash排序
*/
private Comparator<String> keyComparator;
/**
* 是否忽略转换过程中的异常
*/
@ -70,6 +77,40 @@ public class JSONConfig implements Serializable {
return this;
}
/**
* 获取键排序规则<br>
* 键排序规则{@code null}表示不排序不排序情况下如果{@link #order}{@code true}按照加入顺序排序否则按照hash排序
*
* @return 键排序规则
* @since 5.7.21
*/
public Comparator<String> getKeyComparator() {
return this.keyComparator;
}
/**
* 设置自然排序即按照字母顺序排序
*
* @return this
* @since 5.7.21
*/
public JSONConfig setNatureKeyComparator() {
return setKeyComparator(CompareUtil.naturalComparator());
}
/**
* 设置键排序规则<br>
* 键排序规则{@code null}表示不排序不排序情况下如果{@link #order}{@code true}按照加入顺序排序否则按照hash排序
*
* @param keyComparator 键排序规则
* @return this
* @since 5.7.21
*/
public JSONConfig setKeyComparator(Comparator<String> keyComparator) {
this.keyComparator = keyComparator;
return this;
}
/**
* 是否忽略转换过程中的异常
*

View File

@ -10,6 +10,7 @@ import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.mutable.MutablePair;
import cn.hutool.core.map.CaseInsensitiveLinkedMap;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.map.CaseInsensitiveTreeMap;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
@ -25,10 +26,12 @@ import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
/**
* JSON对象<br>
@ -121,9 +124,21 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
config = JSONConfig.create();
}
if (config.isIgnoreCase()) {
this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity);
final Comparator<String> keyComparator = config.getKeyComparator();
if(null != keyComparator){
// 比较器存在情况下isOrder无效
this.rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
}else{
this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity);
}
} else {
this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder());
final Comparator<String> keyComparator = config.getKeyComparator();
if(null != keyComparator){
// 比较器存在情况下isOrder无效
this.rawHashMap = new TreeMap<>(keyComparator);
}else{
this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder());
}
}
this.config = config;
}
@ -178,7 +193,8 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
public JSONObject(Object source, boolean ignoreNullValue, boolean isOrder) {
this(source, JSONConfig.create().setOrder(isOrder)//
.setIgnoreCase((source instanceof CaseInsensitiveMap))//
.setIgnoreNullValue(ignoreNullValue));
.setIgnoreNullValue(ignoreNullValue)
);
}
/**

View File

@ -0,0 +1,18 @@
package cn.hutool.json;
import org.junit.Assert;
import org.junit.Test;
/**
* https://gitee.com/dromara/hutool/issues/I4RBZ4
*/
public class IssueI4RBZ4Test {
@Test
public void sortTest(){
String jsonStr = "{\"id\":\"123\",\"array\":[1,2,3],\"outNum\":356,\"body\":{\"ava1\":\"20220108\",\"use\":1,\"ava2\":\"20230108\"},\"name\":\"John\"}";
final JSONObject jsonObject = JSONUtil.parseObj(jsonStr, JSONConfig.create().setNatureKeyComparator());
Assert.assertEquals("{\"array\":[1,2,3],\"body\":{\"ava1\":\"20220108\",\"ava2\":\"20230108\",\"use\":1},\"id\":\"123\",\"name\":\"John\",\"outNum\":356}", jsonObject.toString());
}
}

View File

@ -1,18 +1,19 @@
package cn.hutool.json;
import cn.hutool.core.lang.Console;
import lombok.Data;
import lombok.experimental.Accessors;
import org.junit.Assert;
import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class issues1881Test {
public class Issues1881Test {
@Accessors(chain = true)
@Data
public class ThingsHolderContactVO implements Serializable {
static class ThingsHolderContactVO implements Serializable {
private static final long serialVersionUID = -8727337936070932370L;
private Long id;
@ -30,6 +31,6 @@ public class issues1881Test {
holderContactVOList.add(new ThingsHolderContactVO().setId(1L).setName("1"));
holderContactVOList.add(new ThingsHolderContactVO().setId(2L).setName("2"));
Console.log(JSONUtil.parseArray(holderContactVOList));
Assert.assertEquals("[{\"name\":\"1\",\"id\":1},{\"name\":\"2\",\"id\":2}]", JSONUtil.parseArray(holderContactVOList).toString());
}
}

View File

@ -2,6 +2,7 @@ package cn.hutool.json;
import cn.hutool.core.lang.Console;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
/**
@ -33,6 +34,7 @@ public class JSONStrFormatterTest {
}
@Test
@Ignore
public void formatTest4(){
String jsonStr = "{\"employees\":[{\"firstName\":\"Bill\",\"lastName\":\"Gates\"},{\"firstName\":\"George\",\"lastName\":\"Bush\"},{\"firstName\":\"Thomas\",\"lastName\":\"Carter\"}]}";
Console.log(JSONUtil.formatJsonStr(jsonStr));

View File

@ -36,7 +36,7 @@ public class JSONUtilTest {
@Test(expected = JSONException.class)
public void parseNumberTest() {
JSONArray json = JSONUtil.parseArray(123L);
Console.log(json);
Assert.assertNotNull(json);
}
/**