diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java index e408b6db3..775ab77fe 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java @@ -4,10 +4,10 @@ import cn.hutool.core.bean.copier.ValueProvider; import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Editor; import cn.hutool.core.map.FuncKeyMap; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import java.lang.reflect.Type; -import java.util.HashMap; import java.util.Map; /** @@ -63,7 +63,7 @@ public class MapValueProvider implements ValueProvider { public MapValueProvider(Map map, boolean ignoreCase, boolean ignoreError, Editor keyEditor) { // issue#2202@Github // 如果用户定义了键编辑器,则提供的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){ key = key.toString().toLowerCase(); } @@ -72,6 +72,7 @@ public class MapValueProvider implements ValueProvider { } return key; }); + this.map.clear(); this.map.putAll(map); this.ignoreError = ignoreError; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java index f3dfcbd7e..edb914ed4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/MapConverter.java @@ -55,13 +55,16 @@ public class MapConverter extends AbstractConverter> { protected Map convertInternal(Object value) { Map map; if (value instanceof Map) { - final Type[] typeArguments = TypeUtil.getTypeArguments(value.getClass()); - if (null != typeArguments // - && 2 == typeArguments.length// - && Objects.equals(this.keyType, typeArguments[0]) // - && Objects.equals(this.valueType, typeArguments[1])) { - //对于键值对类型一致的Map对象,不再做转换,直接返回原对象 - return (Map) value; + final Class valueClass = value.getClass(); + if(valueClass.equals(this.mapType)){ + final Type[] typeArguments = TypeUtil.getTypeArguments(valueClass); + if (null != typeArguments // + && 2 == typeArguments.length// + && Objects.equals(this.keyType, typeArguments[0]) // + && Objects.equals(this.valueType, typeArguments[1])) { + //对于键值对类型一致的Map对象,不再做转换,直接返回原对象 + return (Map) value; + } } map = MapUtil.createMap(TypeUtil.getClass(this.mapType)); convertMapToMap((Map) value, map); 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 d3973d55e..d813f0b54 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -45,7 +45,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando /** * 持有原始数据的List */ - private final List rawList; + private List rawList; /** * 配置项 */ @@ -578,6 +578,12 @@ public class JSONArray implements JSON, JSONGetter, List, Rando 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 /** 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 ca42e36a4..8ac79a341 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -12,6 +12,7 @@ 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.map.MapWrapper; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; @@ -30,7 +31,6 @@ import java.util.Comparator; import java.util.Enumeration; import java.util.Map; import java.util.ResourceBundle; -import java.util.Set; import java.util.TreeMap; /** @@ -43,7 +43,7 @@ import java.util.TreeMap; * * @author looly */ -public class JSONObject implements JSON, JSONGetter, Map { +public class JSONObject extends MapWrapper implements JSON, JSONGetter { private static final long serialVersionUID = -330220388580734346L; /** @@ -51,14 +51,10 @@ public class JSONObject implements JSON, JSONGetter, Map */ public static final int DEFAULT_CAPACITY = MapUtil.DEFAULT_INITIAL_CAPACITY; - /** - * JSON的KV持有Map - */ - private final Map rawHashMap; /** * 配置项 */ - private final JSONConfig config; + private JSONConfig config; // -------------------------------------------------------------------------------------------------------------------- Constructor start @@ -120,25 +116,7 @@ public class JSONObject implements JSON, JSONGetter, Map * @since 4.1.19 */ public JSONObject(int capacity, JSONConfig config) { - if (null == config) { - config = JSONConfig.create(); - } - final Comparator 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()); - } - } + super(createRaw(capacity, config)); this.config = config; } @@ -310,35 +288,9 @@ public class JSONObject implements JSON, JSONGetter, Map 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 public Object getObj(String key, Object defaultValue) { - Object obj = this.rawHashMap.get(key); - return null == obj ? defaultValue : obj; + return this.getOrDefault(key, defaultValue); } @Override @@ -390,7 +342,7 @@ public class JSONObject implements JSON, JSONGetter, Map this.remove(key); } else { InternalJSONUtil.testValidity(value); - this.rawHashMap.put(key, JSONUtil.wrap(value, this.config)); + super.put(key, JSONUtil.wrap(value, this.config)); } return this; } @@ -405,7 +357,7 @@ public class JSONObject implements JSON, JSONGetter, Map */ public JSONObject putOnce(String key, Object value) throws JSONException { if (key != null) { - if (rawHashMap.containsKey(key)) { + if (containsKey(key)) { throw new JSONException("Duplicate key \"{}\"", key); } this.set(key, value); @@ -507,58 +459,6 @@ public class JSONObject implements JSON, JSONGetter, Map return this; } - @Override - public Object remove(Object key) { - return rawHashMap.remove(key); - } - - @Override - public void clear() { - rawHashMap.clear(); - } - - @Override - public Set keySet() { - return this.rawHashMap.keySet(); - } - - @Override - public Collection values() { - return rawHashMap.values(); - } - - @Override - public Set> 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字符串
* 如果解析错误,返回{@code null} @@ -622,6 +522,13 @@ public class JSONObject implements JSON, JSONGetter, Map return writer; } + @Override + public JSONObject clone() throws CloneNotSupportedException { + final JSONObject clone = (JSONObject) super.clone(); + clone.config = this.config; + return clone; + } + // ------------------------------------------------------------------------------------------------- Private method start /** @@ -773,5 +680,36 @@ public class JSONObject implements JSON, JSONGetter, Map } } } + + /** + * 根据配置创建对应的原始Map + * + * @param capacity 初始大小 + * @param config JSON配置项,{@code null}则使用默认配置 + * @return Map + */ + private static Map createRaw(int capacity, JSONConfig config) { + Map rawHashMap; + if (null == config) { + config = JSONConfig.create(); + } + final Comparator 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 } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java index 17d2986e8..a1ba61d1f 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java @@ -776,7 +776,7 @@ public class JSONUtil { return new JSONArray(object, jsonConfig); } // JSONObject - if (object instanceof Map) { + if (object instanceof Map || object instanceof Map.Entry) { return new JSONObject(object, jsonConfig); } diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java index 3d6024387..b38a5c7a9 100755 --- a/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/JSONWriter.java @@ -223,7 +223,7 @@ public class JSONWriter extends Writer { writeRaw(JSONNull.NULL.toString()); } else if (value instanceof JSON) { ((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); } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { new JSONArray(value).write(writer, indentFactor, indent); diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java index f6da3c258..5c4ee03bf 100644 --- a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java @@ -20,6 +20,7 @@ public class Issue1075Test { public void testToBeanIgnoreCase() { // 在忽略大小写的情况下,f2、fac都匹配 ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class); + Assert.assertEquals("fac", o2.getFAC()); Assert.assertEquals("f2", o2.getF2()); } 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 b6e83e0d8..75a2cd9f8 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONArrayTest.java @@ -27,10 +27,18 @@ import java.util.Map; */ public class JSONArrayTest { - @Test(expected = JSONException.class) - public void createJSONArrayTest(){ - // 集合类不支持转为JSONObject - new JSONArray(new JSONObject(), JSONConfig.create()); + @Test() + public void createJSONArrayFromJSONObjectTest(){ + // JSONObject实现了Iterable接口,可以转换为JSONArray + 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 @@ -128,7 +136,7 @@ public class JSONArrayTest { public void toDictListTest() { 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 list = JSONUtil.toList(array, Dict.class);