This commit is contained in:
Looly 2022-03-19 16:15:58 +08:00
parent 2e044cbda1
commit f72645fd4a
8 changed files with 81 additions and 124 deletions

View File

@ -4,10 +4,10 @@ import cn.hutool.core.bean.copier.ValueProvider;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Editor; import cn.hutool.core.lang.Editor;
import cn.hutool.core.map.FuncKeyMap; import cn.hutool.core.map.FuncKeyMap;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -63,7 +63,7 @@ public class MapValueProvider implements ValueProvider<String> {
public MapValueProvider(Map map, boolean ignoreCase, boolean ignoreError, Editor<String> keyEditor) { public MapValueProvider(Map map, boolean ignoreCase, boolean ignoreError, Editor<String> keyEditor) {
// issue#2202@Github // issue#2202@Github
// 如果用户定义了键编辑器则提供的map中的数据必须全部转换key // 如果用户定义了键编辑器则提供的map中的数据必须全部转换key
this.map = new FuncKeyMap(new HashMap(map.size(), 1), (key)->{ this.map = new FuncKeyMap(ObjectUtil.clone(map), (key)->{
if(ignoreCase && key instanceof CharSequence){ if(ignoreCase && key instanceof CharSequence){
key = key.toString().toLowerCase(); key = key.toString().toLowerCase();
} }
@ -72,6 +72,7 @@ public class MapValueProvider implements ValueProvider<String> {
} }
return key; return key;
}); });
this.map.clear();
this.map.putAll(map); this.map.putAll(map);
this.ignoreError = ignoreError; this.ignoreError = ignoreError;

View File

@ -55,13 +55,16 @@ public class MapConverter extends AbstractConverter<Map<?, ?>> {
protected Map<?, ?> convertInternal(Object value) { protected Map<?, ?> convertInternal(Object value) {
Map map; Map map;
if (value instanceof Map) { if (value instanceof Map) {
final Type[] typeArguments = TypeUtil.getTypeArguments(value.getClass()); final Class<?> valueClass = value.getClass();
if (null != typeArguments // if(valueClass.equals(this.mapType)){
&& 2 == typeArguments.length// final Type[] typeArguments = TypeUtil.getTypeArguments(valueClass);
&& Objects.equals(this.keyType, typeArguments[0]) // if (null != typeArguments //
&& Objects.equals(this.valueType, typeArguments[1])) { && 2 == typeArguments.length//
//对于键值对类型一致的Map对象不再做转换直接返回原对象 && Objects.equals(this.keyType, typeArguments[0]) //
return (Map) value; && Objects.equals(this.valueType, typeArguments[1])) {
//对于键值对类型一致的Map对象不再做转换直接返回原对象
return (Map) value;
}
} }
map = MapUtil.createMap(TypeUtil.getClass(this.mapType)); map = MapUtil.createMap(TypeUtil.getClass(this.mapType));
convertMapToMap((Map) value, map); convertMapToMap((Map) value, map);

View File

@ -45,7 +45,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
/** /**
* 持有原始数据的List * 持有原始数据的List
*/ */
private final List<Object> rawList; private List<Object> rawList;
/** /**
* 配置项 * 配置项
*/ */
@ -578,6 +578,12 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
return writer; return writer;
} }
@Override
public Object clone() throws CloneNotSupportedException {
final JSONArray clone = (JSONArray) super.clone();
clone.rawList = ObjectUtil.clone(this.rawList);
return clone;
}
// ------------------------------------------------------------------------------------------------- Private method start // ------------------------------------------------------------------------------------------------- Private method start
/** /**

View File

@ -12,6 +12,7 @@ import cn.hutool.core.map.CaseInsensitiveLinkedMap;
import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.map.CaseInsensitiveTreeMap; import cn.hutool.core.map.CaseInsensitiveTreeMap;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
@ -30,7 +31,6 @@ import java.util.Comparator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
/** /**
@ -43,7 +43,7 @@ import java.util.TreeMap;
* *
* @author looly * @author looly
*/ */
public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object> { public class JSONObject extends MapWrapper<String, Object> implements JSON, JSONGetter<String> {
private static final long serialVersionUID = -330220388580734346L; private static final long serialVersionUID = -330220388580734346L;
/** /**
@ -51,14 +51,10 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
*/ */
public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY; public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY;
/**
* JSON的KV持有Map
*/
private final Map<String, Object> rawHashMap;
/** /**
* 配置项 * 配置项
*/ */
private final JSONConfig config; private JSONConfig config;
// -------------------------------------------------------------------------------------------------------------------- Constructor start // -------------------------------------------------------------------------------------------------------------------- Constructor start
@ -120,25 +116,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
* @since 4.1.19 * @since 4.1.19
*/ */
public JSONObject(int capacity, JSONConfig config) { public JSONObject(int capacity, JSONConfig config) {
if (null == config) { super(createRaw(capacity, config));
config = JSONConfig.create();
}
final Comparator<String> keyComparator = config.getKeyComparator();
if (config.isIgnoreCase()) {
if (null != keyComparator) {
// 比较器存在情况下isOrder无效
this.rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
} else {
this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity);
}
} else {
if (null != keyComparator) {
// 比较器存在情况下isOrder无效
this.rawHashMap = new TreeMap<>(keyComparator);
} else {
this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder());
}
}
this.config = config; this.config = config;
} }
@ -310,35 +288,9 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
return ja; return ja;
} }
@Override
public int size() {
return rawHashMap.size();
}
@Override
public boolean isEmpty() {
return rawHashMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return rawHashMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return rawHashMap.containsValue(value);
}
@Override
public Object get(Object key) {
return rawHashMap.get(key);
}
@Override @Override
public Object getObj(String key, Object defaultValue) { public Object getObj(String key, Object defaultValue) {
Object obj = this.rawHashMap.get(key); return this.getOrDefault(key, defaultValue);
return null == obj ? defaultValue : obj;
} }
@Override @Override
@ -390,7 +342,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
this.remove(key); this.remove(key);
} else { } else {
InternalJSONUtil.testValidity(value); InternalJSONUtil.testValidity(value);
this.rawHashMap.put(key, JSONUtil.wrap(value, this.config)); super.put(key, JSONUtil.wrap(value, this.config));
} }
return this; return this;
} }
@ -405,7 +357,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
*/ */
public JSONObject putOnce(String key, Object value) throws JSONException { public JSONObject putOnce(String key, Object value) throws JSONException {
if (key != null) { if (key != null) {
if (rawHashMap.containsKey(key)) { if (containsKey(key)) {
throw new JSONException("Duplicate key \"{}\"", key); throw new JSONException("Duplicate key \"{}\"", key);
} }
this.set(key, value); this.set(key, value);
@ -507,58 +459,6 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
return this; return this;
} }
@Override
public Object remove(Object key) {
return rawHashMap.remove(key);
}
@Override
public void clear() {
rawHashMap.clear();
}
@Override
public Set<String> keySet() {
return this.rawHashMap.keySet();
}
@Override
public Collection<Object> values() {
return rawHashMap.values();
}
@Override
public Set<Entry<String, Object>> entrySet() {
return rawHashMap.entrySet();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((rawHashMap == null) ? 0 : rawHashMap.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final JSONObject other = (JSONObject) obj;
if (rawHashMap == null) {
return other.rawHashMap == null;
} else {
return rawHashMap.equals(other.rawHashMap);
}
}
/** /**
* 返回JSON字符串<br> * 返回JSON字符串<br>
* 如果解析错误返回{@code null} * 如果解析错误返回{@code null}
@ -622,6 +522,13 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
return writer; return writer;
} }
@Override
public JSONObject clone() throws CloneNotSupportedException {
final JSONObject clone = (JSONObject) super.clone();
clone.config = this.config;
return clone;
}
// ------------------------------------------------------------------------------------------------- Private method start // ------------------------------------------------------------------------------------------------- Private method start
/** /**
@ -773,5 +680,36 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
} }
} }
} }
/**
* 根据配置创建对应的原始Map
*
* @param capacity 初始大小
* @param config JSON配置项{@code null}则使用默认配置
* @return Map
*/
private static Map<String, Object> createRaw(int capacity, JSONConfig config) {
Map<String, Object> rawHashMap;
if (null == config) {
config = JSONConfig.create();
}
final Comparator<String> keyComparator = config.getKeyComparator();
if (config.isIgnoreCase()) {
if (null != keyComparator) {
// 比较器存在情况下isOrder无效
rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
} else {
rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity);
}
} else {
if (null != keyComparator) {
// 比较器存在情况下isOrder无效
rawHashMap = new TreeMap<>(keyComparator);
} else {
rawHashMap = MapUtil.newHashMap(capacity, config.isOrder());
}
}
return rawHashMap;
}
// ------------------------------------------------------------------------------------------------- Private method end // ------------------------------------------------------------------------------------------------- Private method end
} }

