diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java index 61905d586..e3ac8398d 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java @@ -25,20 +25,15 @@ import org.dromara.hutool.core.lang.mutable.MutableEntry; import org.dromara.hutool.core.map.CaseInsensitiveLinkedMap; import org.dromara.hutool.core.map.CaseInsensitiveTreeMap; import org.dromara.hutool.core.math.NumberUtil; -import org.dromara.hutool.core.reflect.ConstructorUtil; -import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.split.SplitUtil; import org.dromara.hutool.json.reader.JSONTokener; -import org.dromara.hutool.json.serialize.GlobalSerializeMapping; -import org.dromara.hutool.json.serialize.JSONDeserializer; -import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.serializer.JSONStringer; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; -import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.*; import java.util.function.Predicate; @@ -309,25 +304,6 @@ public final class InternalJSONUtil { return rawHashMap; } - /** - * 根据目标类型,获取对应的{@link JSONDeserializer},首先判断是否实现了{@link JSONDeserializer}接口
- * 如果未实现从{@link GlobalSerializeMapping}中查找全局的{@link JSONDeserializer},否则返回null - * - * @param targetType 目标类型 - * @param 目标类型 - * @return {@link JSONDeserializer} - */ - @SuppressWarnings("unchecked") - public static JSONDeserializer getDeserializer(final Type targetType) { - final Class rawType = (Class) TypeUtil.getClass(targetType); - if (null != rawType && JSONDeserializer.class.isAssignableFrom(rawType)) { - return (JSONDeserializer) ConstructorUtil.newInstanceIfPossible(rawType); - } - - // 全局自定义反序列化(优先级低于实现JSONDeserializer接口) - return (JSONDeserializer) GlobalSerializeMapping.getDeserializer(targetType); - } - // --------------------------------------------------------------------------------------------- Private method start /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java index 82ef8dc42..b32e117cc 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java @@ -303,9 +303,26 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * * @return Iterable * @since 4.0.12 + * @param JSON类型 + * @param type JSON类型 */ - public Iterable jsonIter() { - return new JSONObjectIter(iterator()); + public Iterable jsonIter(final Class type) { + final Iterator iterator = iterator(); + return () -> new Iterator() { + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public T next() { + return type.cast(iterator.next()); + } + @Override + public void remove() { + iterator.remove(); + } + }; } @Override diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObjectIter.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONObjectIter.java deleted file mode 100644 index c77b84fc2..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObjectIter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.dromara.hutool.json; - -import java.util.Iterator; - -/** - * 此类用于在JSONAray中便于遍历JSONObject而封装的Iterable,可以借助foreach语法遍历 - * - * @author looly - * @since 4.0.12 - */ -public class JSONObjectIter implements Iterable { - - Iterator iterator; - - /** - * 构造 - * - * @param iterator 迭代器 - */ - public JSONObjectIter(final Iterator iterator) { - this.iterator = iterator; - } - - @Override - public Iterator iterator() { - return new Iterator() { - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public JSONObject next() { - return (JSONObject) iterator.next(); - } - - @Override - public void remove() { - iterator.remove(); - } - }; - } - -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONSupport.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONSupport.java deleted file mode 100644 index 1e09390c8..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONSupport.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.dromara.hutool.json; - -import org.dromara.hutool.core.bean.copier.BeanCopier; -import org.dromara.hutool.json.serialize.JSONDeserializer; -import org.dromara.hutool.json.serialize.JSONStringer; - -/** - * JSON支持
- * 继承此类实现实体类与JSON的相互转换 - * - * @author Looly - */ -public class JSONSupport implements JSONStringer, JSONDeserializer { - - /** - * JSON String转Bean - * - * @param jsonString JSON String - */ - public void deserialize(final String jsonString) { - deserialize(new JSONObject(jsonString)); - } - - /** - * JSON转Bean - * - * @param json JSON - */ - @Override - public Object deserialize(final JSON json) { - BeanCopier.of(json, - this, this.getClass(), - InternalJSONUtil.toCopyOptions(json.config())).copy(); - return this; - } - - /** - * @return JSON对象 - */ - public JSONObject toJSON() { - return new JSONObject(this); - } - - @Override - public String toJSONString() { - return toJSON().toString(); - } - - /** - * 美化的JSON(使用回车缩进显示JSON),用于打印输出debug - * - * @return 美化的JSON - */ - public String toPrettyString() { - return toJSON().toStringPretty(); - } - - @Override - public String toString() { - return toJSONString(); - } -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java index 63a8ca4a5..121dfc441 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java @@ -23,17 +23,12 @@ import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.convert.JSONConverter; -import org.dromara.hutool.json.serialize.GlobalSerializeMapping; -import org.dromara.hutool.json.serialize.JSONArraySerializer; -import org.dromara.hutool.json.serialize.JSONDeserializer; -import org.dromara.hutool.json.serialize.JSONObjectSerializer; import org.dromara.hutool.json.writer.GlobalValueWriters; import org.dromara.hutool.json.writer.JSONValueWriter; import org.dromara.hutool.json.writer.JSONWriter; import org.dromara.hutool.json.xml.JSONXMLUtil; import java.io.File; -import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Type; @@ -242,12 +237,8 @@ public class JSONUtil { * @param obj Bean对象 * @return JSON字符串 */ - public static String toJsonPrettyStr(Object obj) { - obj = parse(obj); - if (obj instanceof JSON) { - return ((JSON) obj).toStringPretty(); - } - return StrUtil.toStringOrNull(obj); + public static String toJsonPrettyStr(final Object obj) { + return parse(obj).toStringPretty(); } /** @@ -292,19 +283,9 @@ public class JSONUtil { * @param writer Writer * @since 5.3.3 */ - public static void toJsonStr(Object obj, final Writer writer) { + public static void toJsonStr(final Object obj, final Writer writer) { if (null != obj) { - obj = parse(obj); - if (obj instanceof JSON) { - ((JSON) obj).write(writer); - } - - // 普通值 - try { - writer.write(obj.toString()); - } catch (final IOException e) { - throw new IORuntimeException(e); - } + parse(obj).write(writer); } } @@ -555,40 +536,4 @@ public class JSONUtil { } return StrUtil.isWrap(StrUtil.trim(str), '[', ']'); } - - /** - * 加入自定义的序列化器 - * - * @param type 对象类型 - * @param serializer 序列化器实现 - * @see GlobalSerializeMapping#putSerializer(Type, JSONObjectSerializer) - * @since 6.0.0 - */ - public static void putSerializer(final Type type, final JSONObjectSerializer serializer) { - GlobalSerializeMapping.putSerializer(type, serializer); - } - - /** - * 加入自定义的序列化器 - * - * @param type 对象类型 - * @param serializer 序列化器实现 - * @see GlobalSerializeMapping#putSerializer(Type, JSONArraySerializer) - * @since 6.0.0 - */ - public static void putSerializer(final Type type, final JSONArraySerializer serializer) { - GlobalSerializeMapping.putSerializer(type, serializer); - } - - /** - * 加入自定义的反序列化器 - * - * @param type 对象类型 - * @param deserializer 反序列化器实现 - * @see GlobalSerializeMapping#putDeserializer(Type, JSONDeserializer) - * @since 4.6.5 - */ - public static void putDeserializer(final Type type, final JSONDeserializer deserializer) { - GlobalSerializeMapping.putDeserializer(type, deserializer); - } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java index 1a56f83ba..e6fc5e953 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java @@ -32,8 +32,7 @@ import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.json.*; import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONTokener; -import org.dromara.hutool.json.serialize.JSONDeserializer; -import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.serializer.*; import java.io.Serializable; import java.lang.reflect.Type; @@ -139,6 +138,7 @@ public class JSONConverter implements Converter, Serializable { * @return 转换后的对象 * @throws JSONException 转换异常 */ + @SuppressWarnings("unchecked") public JSON toJSON(Object obj) throws JSONException { if (null == obj) { return null; @@ -154,6 +154,22 @@ public class JSONConverter implements Converter, Serializable { return (JSON) obj; } + // 自定义序列化 + final JSONSerializer serializer = + (JSONSerializer) SerializerManager.getInstance().getSerializer(obj); + if (null != serializer) { + return serializer.serialize(obj, new JSONContext() { + @Override + public JSON getContextJson() { + return null; + } + @Override + public JSONConfig config() { + return JSONConverter.this.config; + } + }); + } + if (obj instanceof Number || obj instanceof Boolean) { // RFC8259规范的原始类型数据 return new JSONPrimitive(obj, config); @@ -223,10 +239,10 @@ public class JSONConverter implements Converter, Serializable { @SuppressWarnings("unchecked") private T toBean(final Type targetType, final JSON json) { // 自定义对象反序列化 - final JSONDeserializer deserializer = InternalJSONUtil.getDeserializer(targetType); + final JSONDeserializer deserializer = SerializerManager.getInstance().getDeserializer(targetType); if (null != deserializer) { - return (T) deserializer.deserialize(json); + return (T) deserializer.deserialize(json, targetType); } // 当目标类型不确定时,返回原JSON diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java index b7c61e0ea..e82467e99 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java @@ -16,16 +16,18 @@ package org.dromara.hutool.json.mapper; +import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.collection.iter.ArrayIter; import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.core.array.ArrayUtil; -import org.dromara.hutool.json.*; +import org.dromara.hutool.json.JSONArray; +import org.dromara.hutool.json.JSONConfig; +import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONTokener; -import org.dromara.hutool.json.serialize.GlobalSerializeMapping; -import org.dromara.hutool.json.serialize.JSONSerializer; +import org.dromara.hutool.json.serializer.JSONSerializer; +import org.dromara.hutool.json.serializer.SerializerManager; import java.io.InputStream; import java.io.Reader; @@ -79,7 +81,7 @@ public class JSONArrayMapper { * @param jsonArray 目标{@link JSONArray} * @throws JSONException 非数组或集合 */ - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("unchecked") public void mapTo(final JSONArray jsonArray) throws JSONException { final Object source = this.source; if (null == source) { @@ -87,9 +89,9 @@ public class JSONArrayMapper { } // 自定义序列化 - final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass()); + final JSONSerializer serializer = SerializerManager.getInstance().getSerializer(source.getClass()); if (null != serializer) { - serializer.serialize(jsonArray, source); + serializer.serialize(source, ()-> jsonArray); return; } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java index e044ef24a..78d523dd5 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java @@ -27,8 +27,8 @@ import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.json.*; import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONTokener; -import org.dromara.hutool.json.serialize.GlobalSerializeMapping; -import org.dromara.hutool.json.serialize.JSONSerializer; +import org.dromara.hutool.json.serializer.JSONSerializer; +import org.dromara.hutool.json.serializer.SerializerManager; import org.dromara.hutool.json.xml.JSONXMLParser; import org.dromara.hutool.json.xml.ParseConfig; @@ -88,7 +88,7 @@ public class JSONObjectMapper { * * @param jsonObject 目标{@link JSONObject} */ - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings("rawtypes") public void mapTo(final JSONObject jsonObject) { final Object source = this.source; if (null == source) { @@ -96,9 +96,9 @@ public class JSONObjectMapper { } // 自定义序列化 - final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass()); + final JSONSerializer serializer = SerializerManager.getInstance().getSerializer(source.getClass()); if (null != serializer) { - serializer.serialize(jsonObject, source); + serializer.serialize(source, () -> jsonObject); return; } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java index cb9a3c2f8..cc5a682c7 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java @@ -22,7 +22,7 @@ import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONObject; -import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.serializer.JSONStringer; import org.dromara.hutool.json.writer.GlobalValueWriters; import java.io.Serializable; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/GlobalSerializeMapping.java b/hutool-json/src/main/java/org/dromara/hutool/json/serialize/GlobalSerializeMapping.java deleted file mode 100644 index 91038bed3..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/GlobalSerializeMapping.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.dromara.hutool.json.serialize; - -import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; -import org.dromara.hutool.core.reflect.NullType; -import org.dromara.hutool.core.util.ObjUtil; -import org.dromara.hutool.json.JSON; - -import java.lang.reflect.Type; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 全局的序列化和反序列化器映射
- * 在JSON和Java对象转换过程中,优先使用注册于此处的自定义转换
- * 分别定义{@link JSONObjectSerializer}和{@link JSONArraySerializer}的原因是,实际加入对象到JSON中时,无法区分是JSONObject还是JSONArray - * - * @author Looly - */ -public class GlobalSerializeMapping { - - private static Map> serializerMap; - private static Map> deserializerMap; - - static { - serializerMap = new SafeConcurrentHashMap<>(); - deserializerMap = new SafeConcurrentHashMap<>(); - - final TemporalAccessorSerializer localDateSerializer = new TemporalAccessorSerializer(LocalDate.class); - serializerMap.put(LocalDate.class, localDateSerializer); - deserializerMap.put(LocalDate.class, localDateSerializer); - - final TemporalAccessorSerializer localDateTimeSerializer = new TemporalAccessorSerializer(LocalDateTime.class); - serializerMap.put(LocalDateTime.class, localDateTimeSerializer); - deserializerMap.put(LocalDateTime.class, localDateTimeSerializer); - - final TemporalAccessorSerializer localTimeSerializer = new TemporalAccessorSerializer(LocalTime.class); - serializerMap.put(LocalTime.class, localTimeSerializer); - deserializerMap.put(LocalTime.class, localTimeSerializer); - } - - /** - * 加入自定义的JSONArray序列化器 - * - * @param type 对象类型 - * @param serializer 序列化器实现 - */ - public static void putSerializer(final Type type, final JSONArraySerializer serializer) { - putInternal(type, serializer); - } - - /** - * 加入自定义的JSONObject序列化器 - * - * @param type 对象类型 - * @param serializer 序列化器实现 - */ - public static void putSerializer(final Type type, final JSONObjectSerializer serializer) { - putInternal(type, serializer); - } - - /** - * 加入自定义的反序列化器 - * - * @param type 对象类型 - * @param deserializer 反序列化器实现 - */ - synchronized public static void putDeserializer(final Type type, final JSONDeserializer deserializer) { - if (null == deserializerMap) { - deserializerMap = new ConcurrentHashMap<>(); - } - deserializerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), deserializer); - } - - /** - * 获取自定义的序列化器,如果未定义返回{@code null} - * - * @param type 类型 - * @return 自定义的序列化器或者{@code null} - */ - public static JSONSerializer getSerializer(final Type type) { - if (null == serializerMap || null == type) { - return null; - } - return serializerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE)); - } - - /** - * 获取自定义的反序列化器,如果未定义返回{@code null} - * - * @param type 类型 - * @return 自定义的反序列化器或者{@code null} - */ - public static JSONDeserializer getDeserializer(final Type type) { - if (null == deserializerMap || null == type) { - return null; - } - return deserializerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE)); - } - - /** - * 加入自定义的序列化器 - * - * @param type 对象类型 - * @param serializer 序列化器实现 - */ - synchronized private static void putInternal(final Type type, final JSONSerializer serializer) { - if (null == serializerMap) { - serializerMap = new ConcurrentHashMap<>(); - } - serializerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), serializer); - } -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONArraySerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java similarity index 50% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONArraySerializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java index f5f359063..656e11505 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONArraySerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn + * Copyright (c) 2024 Hutool Team and hutool.cn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,32 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer; -import org.dromara.hutool.json.JSONArray; +import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.JSONConfig; /** - * JSON列表的序列化接口,用于将特定对象序列化为{@link JSONArray} + * JSON序列化上下文,用于获取当前JSON对象,以便在序列化过程中获取配置信息 * - * @param 对象类型 - * - * @author Looly + * @author looly + * @since 6.0.0 */ -@FunctionalInterface -public interface JSONArraySerializer extends JSONSerializer{} +public interface JSONContext { + + /** + * 获取当前JSON对象 + * + * @return JSON对象 + */ + JSON getContextJson(); + + /** + * 获取JSON配置 + * + * @return JSON配置 + */ + default JSONConfig config() { + return getContextJson().config(); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java similarity index 61% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONDeserializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java index 4f8f5f9d5..bab1d4b97 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java @@ -14,30 +14,32 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer; import org.dromara.hutool.json.JSON; import java.lang.reflect.Type; /** - * JSON自定义反序列化接口,实现JSON to Bean,使用方式为: + * JSON自定义反序列化接口,实现{@link JSON} to Bean,使用方式为: *
    - *
  • 定义好反序列化规则,使用{@link GlobalSerializeMapping#putDeserializer(Type, JSONDeserializer)},关联指定类型与转换器实现反序列化。
  • - *
  • 使Bean实现此接口,调用{@link #deserialize(JSON)}解析字段,返回this即可。
  • + *
  • 定义好反序列化规则,关联指定类型与转换器实现反序列化。
  • + *
  • 使Bean实现此接口,调用{@link #deserialize(JSON, Type)}解析字段,返回this即可。
  • *
* - * @param 反序列化后的类型 + * @param 反序列化后的类型 * @author Looly */ @FunctionalInterface -public interface JSONDeserializer { +public interface JSONDeserializer { /** - * 反序列化,通过实现此方法,自定义实现JSON转换为指定类型的逻辑 + * 反序列化,通过实现此方法,自定义实现JSON转换为指定类型的逻辑
+ * deserializeType用于指明当结果对象存在泛型时,可以获取泛型对应的实际类型 * * @param json {@link JSON} + * @param deserializeType 反序列化类型 * @return 目标对象 */ - T deserialize(JSON json); + V deserialize(JSON json, Type deserializeType); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java similarity index 58% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONSerializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java index 683a8430d..b7b3aabc1 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java @@ -14,26 +14,30 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer; import org.dromara.hutool.json.JSON; /** * 序列化接口,通过实现此接口,实现自定义的对象转换为JSON的操作 * - * @param JSON类型,可以是JSONObject或者JSONArray * @param 对象类型 * @author Looly */ @FunctionalInterface -public interface JSONSerializer { +public interface JSONSerializer { /** - * 序列化实现,通过实现此方法,将指定类型的对象转换为{@link JSON}对象
- * 转换后的对象可以为JSONObject也可以为JSONArray,首先new一个空的JSON,然后将需要的数据字段put到JSON对象中去即可。 + * 序列化实现,通过实现此方法,将指定类型的对象转换为{@link JSON}对象,可以: + *
    + *
  • 如果为原始类型,可以转为{@link org.dromara.hutool.json.JSONPrimitive}
  • + *
  • 如果是集合或数组类,可以转为{@link org.dromara.hutool.json.JSONArray}
  • + *
  • 如果是Bean或键值对类型,可以转为{@link org.dromara.hutool.json.JSONObject}
  • + *
* - * @param json JSON,可以为JSONObject或者JSONArray - * @param bean 指定类型对象 + * @param bean 指定类型对象 + * @param context JSON上下文,用于获取当前json节点或配置等信息 + * @return JSON */ - void serialize(T json, V bean); + JSON serialize(V bean, JSONContext context); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONStringer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONStringer.java similarity index 96% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONStringer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONStringer.java index ff38b1219..62aa2c986 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONStringer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONStringer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer; import org.dromara.hutool.core.lang.wrapper.Wrapper; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java new file mode 100644 index 000000000..e723e8260 --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.json.serializer; + +import org.dromara.hutool.json.JSON; + +import java.lang.reflect.Type; + +/** + * 带有匹配方法的 JSON反序列化器
+ * 匹配方法返回true表示匹配,反序列化器将执行反序列化操作 + * + * @param 反序列化结果类型 + * @author looly + * @since 6.0.0 + */ +public interface MatcherJSONDeserializer extends JSONDeserializer { + + /** + * 匹配反序列化器是否匹配 + * + * @param json JSON对象 + * @param deserializeType 反序列化类型 + * @return 是否匹配 + */ + boolean match(JSON json, Type deserializeType); +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONPrimitiveSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java similarity index 56% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONPrimitiveSerializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java index d172dd7f6..cc735353a 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONPrimitiveSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn + * Copyright (c) 2024 Hutool Team and hutool.cn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,23 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; - -import org.dromara.hutool.json.JSONPrimitive; +package org.dromara.hutool.json.serializer; /** - * 原始对象的序列化接口,用于将特定对象序列化为{@link JSONPrimitive} + * 匹配JSON序列化器,用于判断是否匹配,匹配则执行序列化 * - * @param 对象类型 + * @param JSON对象类型 * @author Looly + * @since 6.0.0 */ -@FunctionalInterface -public interface JSONPrimitiveSerializer extends JSONSerializer { +public interface MatcherJSONSerializer extends JSONSerializer { + + /** + * 判断是否匹配 + * + * @param bean 对象 + * @param context JSON上下文 + * @return 是否匹配 + */ + boolean match(V bean, JSONContext context); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java new file mode 100644 index 000000000..f0f140c72 --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.json.serializer; + +import org.dromara.hutool.core.collection.set.ConcurrentHashSet; +import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; +import org.dromara.hutool.core.reflect.ConstructorUtil; +import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.json.serializer.impl.TemporalAccessorSerializer; +import org.dromara.hutool.json.serializer.impl.TimeZoneSerializer; + +import java.lang.reflect.Type; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; + +/** + * JSON序列化和反序列化管理器,用于管理JSON序列化器,注册和注销自定义序列化器和反序列化器。 + * + * @author looly + * @since 6.0.0 + */ +public class SerializerManager { + /** + * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 + */ + private static class SingletonHolder { + /** + * 静态初始化器,由JVM来保证线程安全 + */ + private static final SerializerManager INSTANCE = new SerializerManager(); + static { + registerDefault(); + } + } + + /** + * 获得单例的 SerializerManager + * + * @return SerializerManager + */ + public static SerializerManager getInstance() { + return SerializerManager.SingletonHolder.INSTANCE; + } + + /** + * 用户自定义序列化器,存储自定义匹配规则的一类对象的转换器 + */ + private volatile Set> serializerSet; + /** + * 用户自定义精确类型转换器
+ * 主要存储类型明确(无子类)的转换器 + */ + private volatile Map> serializerMap; + /** + * 用户自定义类型转换器,存储自定义匹配规则的一类对象的转换器 + */ + private volatile Set> deserializerSet; + /** + * 用户自定义精确类型转换器
+ * 主要存储类型明确(无子类)的转换器 + */ + private volatile Map> deserializerMap; + + /** + * 构造 + */ + public SerializerManager() { + } + + // region ----- register + + /** + * 注册自定义序列化器,用于自定义对象序列化
+ * 当按照匹配规则匹配时,使用对应的序列化器进行序列化 + * + * @param serializer 自定义序列化器 + * @return this + */ + public SerializerManager register(final MatcherJSONSerializer serializer) { + if (null != serializer) { + getSerializerSet().add(serializer); + } + return this; + } + + /** + * 注册自定义序列化器,用于自定义对象序列化
+ * 当类型精准匹配时,使用对应的序列化器进行序列化 + * + * @param type 类型 + * @param serializer 自定义序列化器,{@code null}表示移除 + * @return this + */ + public SerializerManager register(final Type type, final JSONSerializer serializer) { + Assert.notNull(type); + if (null == serializer) { + getSerializerMap().remove(type); + } else { + getSerializerMap().put(type, serializer); + } + return this; + } + + /** + * 注册自定义反序列化器,用于自定义对象反序列化
+ * 当按照匹配规则匹配时,使用对应的反序列化器进行反序列化 + * + * @param deserializer 自定义反序列化器 + * @return this + */ + public SerializerManager register(final MatcherJSONDeserializer deserializer) { + if (null != deserializer) { + getDeserializerSet().add(deserializer); + } + return this; + } + + /** + * 注册自定义反序列化器,用于自定义对象反序列化
+ * 当类型精准匹配时,使用对应的反序列化器进行反序列化 + * + * @param type 类型,{@code null}表示 + * @param deserializer 自定义反序列化器,{@code null}表示移除 + * @return this + */ + public SerializerManager register(final Type type, final JSONDeserializer deserializer) { + Assert.notNull(type); + if (null == deserializer) { + getDeserializerMap().remove(type); + } else { + getDeserializerMap().put(type, deserializer); + } + return this; + } + // endregion + + // region ----- getSerializer or Deserializer + + /** + * 获取匹配器对应的序列化器 + * + * @param bean 对象 + * @return JSONSerializer + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public JSONSerializer getSerializer(final Object bean) { + for (final MatcherJSONSerializer serializer : this.serializerSet) { + if (serializer.match(bean, null)) { + return serializer; + } + } + return null; + } + + /** + * 获取匹配器对应的序列化器 + * + * @param type 类型 + * @return JSONSerializer + */ + @SuppressWarnings("unchecked") + public JSONSerializer getSerializer(final Type type) { + if(null == type){ + return null; + } + return (JSONSerializer) getSerializerMap().get(type); + } + + /** + * 获取匹配器对应的反序列化器 + * + * @param type 类型 + * @return JSONDeserializer + */ + @SuppressWarnings("unchecked") + public JSONDeserializer getDeserializer(final Type type) { + final Class rawType = TypeUtil.getClass(type); + if(null == rawType){ + return null; + } + if (JSONDeserializer.class.isAssignableFrom(rawType)) { + return (JSONDeserializer) ConstructorUtil.newInstanceIfPossible(rawType); + } + + return (JSONDeserializer) getDeserializerMap().get(type); + } + // endregion + + // region ----- getSet or Map + private Set> getSerializerSet() { + if (null == this.serializerSet) { + synchronized (this) { + if (null == this.serializerSet) { + this.serializerSet = new ConcurrentHashSet<>(); + } + } + } + return this.serializerSet; + } + + private Map> getSerializerMap() { + if (null == this.serializerMap) { + synchronized (this) { + if (null == this.serializerMap) { + this.serializerMap = new SafeConcurrentHashMap<>(); + } + } + } + return this.serializerMap; + } + + private Set> getDeserializerSet() { + if (null == this.deserializerSet) { + synchronized (this) { + if (null == this.deserializerSet) { + this.deserializerSet = new ConcurrentHashSet<>(); + } + } + } + return this.deserializerSet; + } + + private Map> getDeserializerMap() { + if (null == this.deserializerMap) { + synchronized (this) { + if (null == this.deserializerMap) { + this.deserializerMap = new SafeConcurrentHashMap<>(); + } + } + } + return this.deserializerMap; + } + + /** + * 注册默认的序列化器和反序列化器 + */ + private static void registerDefault() { + SingletonHolder.INSTANCE.register(LocalDate.class, (JSONSerializer) new TemporalAccessorSerializer(LocalDate.class)); + SingletonHolder.INSTANCE.register(LocalDate.class, (JSONDeserializer) new TemporalAccessorSerializer(LocalDate.class)); + + SingletonHolder.INSTANCE.register(LocalTime.class, (JSONSerializer) new TemporalAccessorSerializer(LocalTime.class)); + SingletonHolder.INSTANCE.register(LocalTime.class, (JSONDeserializer) new TemporalAccessorSerializer(LocalTime.class)); + + SingletonHolder.INSTANCE.register(LocalDateTime.class, (JSONSerializer) new TemporalAccessorSerializer(LocalDateTime.class)); + SingletonHolder.INSTANCE.register(LocalDateTime.class, (JSONDeserializer) new TemporalAccessorSerializer(LocalDateTime.class)); + + SingletonHolder.INSTANCE.register((MatcherJSONSerializer) TimeZoneSerializer.INSTANCE); + SingletonHolder.INSTANCE.register((MatcherJSONDeserializer) TimeZoneSerializer.INSTANCE); + } + // endregion +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/TemporalAccessorSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalAccessorSerializer.java similarity index 84% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/TemporalAccessorSerializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalAccessorSerializer.java index 0ac7131be..c403dd483 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/TemporalAccessorSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalAccessorSerializer.java @@ -14,14 +14,18 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.math.NumberUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.serializer.JSONContext; +import org.dromara.hutool.json.serializer.JSONDeserializer; +import org.dromara.hutool.json.serializer.JSONSerializer; +import java.lang.reflect.Type; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -39,7 +43,7 @@ import java.time.temporal.TemporalAccessor; * @author looly * @since 5.7.22 */ -public class TemporalAccessorSerializer implements JSONSerializer, JSONDeserializer { +public class TemporalAccessorSerializer implements JSONSerializer, JSONDeserializer { private static final String YEAR_KEY = "year"; private static final String MONTH_KEY = "month"; @@ -61,7 +65,14 @@ public class TemporalAccessorSerializer implements JSONSerializer, MatcherJSONDeserializer { + + /** + * 单例 + */ + public static final TimeZoneSerializer INSTANCE = new TimeZoneSerializer(); + + @Override + public boolean match(final JSON json, final Type deserializeType) { + return TimeZone.class.isAssignableFrom(TypeUtil.getClass(deserializeType)); + } + + @SuppressWarnings("DataFlowIssue") + @Override + public boolean match(final TimeZone bean, final JSONContext context) { + return bean instanceof TimeZone; + } + + @Override + public JSON serialize(final TimeZone bean, final JSONContext context) { + return new JSONPrimitive(bean.getID()); + } + + @Override + public TimeZone deserialize(final JSON json, final Type deserializeType) { + return TimeZone.getTimeZone(json.toString()); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONObjectSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/package-info.java similarity index 62% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONObjectSerializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/package-info.java index d0690fb03..c41af8da6 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/JSONObjectSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn + * Copyright (c) 2024 Hutool Team and hutool.cn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,9 @@ * limitations under the License. */ -package org.dromara.hutool.json.serialize; - -import org.dromara.hutool.json.JSONObject; - /** - * 对象的序列化接口,用于将特定对象序列化为{@link JSONObject} - * @param 对象类型 + * 默认实现的序列化和反序列化 * * @author Looly */ -@FunctionalInterface -public interface JSONObjectSerializer extends JSONSerializer{} +package org.dromara.hutool.json.serializer.impl; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/package-info.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/package-info.java similarity index 96% rename from hutool-json/src/main/java/org/dromara/hutool/json/serialize/package-info.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/package-info.java index 32578d2dd..0ee71e92b 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serialize/package-info.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/package-info.java @@ -28,4 +28,4 @@ *
  • 反序列化(Deserialize)指:【JSON对象】 转换为 【Java对象】
  • * */ -package org.dromara.hutool.json.serialize; +package org.dromara.hutool.json.serializer; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java index 83acc9a8d..90bf4ba12 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONStringValueWriter.java @@ -17,7 +17,7 @@ package org.dromara.hutool.json.writer; import org.dromara.hutool.json.JSONException; -import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.serializer.JSONStringer; /** * {@link JSONStringer}的值写出器 diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java index fcb4934b2..72dd22856 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java @@ -16,8 +16,10 @@ package org.dromara.hutool.json; -import org.dromara.hutool.json.serialize.JSONObjectSerializer; import lombok.ToString; +import org.dromara.hutool.json.serializer.JSONDeserializer; +import org.dromara.hutool.json.serializer.JSONSerializer; +import org.dromara.hutool.json.serializer.SerializerManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,8 +29,10 @@ import java.util.Date; public class CustomSerializeTest { @BeforeEach - public void init(){ - JSONUtil.putSerializer(CustomBean.class, (JSONObjectSerializer) (json, bean) -> json.set("customName", bean.name)); + public void init() { + SerializerManager.getInstance().register(CustomBean.class, + (JSONSerializer) (bean, context) -> + ((JSONObject)context.getContextJson()).set("customName", bean.name)); } @Test @@ -51,9 +55,9 @@ public class CustomSerializeTest { @Test public void deserializeTest() { - JSONUtil.putDeserializer(CustomBean.class, json -> { + SerializerManager.getInstance().register(CustomBean.class, (JSONDeserializer) (json, deserializeType) -> { final CustomBean customBean = new CustomBean(); - customBean.name = ((JSONObject)json).getStr("customName"); + customBean.name = ((JSONObject) json).getStr("customName"); return customBean; }); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java index 52c35abf4..fa1cf077f 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java @@ -16,17 +16,21 @@ package org.dromara.hutool.json; -import org.dromara.hutool.json.serialize.JSONDeserializer; -import org.dromara.hutool.json.serialize.JSONObjectSerializer; import lombok.Data; +import org.dromara.hutool.json.serializer.JSONContext; +import org.dromara.hutool.json.serializer.JSONDeserializer; +import org.dromara.hutool.json.serializer.JSONSerializer; +import org.dromara.hutool.json.serializer.SerializerManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.lang.reflect.Type; + public class Issue2555Test { @Test public void serAndDeserTest(){ - JSONUtil.putSerializer(MyType.class, new MySerializer()); - JSONUtil.putDeserializer(MyType.class, new MyDeserializer()); + SerializerManager.getInstance().register(MyType.class, new MySerializer()); + SerializerManager.getInstance().register(MyType.class, new MyDeserializer()); final SimpleObj simpleObj = new SimpleObj(); final MyType child = new MyType(); @@ -50,16 +54,16 @@ public class Issue2555Test { private MyType myType; } - public static class MySerializer implements JSONObjectSerializer { + public static class MySerializer implements JSONSerializer { @Override - public void serialize(final JSONObject json, final MyType bean) { - json.set("addr", bean.getAddress()); + public JSON serialize(final MyType bean, final JSONContext context) { + return ((JSONObject)context.getContextJson()).set("addr", bean.getAddress()); } } public static class MyDeserializer implements JSONDeserializer { @Override - public MyType deserialize(final JSON json) { + public MyType deserialize(final JSON json, final Type deserializeType) { final MyType myType = new MyType(); myType.setAddress(((JSONObject)json).getStr("addr")); return myType; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java index 14a1b8653..160736f1f 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java @@ -18,7 +18,9 @@ package org.dromara.hutool.json; import lombok.Data; import org.dromara.hutool.core.collection.ListUtil; -import org.dromara.hutool.json.serialize.JSONObjectSerializer; +import org.dromara.hutool.json.serializer.JSONContext; +import org.dromara.hutool.json.serializer.JSONSerializer; +import org.dromara.hutool.json.serializer.SerializerManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -31,7 +33,7 @@ public class Issue3086Test { @Test public void serializeTest() { - JSONUtil.putSerializer(TestBean.class, new TestBean()); + SerializerManager.getInstance().register(TestBean.class, new TestBean()); final List strings = ListUtil.of( new SimpleGrantedAuthority("ROLE_admin"), @@ -61,14 +63,19 @@ public class Issue3086Test { } @Data - static class TestBean implements JSONObjectSerializer { + static class TestBean implements JSONSerializer { private Collection authorities = new ArrayList<>(); @Override - public void serialize(final JSONObject json, final TestBean testBean) { - final List strings = testBean.getAuthorities() + public JSON serialize(final TestBean bean, final JSONContext context) { + final List strings = bean.getAuthorities() .stream().map(SimpleGrantedAuthority::getAuthority).collect(Collectors.toList()); - json.set("authorities",strings); + JSONObject contextJson = (JSONObject) context.getContextJson(); + if(null == contextJson){ + contextJson = new JSONObject(context.config()); + } + contextJson.set("authorities",strings); + return contextJson; } } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI7M2GZTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI7M2GZTest.java index 0d541d7be..0663145cd 100755 --- a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI7M2GZTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI7M2GZTest.java @@ -19,10 +19,11 @@ package org.dromara.hutool.json; import lombok.AllArgsConstructor; import lombok.Data; import org.dromara.hutool.core.reflect.TypeReference; -import org.dromara.hutool.json.serialize.JSONDeserializer; +import org.dromara.hutool.json.serializer.JSONDeserializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -38,7 +39,7 @@ public class IssueI7M2GZTest { private Integer parsed; @Override - public JSONBeanParserImpl deserialize(final JSON json) { + public JSONBeanParserImpl deserialize(final JSON json, final Type deserializeType) { setName("new Object"); setParsed(12); return this; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssuesI44E4HTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssuesI44E4HTest.java index c2652f42e..2fd49c7d9 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/IssuesI44E4HTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssuesI44E4HTest.java @@ -16,11 +16,11 @@ package org.dromara.hutool.json; -import org.dromara.hutool.json.serialize.GlobalSerializeMapping; -import org.dromara.hutool.json.serialize.JSONDeserializer; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import org.dromara.hutool.json.serializer.JSONDeserializer; +import org.dromara.hutool.json.serializer.SerializerManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -31,7 +31,7 @@ public class IssuesI44E4HTest { @Test public void deserializerTest(){ - GlobalSerializeMapping.putDeserializer(TestDto.class, (JSONDeserializer) json -> { + SerializerManager.getInstance().register(TestDto.class, (JSONDeserializer) (json, deserializeType) -> { final TestDto testDto = new TestDto(); testDto.setMd(new AcBizModuleMd("name1", ((JSONObject)json).getStr("md"))); return testDto; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java index 8fc0ed91b..226a2cc64 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java @@ -16,6 +16,7 @@ package org.dromara.hutool.json; +import lombok.Data; import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.io.file.FileUtil; @@ -25,7 +26,6 @@ import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.json.test.bean.Exam; import org.dromara.hutool.json.test.bean.JsonNode; import org.dromara.hutool.json.test.bean.KeyBean; -import lombok.Data; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -34,6 +34,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * JSONArray单元测试 * @@ -47,19 +50,19 @@ public class JSONArrayTest { final JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(jsonObject, JSONConfig.of()); - Assertions.assertEquals(new JSONArray(), jsonArray); + assertEquals(new JSONArray(), jsonArray); jsonObject.set("key1", "value1"); jsonArray = new JSONArray(jsonObject, JSONConfig.of()); - Assertions.assertEquals(1, jsonArray.size()); - Assertions.assertEquals("[{\"key1\":\"value1\"}]", jsonArray.toString()); + assertEquals(1, jsonArray.size()); + assertEquals("[{\"key1\":\"value1\"}]", jsonArray.toString()); } @Test public void addNullTest() { final List aaa = ListUtil.view("aaa", null); final String jsonStr = JSONUtil.toJsonStr(JSONUtil.parse(aaa, JSONConfig.of().setIgnoreNullValue(false))); - Assertions.assertEquals("[\"aaa\",null]", jsonStr); + assertEquals("[\"aaa\",null]", jsonStr); } @Test @@ -72,14 +75,14 @@ public class JSONArrayTest { array.add("value2"); array.add("value3"); - Assertions.assertEquals(array.get(0), "value1"); + assertEquals(array.get(0), "value1"); } @Test public void parseTest() { final String jsonStr = "[\"value1\", \"value2\", \"value3\"]"; final JSONArray array = JSONUtil.parseArray(jsonStr); - Assertions.assertEquals(array.get(0), "value1"); + assertEquals(array.get(0), "value1"); } @Test @@ -90,7 +93,7 @@ public class JSONArrayTest { // 不忽略null,则null的键值对被保留 jsonArray = JSONUtil.parseArray(jsonStr, JSONConfig.of().setIgnoreNullValue(false)); - Assertions.assertTrue(jsonArray.getJSONObject(1).containsKey("result")); + assertTrue(jsonArray.getJSONObject(1).containsKey("result")); } @Test @@ -99,7 +102,7 @@ public class JSONArrayTest { final JSONObject obj0 = array.getJSONObject(0); final Exam exam = JSONUtil.toBean(obj0, Exam.class); - Assertions.assertEquals("0", exam.getAnswerArray()[0].getSeq()); + assertEquals("0", exam.getAnswerArray()[0].getSeq()); } @Test @@ -114,8 +117,8 @@ public class JSONArrayTest { final ArrayList list = ListUtil.of(b1, b2); final JSONArray jsonArray = JSONUtil.parseArray(list); - Assertions.assertEquals("aValue1", jsonArray.getJSONObject(0).getStr("akey")); - Assertions.assertEquals("bValue2", jsonArray.getJSONObject(1).getStr("bkey")); + assertEquals("aValue1", jsonArray.getJSONObject(0).getStr("akey")); + assertEquals("bValue2", jsonArray.getJSONObject(1).getStr("bkey")); } @Test @@ -138,11 +141,11 @@ public class JSONArrayTest { Assertions.assertFalse(userList.isEmpty()); Assertions.assertSame(User.class, userList.get(0).getClass()); - Assertions.assertEquals(Integer.valueOf(111), userList.get(0).getId()); - Assertions.assertEquals(Integer.valueOf(112), userList.get(1).getId()); + assertEquals(Integer.valueOf(111), userList.get(0).getId()); + assertEquals(Integer.valueOf(112), userList.get(1).getId()); - Assertions.assertEquals("test1", userList.get(0).getName()); - Assertions.assertEquals("test2", userList.get(1).getName()); + assertEquals("test1", userList.get(0).getName()); + assertEquals("test2", userList.get(1).getName()); } @Test @@ -156,11 +159,11 @@ public class JSONArrayTest { Assertions.assertFalse(list.isEmpty()); Assertions.assertSame(Dict.class, list.get(0).getClass()); - Assertions.assertEquals(Integer.valueOf(111), list.get(0).getInt("id")); - Assertions.assertEquals(Integer.valueOf(112), list.get(1).getInt("id")); + assertEquals(Integer.valueOf(111), list.get(0).getInt("id")); + assertEquals(Integer.valueOf(112), list.get(1).getInt("id")); - Assertions.assertEquals("test1", list.get(0).getStr("name")); - Assertions.assertEquals("test2", list.get(1).getStr("name")); + assertEquals("test1", list.get(0).getStr("name")); + assertEquals("test2", list.get(1).getStr("name")); } @Test @@ -184,8 +187,8 @@ public class JSONArrayTest { final List list = ja.toList(KeyBean.class); Assertions.assertNull(list.get(0)); - Assertions.assertEquals("avalue", list.get(1).getAkey()); - Assertions.assertEquals("bvalue", list.get(1).getBkey()); + assertEquals("avalue", list.get(1).getAkey()); + assertEquals("bvalue", list.get(1).getBkey()); } @Test @@ -209,28 +212,28 @@ public class JSONArrayTest { final JSONArray jsonArray = JSONUtil.parseArray(mapList); final List nodeList = jsonArray.toList(JsonNode.class); - Assertions.assertEquals(Long.valueOf(0L), nodeList.get(0).getId()); - Assertions.assertEquals(Long.valueOf(1L), nodeList.get(1).getId()); - Assertions.assertEquals(Long.valueOf(0L), nodeList.get(2).getId()); - Assertions.assertEquals(Long.valueOf(0L), nodeList.get(3).getId()); + assertEquals(Long.valueOf(0L), nodeList.get(0).getId()); + assertEquals(Long.valueOf(1L), nodeList.get(1).getId()); + assertEquals(Long.valueOf(0L), nodeList.get(2).getId()); + assertEquals(Long.valueOf(0L), nodeList.get(3).getId()); - Assertions.assertEquals(Integer.valueOf(0), nodeList.get(0).getParentId()); - Assertions.assertEquals(Integer.valueOf(1), nodeList.get(1).getParentId()); - Assertions.assertEquals(Integer.valueOf(0), nodeList.get(2).getParentId()); - Assertions.assertEquals(Integer.valueOf(0), nodeList.get(3).getParentId()); + assertEquals(Integer.valueOf(0), nodeList.get(0).getParentId()); + assertEquals(Integer.valueOf(1), nodeList.get(1).getParentId()); + assertEquals(Integer.valueOf(0), nodeList.get(2).getParentId()); + assertEquals(Integer.valueOf(0), nodeList.get(3).getParentId()); - Assertions.assertEquals("0", nodeList.get(0).getName()); - Assertions.assertEquals("1", nodeList.get(1).getName()); - Assertions.assertEquals("+0", nodeList.get(2).getName()); - Assertions.assertEquals("-0", nodeList.get(3).getName()); + assertEquals("0", nodeList.get(0).getName()); + assertEquals("1", nodeList.get(1).getName()); + assertEquals("+0", nodeList.get(2).getName()); + assertEquals("-0", nodeList.get(3).getName()); } @Test public void getByPathTest() { final String jsonStr = "[{\"id\": \"1\",\"name\": \"a\"},{\"id\": \"2\",\"name\": \"b\"}]"; final JSONArray jsonArray = JSONUtil.parseArray(jsonStr); - Assertions.assertEquals("b", jsonArray.getByPath("[1].name")); - Assertions.assertEquals("b", JSONUtil.getByPath(jsonArray, "[1].name")); + assertEquals("b", jsonArray.getByPath("[1].name")); + assertEquals("b", JSONUtil.getByPath(jsonArray, "[1].name")); } @Test @@ -238,12 +241,12 @@ public class JSONArrayTest { JSONArray jsonArray = new JSONArray(); jsonArray.set(3, "test"); // 默认忽略null值,因此空位无值,只有一个值 - Assertions.assertEquals(1, jsonArray.size()); + assertEquals(1, jsonArray.size()); jsonArray = new JSONArray(JSONConfig.of().setIgnoreNullValue(false)); jsonArray.set(2, "test"); // 第三个位置插入值,0~2都是null - Assertions.assertEquals(3, jsonArray.size()); + assertEquals(3, jsonArray.size()); } // https://github.com/dromara/hutool/issues/1858 @@ -251,8 +254,8 @@ public class JSONArrayTest { public void putTest2() { final JSONArray jsonArray = new JSONArray(); jsonArray.put(0, 1); - Assertions.assertEquals(1, jsonArray.size()); - Assertions.assertEquals(1, jsonArray.get(0)); + assertEquals(1, jsonArray.size()); + assertEquals(1, jsonArray.get(0)); } private static Map buildMap(final String id, final String parentId, final String name) { @@ -278,7 +281,7 @@ public class JSONArrayTest { .set(true); final String s = json1.toJSONString(0, (pair) -> pair.getValue().equals("value2")); - Assertions.assertEquals("[\"value2\"]", s); + assertEquals("[\"value2\"]", s); } @Test @@ -290,7 +293,7 @@ public class JSONArrayTest { .set(true); final String s = json1.toJSONString(0, (pair) -> !pair.getValue().equals("value2")); - Assertions.assertEquals("[\"value1\",\"value3\",true]", s); + assertEquals("[\"value1\",\"value3\",true]", s); } @Test @@ -298,7 +301,7 @@ public class JSONArrayTest { final JSONArray array = JSONUtil.ofArray(JSONConfig.of().setIgnoreNullValue(false)); array.set(null); - Assertions.assertEquals("[null]", array.toString()); + assertEquals("[null]", array.toString()); } @Test @@ -306,8 +309,8 @@ public class JSONArrayTest { final String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONArray array = new JSONArray(jsonArr, null, (mutable) -> mutable.get().toString().contains("111")); - Assertions.assertEquals(1, array.size()); - Assertions.assertTrue(array.getJSONObject(0).containsKey("id")); + assertEquals(1, array.size()); + assertTrue(array.getJSONObject(0).containsKey("id")); } @Test @@ -322,8 +325,20 @@ public class JSONArrayTest { mutable.set(o); return true; }); - Assertions.assertEquals(2, array.size()); - Assertions.assertTrue(array.getJSONObject(0).containsKey("id")); - Assertions.assertEquals("test1_edit", array.getJSONObject(0).get("name")); + assertEquals(2, array.size()); + assertTrue(array.getJSONObject(0).containsKey("id")); + assertEquals("test1_edit", array.getJSONObject(0).get("name")); + } + + @Test + void jsonIterTest() { + final JSONArray array = JSONUtil.ofArray(); + array.add(JSONUtil.ofObj().set("name", "aaa")); + array.add(JSONUtil.ofObj().set("name", "bbb")); + array.add(JSONUtil.ofObj().set("name", "ccc")); + + StringBuilder result = new StringBuilder(); + array.jsonIter(JSONObject.class).forEach(result::append); + assertEquals("{\"name\":\"aaa\"}{\"name\":\"bbb\"}{\"name\":\"ccc\"}", result.toString()); } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONDeserializerTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONDeserializerTest.java index 78429e274..7b7b87bb4 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONDeserializerTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONDeserializerTest.java @@ -16,11 +16,13 @@ package org.dromara.hutool.json; -import org.dromara.hutool.json.serialize.JSONDeserializer; import lombok.Data; +import org.dromara.hutool.json.serializer.JSONDeserializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.lang.reflect.Type; + public class JSONDeserializerTest { @Test @@ -33,14 +35,14 @@ public class JSONDeserializerTest { } @Data - static class TestBean implements JSONDeserializer { + static class TestBean implements JSONDeserializer { private String name; private String address; @Override - public Object deserialize(final JSON value) { - final JSONObject valueObj = (JSONObject) value; + public TestBean deserialize(final JSON json, final Type deserializeType) { + final JSONObject valueObj = (JSONObject) json; this.name = valueObj.getStr("customName"); this.address = valueObj.getStr("customAddress"); return this; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONSupportTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONSupportTest.java deleted file mode 100644 index 09dfc978e..000000000 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONSupportTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024 Hutool Team and hutool.cn - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.dromara.hutool.json; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class JSONSupportTest { - - /** - * https://github.com/dromara/hutool/issues/1779 - * 在JSONSupport的JSONBeanParse中,如果使用json.toBean,会导致JSONBeanParse.parse方法反复递归调用,最终栈溢出
    - * 因此parse方法默认实现必须避开JSONBeanParse.parse调用。 - */ - @Test - public void parseTest() { - final String jsonstr = "{\n" + - " \"location\": \"https://hutool.cn\",\n" + - " \"message\": \"这是一条测试消息\",\n" + - " \"requestId\": \"123456789\",\n" + - " \"traceId\": \"987654321\"\n" + - "}"; - - - final TestBean testBean = JSONUtil.toBean(jsonstr, TestBean.class); - Assertions.assertEquals("https://hutool.cn", testBean.getLocation()); - Assertions.assertEquals("这是一条测试消息", testBean.getMessage()); - Assertions.assertEquals("123456789", testBean.getRequestId()); - Assertions.assertEquals("987654321", testBean.getTraceId()); - } - - @EqualsAndHashCode(callSuper = true) - @Data - static class TestBean extends JSONSupport{ - - private String location; - - private String message; - - private String requestId; - - private String traceId; - - } -} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONUtilTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONUtilTest.java index 463a12cb0..123bba377 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONUtilTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONUtilTest.java @@ -21,7 +21,7 @@ import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.date.DateUtil; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.math.NumberUtil; -import org.dromara.hutool.json.serialize.JSONStringer; +import org.dromara.hutool.json.serializer.JSONStringer; import org.dromara.hutool.json.test.bean.Price; import org.dromara.hutool.json.test.bean.UserA; import org.dromara.hutool.json.test.bean.UserC; diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineTest.java index 5602b998a..de4056eac 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineTest.java @@ -46,7 +46,6 @@ public class JSONEngineTest { @Test void writeTimeZoneTest() { - // TODO Hutool无法序列化TimeZone等特殊对象 Arrays.stream(engineNames).forEach(this::assertWriteTimeZone); }