View File

@ -776,7 +776,7 @@ public class JSONUtil {
return new JSONArray(object, jsonConfig); return new JSONArray(object, jsonConfig);
} }
// JSONObject // JSONObject
if (object instanceof Map) { if (object instanceof Map || object instanceof Map.Entry) {
return new JSONObject(object, jsonConfig); return new JSONObject(object, jsonConfig);
} }

View File

@ -223,7 +223,7 @@ public class JSONWriter extends Writer {
writeRaw(JSONNull.NULL.toString()); writeRaw(JSONNull.NULL.toString());
} else if (value instanceof JSON) { } else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent); ((JSON) value).write(writer, indentFactor, indent);
} else if (value instanceof Map) { } else if (value instanceof Map || value instanceof Map.Entry) {
new JSONObject(value).write(writer, indentFactor, indent); new JSONObject(value).write(writer, indentFactor, indent);
} else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) {
new JSONArray(value).write(writer, indentFactor, indent); new JSONArray(value).write(writer, indentFactor, indent);

View File

@ -20,6 +20,7 @@ public class Issue1075Test {
public void testToBeanIgnoreCase() { public void testToBeanIgnoreCase() {
// 在忽略大小写的情况下f2fac都匹配 // 在忽略大小写的情况下f2fac都匹配
ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class); ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class);
Assert.assertEquals("fac", o2.getFAC()); Assert.assertEquals("fac", o2.getFAC());
Assert.assertEquals("f2", o2.getF2()); Assert.assertEquals("f2", o2.getF2());
} }

View File

@ -27,10 +27,18 @@ import java.util.Map;
*/ */
public class JSONArrayTest { public class JSONArrayTest {
@Test(expected = JSONException.class) @Test()
public void createJSONArrayTest(){ public void createJSONArrayFromJSONObjectTest(){
// 集合类不支持转为JSONObject // JSONObject实现了Iterable接口可以转换为JSONArray
new JSONArray(new JSONObject(), JSONConfig.create()); final JSONObject jsonObject = new JSONObject();
JSONArray jsonArray = new JSONArray(jsonObject, JSONConfig.create());
Assert.assertEquals(new JSONArray(), jsonArray);
jsonObject.set("key1", "value1");
jsonArray = new JSONArray(jsonObject, JSONConfig.create());
Assert.assertEquals(1, jsonArray.size());
Assert.assertEquals("[{\"key1\":\"value1\"}]", jsonArray.toString());
} }
@Test @Test
@ -128,7 +136,7 @@ public class JSONArrayTest {
public void toDictListTest() { public void toDictListTest() {
String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]"; String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
JSONArray array = JSONUtil.parseArray(jsonArr); JSONArray array = JSONUtil.parseArray(jsonArr, JSONConfig.create().setIgnoreError(false));
List<Dict> list = JSONUtil.toList(array, Dict.class); List<Dict> list = JSONUtil.toList(array, Dict.class);