From ff187f6fdeff6611c12a3d5635999d3cc11470e7 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 22 Sep 2024 18:15:39 +0800 Subject: [PATCH] fix code --- .../dromara/hutool/core/lang/tuple/Pair.java | 1 + .../core/reflect/ActualTypeMapperPool.java | 2 +- .../hutool/core/reflect/TypeReference.java | 8 +- .../dromara/hutool/core/reflect/TypeUtil.java | 110 +++++--- .../parser/DefaultRegexDateParserTest.java | 7 + .../java/org/dromara/hutool/json/JSON.java | 22 +- .../dromara/hutool/json/JSONPrimitive.java | 18 +- .../org/dromara/hutool/json/JSONUtil.java | 6 +- .../hutool/json/convert/JSONConverter.java | 254 ------------------ .../json/convert/JSONGetterValueProvider.java | 52 ---- .../hutool/json/engine/gson/DateSerDesc.java | 2 +- .../hutool/json/engine/gson/GsonEngine.java | 8 +- ...{GsonSerDesc.java => GsonTypeAdapter.java} | 2 +- ...Desc.java => TemporalGsonTypeAdapter.java} | 4 +- ...Desc.java => TimeZoneGsonTypeAdapter.java} | 4 +- .../hutool/json/mapper/JSONArrayMapper.java | 46 +--- .../hutool/json/mapper/JSONObjectMapper.java | 57 +--- .../json/serializer/TypeAdapterManager.java | 79 +++--- ...eserializer.java => ArrayTypeAdapter.java} | 18 +- .../impl/CharSequenceTypeAdapter.java | 88 ++++++ .../json/serializer/impl/DateTypeAdapter.java | 19 +- .../serializer/impl/DefaultDeserializer.java | 60 +---- ...eserializer.java => EntryTypeAdapter.java} | 28 +- ...Deserializer.java => IterTypeAdapter.java} | 56 +++- .../impl/JSONPrimitiveTypeAdapter.java | 82 ++++++ .../serializer/impl/KBeanDeserializer.java | 6 +- ...pDeserializer.java => MapTypeAdapter.java} | 31 ++- .../serializer/impl/PairDeserializer.java | 58 ++++ .../serializer/impl/TemporalTypeAdapter.java | 102 +++++-- .../serializer/impl/TripleDeserializer.java | 61 +++++ .../serializer/impl/TupleDeserializer.java | 42 +++ .../hutool/json/xml/JSONXMLSerializer.java | 46 ++-- .../dromara/hutool/json/xml/JSONXMLUtil.java | 19 +- .../hutool/json/CustomSerializeTest.java | 11 +- .../dromara/hutool/json/Issue2090Test.java | 22 +- .../dromara/hutool/json/Issue2447Test.java | 6 +- .../dromara/hutool/json/Issue3681Test.java | 4 +- .../dromara/hutool/json/IssueI3BS4STest.java | 4 +- .../dromara/hutool/json/JSONArrayTest.java | 4 +- .../dromara/hutool/json/JSONObjectTest.java | 31 ++- .../org/dromara/hutool/json/JSONUtilTest.java | 2 +- .../dromara/hutool/json/JSONWriterTest.java | 2 +- .../org/dromara/hutool/json/jwt/JWTTest.java | 2 +- .../org/dromara/hutool/json/xml/XMLTest.java | 9 +- 44 files changed, 831 insertions(+), 664 deletions(-) delete mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java delete mode 100755 hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java rename hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/{GsonSerDesc.java => GsonTypeAdapter.java} (91%) rename hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/{TemporalSerDesc.java => TemporalGsonTypeAdapter.java} (90%) rename hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/{TimeZoneSerDesc.java => TimeZoneGsonTypeAdapter.java} (88%) rename hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/{ArrayDeserializer.java => ArrayTypeAdapter.java} (78%) create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java rename hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/{EntryDeserializer.java => EntryTypeAdapter.java} (71%) rename hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/{CollectionDeserializer.java => IterTypeAdapter.java} (59%) create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java rename hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/{MapDeserializer.java => MapTypeAdapter.java} (63%) create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/PairDeserializer.java create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TripleDeserializer.java create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TupleDeserializer.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/tuple/Pair.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/tuple/Pair.java index 3d2d95350..4ac2996af 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/lang/tuple/Pair.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/tuple/Pair.java @@ -96,6 +96,7 @@ public class Pair implements Serializable, Cloneable { if (o == null || getClass() != o.getClass()) { return false; } + final Pair pair = (Pair) o; return Objects.equals(left, pair.left) && Objects.equals(right, pair.right); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java index 3beb51f6f..cd1c8fde8 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ActualTypeMapperPool.java @@ -92,7 +92,7 @@ public class ActualTypeMapperPool { } /** - * 创建类中所有的泛型变量和泛型实际类型的对应关系Map + * 创建类中所有的泛型变量和泛型实际类型的对应关系Map
* * @param type 被解析的包含泛型参数的类 * @return 泛型对应关系Map diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeReference.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeReference.java index cecc047fd..2b5c056f8 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeReference.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeReference.java @@ -22,10 +22,10 @@ import java.lang.reflect.Type; * Type类型参考
* 通过构建一个类型参考子类,可以获取其泛型参数中的Type类型。例如: * - *
- * TypeReference<List<String>> list = new TypeReference<List<String>>() {};
- * Type t = tr.getType();
- * 
+ *
{@code
+ *   TypeReference> list = new TypeReference>() {};
+ *   Type t = tr.getType();
+ * }
* * 此类无法应用于通配符泛型参数(wildcard parameters),比如:{@code Class} 或者 {@code List? extends CharSequence>} * diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java index e7cf82c12..0b87b9f7b 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/TypeUtil.java @@ -45,29 +45,32 @@ public class TypeUtil { * @return 原始类,如果无法获取原始类,返回{@code null} */ public static Class getClass(final Type type) { - if (null != type) { - if (type instanceof Class) { - return (Class) type; - } else if (type instanceof ParameterizedType) { - return (Class) ((ParameterizedType) type).getRawType(); - } else if (type instanceof TypeVariable) { - //return (Class) ((TypeVariable) type).getBounds()[0]; - final Type[] bounds = ((TypeVariable) type).getBounds(); - if (bounds.length == 1) { - return getClass(bounds[0]); - } - } else if (type instanceof WildcardType) { - final Type[] upperBounds = ((WildcardType) type).getUpperBounds(); - if (upperBounds.length == 1) { - return getClass(upperBounds[0]); - } - } else if(type instanceof GenericArrayType){ - return Array.newInstance(getClass(((GenericArrayType)type).getGenericComponentType()), 0).getClass(); - } else if(type instanceof TypeReference){ - return getClass(((TypeReference)type).getType()); - } + if (null == type) { + return null; } - return null; + + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + return (Class) ((ParameterizedType) type).getRawType(); + } else if (type instanceof TypeVariable) { + //return (Class) ((TypeVariable) type).getBounds()[0]; + final Type[] bounds = ((TypeVariable) type).getBounds(); + if (bounds.length == 1) { + return getClass(bounds[0]); + } + } else if (type instanceof WildcardType) { + final Type[] upperBounds = ((WildcardType) type).getUpperBounds(); + if (upperBounds.length == 1) { + return getClass(upperBounds[0]); + } + } else if (type instanceof GenericArrayType) { + return Array.newInstance(getClass(((GenericArrayType) type).getGenericComponentType()), 0).getClass(); + } else if (type instanceof TypeReference) { + return getClass(((TypeReference) type).getType()); + } + + throw new IllegalArgumentException("Unsupported Type: " + type.getClass().getName()); } /** @@ -107,7 +110,7 @@ public class TypeUtil { return null == field ? null : field.getType(); } - // ----------------------------------------------------------------------------------- Param Type + // region ----- Param Type /** * 获取方法的第一个参数类型
@@ -190,8 +193,9 @@ public class TypeUtil { public static Class[] getParamClasses(final Method method) { return null == method ? null : method.getParameterTypes(); } + // endregion - // ----------------------------------------------------------------------------------- Return Type + // region ----- Return Type /** * 获取方法的返回值类型
@@ -218,8 +222,9 @@ public class TypeUtil { public static Class getReturnClass(final Method method) { return null == method ? null : method.getReturnType(); } + // endregion - // ----------------------------------------------------------------------------------- Type Argument + // region ----- Type Argument /** * 获得给定类的第一个泛型参数 @@ -267,6 +272,7 @@ public class TypeUtil { final ParameterizedType parameterizedType = toParameterizedType(type); return (null == parameterizedType) ? null : parameterizedType.getActualTypeArguments(); } + // endregion /** * 将{@link Type} 转换为{@link ParameterizedType}
@@ -347,7 +353,7 @@ public class TypeUtil { if (ArrayUtil.isNotEmpty(genericInterfaces)) { for (final Type genericInterface : genericInterfaces) { final ParameterizedType parameterizedType = toParameterizedType(genericInterface); - if(null != parameterizedType){ + if (null != parameterizedType) { result.add(parameterizedType); } } @@ -383,20 +389,7 @@ public class TypeUtil { return false; } - /** - * 获取泛型变量和泛型实际类型的对应关系Map,例如: - * - *
-	 *     T    org.dromara.hutool.test.User
-	 *     E    java.lang.Integer
-	 * 
- * - * @param clazz 被解析的包含泛型参数的类 - * @return 泛型对应关系Map - */ - public static Map getTypeMap(final Class clazz) { - return ActualTypeMapperPool.get(clazz); - } + // region ----- Actual type /** * 获得泛型字段对应的泛型实际类型,如果此变量没有对应的实际类型,返回null @@ -417,7 +410,7 @@ public class TypeUtil { * 此方法可以处理: * *
-	 *     1. 泛型化对象,类似于Map<User, Key<Long>>
+	 *     1. 泛型化对象,类似于{@code Map>}
 	 *     2. 泛型变量,类似于T
 	 * 
* @@ -431,17 +424,30 @@ public class TypeUtil { } if (typeVariable instanceof TypeVariable) { - // TODO TypeReference无效 - return ActualTypeMapperPool.getActualType(type, (TypeVariable) typeVariable); + return getActualType(type, (TypeVariable) typeVariable); } // 没有需要替换的泛型变量,原样输出 return typeVariable; } + /** + * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回typeVariable + * + * @param type 类 + * @param typeVariable 泛型变量 + * @return 实际类型,可能为Class等 + */ + public static Type getActualType(final Type type, final TypeVariable typeVariable) { + return ObjUtil.defaultIfNull(ActualTypeMapperPool.getActualType(type, typeVariable), typeVariable); + } + /** * 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null - * 此方法可以处理复杂的泛型化对象,类似于Map<User, Key<Long>> + * 此方法可以处理复杂的泛型化对象,类似于: + *
{@code
+	 *   Map>
+	 * }
* * @param type 类 * @param parameterizedType 泛型变量,例如List<T>等 @@ -473,4 +479,20 @@ public class TypeUtil { public static Type[] getActualTypes(final Type type, final Type... typeVariables) { return ActualTypeMapperPool.getActualTypes(type, typeVariables); } + + /** + * 获取泛型变量和泛型实际类型的对应关系Map,例如: + * + *
+	 *     T    org.dromara.hutool.test.User
+	 *     E    java.lang.Integer
+	 * 
+ * + * @param clazz 被解析的包含泛型参数的类 + * @return 泛型对应关系Map + */ + public static Map getTypeMap(final Class clazz) { + return ActualTypeMapperPool.get(clazz); + } + // endregion } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/DefaultRegexDateParserTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/DefaultRegexDateParserTest.java index 1604f9914..aa8a8995d 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/DefaultRegexDateParserTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/DefaultRegexDateParserTest.java @@ -28,6 +28,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; */ public class DefaultRegexDateParserTest { + @Test + void parseYearMonthDaySplitByDashedWithTTest() { + assertParse("2021-03-17 06:31:33", "2021-03-17T06:31:33"); + assertParse("2021-03-17 06:31:33", "2021-03-17T06:31:33.999"); + assertParse("2021-03-17 06:31:33", "2021-03-17T06:31:33.9999"); + } + @Test void parseYearMonthDaySplitByDashedTest() { assertParse("2013-02-03 00:00:00", "2013-Feb-03"); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java index f4c8949bd..19af217c4 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java @@ -18,6 +18,7 @@ package org.dromara.hutool.json; import org.dromara.hutool.core.bean.path.BeanPath; import org.dromara.hutool.core.lang.mutable.MutableEntry; +import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.serializer.JSONDeserializer; import org.dromara.hutool.json.serializer.TypeAdapterManager; import org.dromara.hutool.json.writer.JSONWriter; @@ -231,10 +232,29 @@ public interface JSON extends Serializable { */ @SuppressWarnings("unchecked") default T toBean(final Type type) { + if(null == type || Object.class == type){ + if(this instanceof JSONPrimitive){ + return (T) ((JSONPrimitive) this).getValue(); + } + return (T) this; + } + final JSONDeserializer deserializer = TypeAdapterManager.getInstance().getDeserializer(this, type); + final boolean ignoreError = ObjUtil.defaultIfNull(config(), JSONConfig::isIgnoreError, false); if(null == deserializer){ + if(ignoreError){ + return null; + } throw new JSONException("No deserializer for type: " + type); } - return (T) deserializer.deserialize(this, type); + + try{ + return (T) deserializer.deserialize(this, type); + } catch (final Exception e){ + if(ignoreError){ + return null; + } + throw e; + } } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java index 924115f4d..24c1e3296 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java @@ -19,6 +19,7 @@ package org.dromara.hutool.json; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.wrapper.Wrapper; import org.dromara.hutool.core.math.NumberUtil; +import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.json.writer.JSONWriter; import org.dromara.hutool.json.writer.NumberWriteMode; @@ -51,7 +52,22 @@ public class JSONPrimitive implements Wrapper, JSON { * @return 是否为JSONPrimitive类型 */ public static boolean isTypeForJSONPrimitive(final Object value) { - return value instanceof Boolean || value instanceof Number || value instanceof String; + return value instanceof Boolean + || value instanceof Number + || value instanceof Character + || value instanceof String; + } + + /** + * 判断给定类是否可以转为JSONPrimitive类型 + * + * @param type 值 + * @return 是否为JSONPrimitive类型 + */ + public static boolean isTypeForJSONPrimitive(final Class type) { + return ClassUtil.isBasicType(type) + || Number.class.isAssignableFrom(type) + || String.class == type; } private Object value; 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 088c2fa3c..5a3c45f6d 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 @@ -27,6 +27,7 @@ import org.dromara.hutool.json.mapper.JSONValueMapper; import org.dromara.hutool.json.writer.JSONWriter; import org.dromara.hutool.json.xml.JSONXMLUtil; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.Writer; import java.lang.reflect.Type; @@ -118,7 +119,10 @@ public class JSONUtil { * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留 * @return JSONObject */ - public static JSONObject parseObj(final Object obj, final JSONConfig config, final Predicate> predicate) { + public static JSONObject parseObj(Object obj, final JSONConfig config, final Predicate> predicate) { + if(obj instanceof byte[]){ + obj = new ByteArrayInputStream((byte[]) obj); + } return (JSONObject) parse(obj, config, predicate); } 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 deleted file mode 100644 index 30441b34e..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ /dev/null @@ -1,254 +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.convert; - -import org.dromara.hutool.core.bean.BeanUtil; -import org.dromara.hutool.core.bean.copier.BeanCopier; -import org.dromara.hutool.core.convert.*; -import org.dromara.hutool.core.convert.impl.DateConverter; -import org.dromara.hutool.core.convert.impl.TemporalAccessorConverter; -import org.dromara.hutool.core.reflect.ConstructorUtil; -import org.dromara.hutool.core.reflect.TypeReference; -import org.dromara.hutool.core.reflect.TypeUtil; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.core.util.ObjUtil; -import org.dromara.hutool.json.*; -import org.dromara.hutool.json.mapper.JSONValueMapper; -import org.dromara.hutool.json.reader.JSONParser; -import org.dromara.hutool.json.reader.JSONTokener; -import org.dromara.hutool.json.serializer.JSONDeserializer; -import org.dromara.hutool.json.serializer.TypeAdapterManager; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.time.temporal.TemporalAccessor; -import java.util.Date; - -/** - * JSON转换器,实现Object对象转换为{@link JSON},支持的对象: - *
    - *
  • 任意支持的对象,转换为JSON
  • - *
  • JSON转换为指定对象Bean
  • - *
- * - * @author looly - * @since 6.0.0 - */ -public class JSONConverter implements Converter, Serializable { - private static final long serialVersionUID = 1L; - - /** - * 单例 - */ - public static final JSONConverter INSTANCE = new JSONConverter(null); - - /** - * 创建JSON转换器 - * - * @param config JSON配置 - * @return JSONConverter - */ - public static JSONConverter of(final JSONConfig config) { - final JSONConverter jsonConverter = new JSONConverter(config); - jsonConverter.registerConverter = new RegisterConverter(jsonConverter) - .register(JSONObject.class, INSTANCE) - .register(JSONArray.class, INSTANCE) - .register(JSONPrimitive.class, INSTANCE); - jsonConverter.specialConverter = new SpecialConverter(jsonConverter); - return jsonConverter; - } - - private final JSONConfig config; - private RegisterConverter registerConverter; - private SpecialConverter specialConverter; - - /** - * 构造 - * - * @param config JSON配置 - */ - private JSONConverter(final JSONConfig config) { - this.config = config; - } - - @Override - public Object convert(Type targetType, final Object value) throws ConvertException { - if (null == value) { - return null; - } - - // JSON转对象 - if (value instanceof JSON) { - if (targetType instanceof TypeReference) { - // 还原原始类型 - targetType = ((TypeReference) targetType).getType(); - } - return toBean(targetType, (JSON) value); - } - - // 对象转JSON - final Class targetClass = TypeUtil.getClass(targetType); - if (null != targetClass) { - if (JSON.class.isAssignableFrom(targetClass)) { - return toJSON(value); - } - // 自定义日期格式 - if (Date.class.isAssignableFrom(targetClass) || TemporalAccessor.class.isAssignableFrom(targetClass)) { - final Object date = toDateWithFormat(targetClass, value); - if (null != date) { - return date; - } - } - } - - return ConvertUtil.convertWithCheck(targetType, value, null, config.isIgnoreError()); - } - - /** - * 实现Object对象转换为JSON对象,根据RFC8259规范,支持的对象: - *
    - *
  • String: 转换为相应的对象,"和'包围的字符串返回原字符串,""返回{@code null}
  • - *
  • Array、Iterable、Iterator:转换为JSONArray
  • - *
  • Bean对象:转为JSONObject
  • - *
  • Number、Boolean:返回原对象
  • - *
  • null:返回{@code null}
  • - *
- * - * @param obj 被转换的对象 - * @return 转换后的对象 - * @throws JSONException 转换异常 - */ - public JSON toJSON(final Object obj) throws JSONException { - if (null == obj) { - return null; - } - - return JSONValueMapper.of(config, null).map(obj); - } - - /** - * 实现{@link CharSequence}转换为JSON对象,根据RFC8259规范
- * 转换为相应的对象,"和'包围的字符串返回原字符串,""返回{@code null} - * - * @param str 被转换的字符串 - * @return 转换后的对象 - * @throws JSONException 转换异常 - */ - public JSON toJSON(final CharSequence str) throws JSONException { - if (null == str) { - return null; - } - - final String jsonStr = StrUtil.trim(str); - if (jsonStr.isEmpty()) { - // https://www.rfc-editor.org/rfc/rfc8259#section-7 - // 未被包装的空串理解为null - return null; - } - - // RFC8259,JSON字符串值、number, boolean, or null - final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), config); - return jsonParser.parse(); - } - - // ----------------------------------------------------------- Private method start - - /** - * JSON转Bean,流程为: - *
{@code
-	 *     自定义反序列化 --> 尝试转Kotlin --> 基于注册的标准转换器 --> Collection、Map等含有泛型的特殊转换器 --> 普通Bean转换器
-	 * }
- * - * @param 目标类型 - * @param targetType 目标类型, - * @param json JSON - * @return bean - */ - @SuppressWarnings("unchecked") - private T toBean(final Type targetType, final JSON json) { - // 自定义对象反序列化 - final JSONDeserializer deserializer = TypeAdapterManager.getInstance().getDeserializer(json, targetType); - if (null != deserializer) { - return (T) deserializer.deserialize(json, targetType); - } - - // 当目标类型不确定时,返回原JSON - final Class rawType = (Class) TypeUtil.getClass(targetType); - if (null == rawType || JSON.class.isAssignableFrom(rawType)) { - return (T) json; - //throw new JSONException("Can not get class from type: {}", targetType); - } - - final Object value; - // JSON原始类型 - if (json instanceof JSONPrimitive) { - value = ((JSONPrimitive) json).getValue(); - } else { - value = json; - } - - final JSONConfig config = ObjUtil.defaultIfNull(json.config(), JSONConfig::of); - final boolean ignoreError = config.isIgnoreError(); - try { - // 标准转换器 - final Converter converter = registerConverter.getConverter(targetType, value, true); - if (null != converter) { - return (T) converter.convert(targetType, value); - } - - // 特殊类型转换,包括Collection、Map、强转、Array等 - final T result = (T) specialConverter.convert(targetType, rawType, value); - if (null != result) { - return result; - } - } catch (final ConvertException e) { - if (ignoreError) { - return null; - } - } - - // 尝试转Bean - if (!(json instanceof JSONPrimitive) && BeanUtil.isWritableBean(rawType)) { - return BeanCopier.of(value, - ConstructorUtil.newInstanceIfPossible(rawType), targetType, - InternalJSONUtil.toCopyOptions(config)).copy(); - } - - // 跳过异常时返回null - if (ignoreError) { - return null; - } - - // 无法转换 - throw new JSONException("Can not convert from '{}': {} to '{}'", - json.getClass().getName(), json, targetType.getTypeName()); - } - - private Object toDateWithFormat(final Class targetDateClass, final Object value) { - // 日期转换,支持自定义日期格式 - final String format = config.getDateFormat(); - if (StrUtil.isNotBlank(format)) { - if (Date.class.isAssignableFrom(targetDateClass)) { - return new DateConverter(format).convert(targetDateClass, value); - } else { - return new TemporalAccessorConverter(format).convert(targetDateClass, value); - } - } - return null; - } - // ----------------------------------------------------------- Private method end -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java deleted file mode 100755 index a39bed858..000000000 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java +++ /dev/null @@ -1,52 +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.convert; - -import org.dromara.hutool.core.bean.copier.ValueProvider; -import org.dromara.hutool.json.JSONGetter; - -import java.lang.reflect.Type; - -/** - * JSONGetter的ValueProvider - * - * @param 键类型 - * @author looly - */ -public class JSONGetterValueProvider implements ValueProvider { - - private final JSONGetter jsonGetter; - - /** - * 构造 - * - * @param jsonGetter {@link JSONGetter} - */ - public JSONGetterValueProvider(final JSONGetter jsonGetter) { - this.jsonGetter = jsonGetter; - } - - @Override - public Object value(final K key, final Type valueType) { - return jsonGetter.get(key, valueType); - } - - @Override - public boolean containsKey(final K key) { - return !jsonGetter.isNull(key); - } -} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/DateSerDesc.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/DateSerDesc.java index b8200972a..ce638917c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/DateSerDesc.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/DateSerDesc.java @@ -30,7 +30,7 @@ import java.util.Date; * @author Looly * @since 6.0.0 */ -public class DateSerDesc implements GsonSerDesc { +public class DateSerDesc implements GsonTypeAdapter { /** * 默认日期格式化描述,默认为null,表示使用时间戳 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java index 4d8582f25..22abb820c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java @@ -116,11 +116,11 @@ public class GsonEngine extends AbstractJSONEngine implements Wrapper { private void registerDate(final GsonBuilder builder, final String dateFormat){ // java date builder.registerTypeHierarchyAdapter(Date.class, new DateSerDesc(dateFormat)); - builder.registerTypeHierarchyAdapter(TimeZone.class, TimeZoneSerDesc.INSTANCE); + builder.registerTypeHierarchyAdapter(TimeZone.class, TimeZoneGsonTypeAdapter.INSTANCE); // java.time - builder.registerTypeAdapter(LocalDateTime.class, new TemporalSerDesc(LocalDateTime.class, dateFormat)); - builder.registerTypeAdapter(LocalDate.class, new TemporalSerDesc(LocalDate.class, dateFormat)); - builder.registerTypeAdapter(LocalTime.class, new TemporalSerDesc(LocalTime.class, dateFormat)); + builder.registerTypeAdapter(LocalDateTime.class, new TemporalGsonTypeAdapter(LocalDateTime.class, dateFormat)); + builder.registerTypeAdapter(LocalDate.class, new TemporalGsonTypeAdapter(LocalDate.class, dateFormat)); + builder.registerTypeAdapter(LocalTime.class, new TemporalGsonTypeAdapter(LocalTime.class, dateFormat)); } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonSerDesc.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonTypeAdapter.java similarity index 91% rename from hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonSerDesc.java rename to hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonTypeAdapter.java index c54bd9d42..607dcf244 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonSerDesc.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonTypeAdapter.java @@ -26,5 +26,5 @@ import com.google.gson.JsonSerializer; * @author Looly * @since 6.0.0 */ -public interface GsonSerDesc extends JsonSerializer, JsonDeserializer { +public interface GsonTypeAdapter extends JsonSerializer, JsonDeserializer { } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalSerDesc.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalGsonTypeAdapter.java similarity index 90% rename from hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalSerDesc.java rename to hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalGsonTypeAdapter.java index fca4269f4..665031116 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalSerDesc.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TemporalGsonTypeAdapter.java @@ -30,7 +30,7 @@ import java.time.temporal.TemporalAccessor; * @author Looly * @since 6.0.0 */ -public class TemporalSerDesc implements GsonSerDesc { +public class TemporalGsonTypeAdapter implements GsonTypeAdapter { private final Class type; private final String dateFormat; @@ -41,7 +41,7 @@ public class TemporalSerDesc implements GsonSerDesc { * @param type 时间类型 * @param dateFormat 日期格式 */ - public TemporalSerDesc(final Class type, final String dateFormat) { + public TemporalGsonTypeAdapter(final Class type, final String dateFormat) { this.type = type; this.dateFormat = dateFormat; } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneSerDesc.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneGsonTypeAdapter.java similarity index 88% rename from hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneSerDesc.java rename to hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneGsonTypeAdapter.java index 31543a0eb..b4a3db972 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneSerDesc.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/TimeZoneGsonTypeAdapter.java @@ -27,12 +27,12 @@ import java.util.TimeZone; * @author Looly * @since 6.0.0 */ -public class TimeZoneSerDesc implements GsonSerDesc{ +public class TimeZoneGsonTypeAdapter implements GsonTypeAdapter { /** * 默认时区格式化描述 */ - public static final TimeZoneSerDesc INSTANCE = new TimeZoneSerDesc(); + public static final TimeZoneGsonTypeAdapter INSTANCE = new TimeZoneGsonTypeAdapter(); @Override public JsonElement serialize(final TimeZone src, final Type typeOfSrc, final JsonSerializationContext context) { 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 b7b5f9f4d..be429f64b 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,8 +16,6 @@ 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.MutableEntry; import org.dromara.hutool.json.JSONArray; @@ -26,7 +24,6 @@ import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONTokener; -import java.util.Iterator; import java.util.function.Predicate; /** @@ -90,50 +87,9 @@ class JSONArrayMapper { jsonArray.set(b); } } - } else { - final Iterator iter; - if (ArrayUtil.isArray(source)) {// 数组 - iter = new ArrayIter<>(source); - } else if (source instanceof Iterator) {// Iterator - iter = ((Iterator) source); - } else if (source instanceof Iterable) {// Iterable - iter = ((Iterable) source).iterator(); - } else { - if (!jsonArray.config().isIgnoreError()) { - throw new JSONException("Unsupported [{}] to JSONArray", source.getClass()); - } - // 如果用户选择跳过异常,则跳过此值转换 - return; - } - - mapFromIterator(iter, jsonArray); } - } - /** - * 从Iterator中读取数据,并添加到JSONArray中 - * - * @param iter {@link Iterator} - * @param jsonArray {@link JSONArray} - */ - private void mapFromIterator(final Iterator iter, final JSONArray jsonArray) { - Object next; - while (iter.hasNext()) { - next = iter.next(); - // 检查循环引用 - if (next != source) { - if (null != this.predicate) { - final MutableEntry entry = MutableEntry.of(jsonArray.size(), next); - if (predicate.test(entry)) { - // 使用修改后的键值对 - next = entry.getValue(); - jsonArray.set(next); - } - } else { - jsonArray.set(next); - } - } - } + throw new JSONException("Unsupported [{}] to JSONArray", source.getClass()); } /** 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 ea8153f7d..2a193fc9e 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 @@ -16,14 +16,8 @@ package org.dromara.hutool.json.mapper; -import org.dromara.hutool.core.bean.BeanUtil; -import org.dromara.hutool.core.bean.RecordUtil; -import org.dromara.hutool.core.bean.copier.CopyOptions; -import org.dromara.hutool.core.convert.ConvertUtil; import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.lang.mutable.MutableEntry; -import org.dromara.hutool.core.reflect.method.MethodUtil; -import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.json.InternalJSONUtil; import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONException; @@ -31,9 +25,7 @@ import org.dromara.hutool.json.JSONObject; import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.reader.JSONTokener; -import java.lang.reflect.Type; import java.util.Enumeration; -import java.util.Map; import java.util.ResourceBundle; import java.util.function.Predicate; @@ -81,32 +73,17 @@ class JSONObjectMapper { * * @param jsonObject 目标{@link JSONObject} */ - @SuppressWarnings("rawtypes") public void mapTo(final JSONObject jsonObject) { final Object source = this.source; if (null == source) { return; } - if (source instanceof Map) { - // Map - for (final Map.Entry e : ((Map) source).entrySet()) { - jsonObject.set(ConvertUtil.toStr(e.getKey()), e.getValue()); - } - } else if (source instanceof Map.Entry) { - final Map.Entry entry = (Map.Entry) source; - jsonObject.set(ConvertUtil.toStr(entry.getKey()), entry.getValue()); - } else if (source instanceof byte[]) { + if (source instanceof byte[]) { mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source)), jsonObject.config(), jsonObject); } else if (source instanceof ResourceBundle) { // ResourceBundle mapFromResourceBundle((ResourceBundle) source, jsonObject); - } else if (RecordUtil.isRecord(source.getClass())) { - // since 6.0.0 - mapFromRecord(source, jsonObject); - } else if (BeanUtil.isReadableBean(source.getClass())) { - // 普通Bean - mapFromBean(source, jsonObject); } else { if (!jsonObject.config().isIgnoreError()) { // 不支持对象类型转换为JSONObject @@ -142,36 +119,4 @@ class JSONObjectMapper { private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONObject jsonObject) { JSONParser.of(x, config).setPredicate(this.predicate).parseTo(jsonObject); } - - /** - * 从Record转换 - * - * @param record Record对象 - * @param jsonObject {@link JSONObject} - */ - private void mapFromRecord(final Object record, final JSONObject jsonObject) { - final Map.Entry[] components = RecordUtil.getRecordComponents(record.getClass()); - - String key; - for (final Map.Entry entry : components) { - key = entry.getKey(); - jsonObject.set(key, MethodUtil.invoke(record, key)); - } - } - - /** - * 从Bean转换 - * - * @param bean Bean对象 - * @param jsonObject {@link JSONObject} - */ - private void mapFromBean(final Object bean, final JSONObject jsonObject) { - final CopyOptions copyOptions = InternalJSONUtil.toCopyOptions(jsonObject.config()); - if (null != this.predicate) { - copyOptions.setFieldEditor((entry -> this.predicate.test( - MutableEntry.of(StrUtil.toStringOrNull(entry.getKey()), entry.getValue())) ? - entry : null)); - } - BeanUtil.beanToMap(bean, jsonObject, copyOptions); - } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/TypeAdapterManager.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/TypeAdapterManager.java index 785182636..a245e7524 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/TypeAdapterManager.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/TypeAdapterManager.java @@ -17,10 +17,11 @@ package org.dromara.hutool.json.serializer; import org.dromara.hutool.core.collection.CollUtil; -import org.dromara.hutool.core.collection.set.ConcurrentHashSet; import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.lang.tuple.Pair; +import org.dromara.hutool.core.lang.tuple.Triple; +import org.dromara.hutool.core.lang.tuple.Tuple; import org.dromara.hutool.core.map.MapUtil; -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.JSON; @@ -28,6 +29,8 @@ import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.serializer.impl.*; import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -57,11 +60,7 @@ public class TypeAdapterManager { /** * 静态初始化器,由JVM来保证线程安全 */ - private static final TypeAdapterManager INSTANCE = new TypeAdapterManager(); - - static { - registerDefault(INSTANCE); - } + private static final TypeAdapterManager INSTANCE = registerDefault(new TypeAdapterManager()); } /** @@ -79,9 +78,7 @@ public class TypeAdapterManager { * @return SerializerManager */ public static TypeAdapterManager of() { - final TypeAdapterManager typeAdapterManager = new TypeAdapterManager(); - registerDefault(typeAdapterManager); - return typeAdapterManager; + return registerDefault(new TypeAdapterManager()); } /** @@ -168,20 +165,31 @@ public class TypeAdapterManager { */ @SuppressWarnings({"unchecked"}) public JSONSerializer getSerializer(final Object bean, final Type type) { - JSONSerializer result = null; - if (null != type && MapUtil.isNotEmpty(this.serializerMap)) { - result = (JSONSerializer) this.serializerMap.get(type); + final Class rawType = TypeUtil.getClass(type); + if (null == rawType) { + return null; + } + if (JSONSerializer.class.isAssignableFrom(rawType)) { + return (JSONSerializer) ConstructorUtil.newInstanceIfPossible(rawType); } - if (null == result && CollUtil.isNotEmpty(this.serializerSet)) { + if (MapUtil.isNotEmpty(this.serializerMap)) { + final JSONSerializer result = this.serializerMap.get(rawType); + if(null != result){ + return (JSONSerializer) result; + } + } + + // Matcher + if (CollUtil.isNotEmpty(this.serializerSet)) { for (final MatcherJSONSerializer serializer : this.serializerSet) { if (serializer.match(bean, null)) { - result = (MatcherJSONSerializer) serializer; - break; + return (MatcherJSONSerializer) serializer; } } } - return result; + + throw new JSONException("No serializer for type: " + type); } /** @@ -201,8 +209,8 @@ public class TypeAdapterManager { return (JSONDeserializer) ConstructorUtil.newInstanceIfPossible(rawType); } - if (CollUtil.isNotEmpty(this.deserializerMap)) { - final JSONDeserializer jsonDeserializer = this.deserializerMap.get(type); + if (MapUtil.isNotEmpty(this.deserializerMap)) { + final JSONDeserializer jsonDeserializer = this.deserializerMap.get(rawType); if (null != jsonDeserializer) { return (JSONDeserializer) jsonDeserializer; } @@ -226,7 +234,7 @@ public class TypeAdapterManager { if (null == this.serializerSet) { synchronized (this) { if (null == this.serializerSet) { - this.serializerSet = new ConcurrentHashSet<>(); + this.serializerSet = new LinkedHashSet<>(); } } } @@ -237,7 +245,7 @@ public class TypeAdapterManager { if (null == this.serializerMap) { synchronized (this) { if (null == this.serializerMap) { - this.serializerMap = new SafeConcurrentHashMap<>(); + this.serializerMap = new HashMap<>(); } } } @@ -248,7 +256,7 @@ public class TypeAdapterManager { if (null == this.deserializerSet) { synchronized (this) { if (null == this.deserializerSet) { - this.deserializerSet = new ConcurrentHashSet<>(); + this.deserializerSet = new LinkedHashSet<>(); } } } @@ -259,7 +267,7 @@ public class TypeAdapterManager { if (null == this.deserializerMap) { synchronized (this) { if (null == this.deserializerMap) { - this.deserializerMap = new SafeConcurrentHashMap<>(); + this.deserializerMap = new HashMap<>(); } } } @@ -271,24 +279,35 @@ public class TypeAdapterManager { * 注册默认的序列化器和反序列化器 * * @param manager {@code SerializerManager} + * @return TypeAdapterManager */ - private static void registerDefault(final TypeAdapterManager manager) { - // issue#I5WDP0 对于Kotlin对象,由于参数可能非空限制,导致无法创建一个默认的对象再赋值 + private static TypeAdapterManager registerDefault(final TypeAdapterManager manager) { + + // 自定义序列化器 + + // 自定义反序列化器 manager.register(KBeanDeserializer.INSTANCE); - manager.register(CollectionDeserializer.INSTANCE); - manager.register(ArrayDeserializer.INSTANCE); - manager.register(MapDeserializer.INSTANCE); - manager.register(EntryDeserializer.INSTANCE); manager.register(RecordDeserializer.INSTANCE); + manager.register(Triple.class, TripleDeserializer.INSTANCE); + manager.register(Pair.class, PairDeserializer.INSTANCE); + manager.register(Tuple.class, TupleDeserializer.INSTANCE); - + // 自定义类型适配器 + manager.register(JSONPrimitiveTypeAdapter.INSTANCE); + manager.register(CharSequenceTypeAdapter.INSTANCE); manager.register(DateTypeAdapter.INSTANCE); manager.register(CalendarTypeAdapter.INSTANCE); manager.register(TemporalTypeAdapter.INSTANCE); manager.register(TimeZoneTypeAdapter.INSTANCE); manager.register(EnumTypeAdapter.INSTANCE); manager.register(ThrowableTypeAdapter.INSTANCE); + manager.register(EntryTypeAdapter.INSTANCE); + manager.register(MapTypeAdapter.INSTANCE); + manager.register(IterTypeAdapter.INSTANCE); + manager.register(ArrayTypeAdapter.INSTANCE); // 最低优先级 manager.register(BeanTypeAdapter.INSTANCE); + + return manager; } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java similarity index 78% rename from hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayDeserializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java index 94a8292eb..50f7df5ec 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java @@ -16,11 +16,15 @@ package org.dromara.hutool.json.serializer.impl; +import org.dromara.hutool.core.array.ArrayUtil; +import org.dromara.hutool.core.collection.iter.ArrayIter; import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; import java.lang.reflect.Array; import java.lang.reflect.Type; @@ -32,12 +36,17 @@ import java.util.Map; * @author looly * @since 6.0.0 */ -public class ArrayDeserializer implements MatcherJSONDeserializer { +public class ArrayTypeAdapter implements MatcherJSONSerializer, MatcherJSONDeserializer { /** * 单例 */ - public static final ArrayDeserializer INSTANCE = new ArrayDeserializer(); + public static final ArrayTypeAdapter INSTANCE = new ArrayTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return ArrayUtil.isArray(bean); + } @Override public boolean match(final JSON json, final Type deserializeType) { @@ -47,6 +56,11 @@ public class ArrayDeserializer implements MatcherJSONDeserializer { return false; } + @Override + public JSON serialize(final Object bean, final JSONContext context) { + return IterTypeAdapter.INSTANCE.serialize(new ArrayIter<>(bean), context); + } + @Override public Object deserialize(final JSON json, final Type deserializeType) { final int size = json.size(); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java new file mode 100644 index 000000000..a27933238 --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java @@ -0,0 +1,88 @@ +/* + * 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.impl; + +import org.dromara.hutool.core.reflect.TypeUtil; +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.serializer.JSONContext; +import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; +import org.dromara.hutool.json.xml.JSONXMLParser; +import org.dromara.hutool.json.xml.ParseConfig; + +import java.lang.reflect.Type; + +/** + * CharSequence类型适配器,用于处理未匹配的JSON类型。 + * + * @author looly + * @since 6.0.0 + */ +public class CharSequenceTypeAdapter implements MatcherJSONSerializer, MatcherJSONDeserializer { + + /** + * 单例 + */ + public static final CharSequenceTypeAdapter INSTANCE = new CharSequenceTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return bean instanceof CharSequence; + } + + @Override + public boolean match(final JSON json, final Type deserializeType) { + return CharSequence.class.isAssignableFrom(TypeUtil.getClass(deserializeType)); + } + + @Override + public JSON serialize(final CharSequence bean, final JSONContext context) { + final String jsonStr = StrUtil.trim(bean); + if (StrUtil.startWith(jsonStr, '<')) { + // 可能为XML + JSONObject jsonObject = (JSONObject) context.getContextJson(); + if(null == jsonObject){ + jsonObject = JSONUtil.ofObj(context.config()); + } + JSONXMLParser.of(ParseConfig.of(), null).parseJSONObject(jsonStr, jsonObject); + return jsonObject; + } + + return mapFromTokener(new JSONTokener(jsonStr), context.config()); + } + + @Override + public CharSequence deserialize(final JSON json, final Type deserializeType) { + if(json instanceof JSONPrimitive){ + return ((JSONPrimitive) json).getValue().toString(); + } + return json.toString(); + } + + /** + * 从{@link JSONTokener} 中读取JSON字符串,并转换为JSON + * + * @param tokener {@link JSONTokener} + * @return JSON + */ + private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) { + return JSONParser.of(tokener, config).setPredicate(null).parse(); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DateTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DateTypeAdapter.java index 94afaf0fd..de4a28417 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DateTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DateTypeAdapter.java @@ -18,6 +18,7 @@ package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.convert.impl.DateConverter; import org.dromara.hutool.core.date.DateUtil; +import org.dromara.hutool.core.date.format.GlobalCustomFormat; import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.JSON; @@ -55,12 +56,20 @@ public class DateTypeAdapter implements MatcherJSONSerializer, MatcherJSON @Override public JSON serialize(final Date bean, final JSONContext context) { - final JSONConfig config = ObjUtil.apply(context, JSONContext::config); + final JSONConfig config = context.config(); final String format = ObjUtil.apply(config, JSONConfig::getDateFormat); - return new JSONPrimitive( - null == format - ? bean.getTime() - : DateUtil.format(bean, format), config); + + final Object value; + // 默认为时间戳 + if(null == format || GlobalCustomFormat.FORMAT_MILLISECONDS.equals(format)){ + value = bean.getTime(); + } else if(GlobalCustomFormat.FORMAT_SECONDS.equals(format)){ + value = Math.floorDiv(bean.getTime(), 1000L); + } else { + value = DateUtil.format(bean, format); + } + + return new JSONPrimitive(value, config); } @Override diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DefaultDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DefaultDeserializer.java index 3b62d485b..c860e9b37 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DefaultDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/DefaultDeserializer.java @@ -16,7 +16,6 @@ package org.dromara.hutool.json.serializer.impl; -import org.dromara.hutool.core.convert.CompositeConverter; import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.json.*; import org.dromara.hutool.json.serializer.JSONDeserializer; @@ -40,58 +39,21 @@ public class DefaultDeserializer implements JSONDeserializer { public Object deserialize(final JSON json, final Type deserializeType) { // 当目标类型不确定时,返回原JSON final Class rawType = TypeUtil.getClass(deserializeType); - if (null == rawType || rawType == json.getClass()) { + if (null == rawType || Object.class == rawType || rawType == json.getClass()) { return json; } - if (json instanceof JSONObject) { - return fromJSONObject((JSONObject) json, deserializeType, rawType); - } else if (json instanceof JSONArray) { - return fromJSONArray((JSONArray) json, deserializeType, rawType); - } else if (json instanceof JSONPrimitive) { - return fromJSONPrimitive((JSONPrimitive) json, deserializeType, rawType); - } - throw new JSONException("Unsupported JSON type: {}", json.getClass()); - } - - /** - * 从JSONObject反序列化 - * - * @param json JSONObject - * @param deserializeType 目标类型 - * @param rawType 目标类型 - * @return 反序列化后的对象 - */ - private Object fromJSONObject(final JSONObject json, final Type deserializeType, final Class rawType) { - throw new JSONException("Unsupported JSONObject to {}", rawType); - } - - /** - * 从JSONArray反序列化 - * - * @param json JSONArray - * @param deserializeType 目标类型 - * @param rawType 目标类型 - * @return 反序列化后的对象 - */ - private Object fromJSONArray(final JSONArray json, final Type deserializeType, final Class rawType) { - throw new JSONException("Unsupported JSONArray to {}", rawType); - } - - /** - * 从JSONPrimitive反序列化 - * - * @param json JSONPrimitive - * @param deserializeType 目标类型 - * @param rawType 目标类型 - * @return 反序列化后的对象 - */ - private Object fromJSONPrimitive(final JSONPrimitive json, final Type deserializeType, final Class rawType) { - final Object value = json.getValue(); - if (null != value && rawType.isAssignableFrom(value.getClass())) { - return value; + // JSON类型之间互转 + if(json instanceof JSONPrimitive && JSON.class.isAssignableFrom(rawType)){ + final Object value = json.asJSONPrimitive().getValue(); + if(value instanceof CharSequence){ + // JSON字符串转JSON + return JSONUtil.parse(value, json.config()); + } + } else if(json instanceof JSONObject && JSONArray.class == rawType){ + return JSONUtil.parseArray(json, json.config()); } - return CompositeConverter.getInstance().convert(deserializeType, value); + throw new JSONException("Unsupported type {} to {}", json.getClass(), deserializeType.getTypeName()); } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryTypeAdapter.java similarity index 71% rename from hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryDeserializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryTypeAdapter.java index 9631c4823..989a222d4 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/EntryTypeAdapter.java @@ -17,27 +17,36 @@ package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.convert.CompositeConverter; +import org.dromara.hutool.core.convert.ConvertUtil; import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.JSONUtil; +import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; import java.lang.reflect.Type; import java.util.Map; /** - * Map.Entry反序列化器,用于将JSON对象转换为Map.Entry对象。 + * Map.Entry序列化和反序列化器,用于将JSON对象和Map.Entry对象互转。 * * @author looly * @since 6.0.0 */ -public class EntryDeserializer implements MatcherJSONDeserializer> { +public class EntryTypeAdapter implements MatcherJSONSerializer>, MatcherJSONDeserializer> { /** * 单例 */ - public static final EntryDeserializer INSTANCE = new EntryDeserializer(); + public static final EntryTypeAdapter INSTANCE = new EntryTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return bean instanceof Map.Entry; + } @Override public boolean match(final JSON json, final Type deserializeType) { @@ -48,6 +57,19 @@ public class EntryDeserializer implements MatcherJSONDeserializer bean, final JSONContext context) { + final JSONObject result; + final JSON contextJson = context.getContextJson(); + if(contextJson instanceof JSONObject){ + result = contextJson.asJSONObject(); + }else{ + result = JSONUtil.ofObj(context.config()); + } + result.set(ConvertUtil.toStr(bean.getKey()), bean.getValue()); + return result; + } + @Override public Map.Entry deserialize(final JSON json, final Type deserializeType) { final Type keyType = TypeUtil.getTypeArgument(deserializeType, 0); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CollectionDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java similarity index 59% rename from hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CollectionDeserializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java index a7395a42c..67c1b8add 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CollectionDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java @@ -18,39 +18,66 @@ package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.JSONUtil; +import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; import java.lang.reflect.Type; import java.util.Collection; +import java.util.Iterator; import java.util.Map; /** - * 集合类型反序列化器 + * Iterator序列化器,将{@link Iterable}或{@link Iterator}转换为JSONArray * - * @author looly - * @since 6.0.0 + * @author Looly */ -public class CollectionDeserializer implements MatcherJSONDeserializer> { +public class IterTypeAdapter implements MatcherJSONSerializer, MatcherJSONDeserializer { /** * 单例 */ - public static final CollectionDeserializer INSTANCE = new CollectionDeserializer(); + public static final IterTypeAdapter INSTANCE = new IterTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return bean instanceof Iterable || bean instanceof Iterator; + } @Override public boolean match(final JSON json, final Type deserializeType) { if (json instanceof JSONArray || json instanceof JSONObject) { final Class rawType = TypeUtil.getClass(deserializeType); + // 反序列化只支持到集合 return Collection.class.isAssignableFrom(rawType); } return false; } @Override - public Collection deserialize(final JSON json, final Type deserializeType) { + public JSON serialize(final Object bean, final JSONContext context) { + final Iterator iter; + if (bean instanceof Iterator) {// Iterator + iter = ((Iterator) bean); + } else {// Iterable + iter = ((Iterable) bean).iterator(); + } + + JSONArray json = (JSONArray) context.getContextJson(); + if(null == json){ + json = JSONUtil.ofArray(ObjUtil.apply(context, JSONContext::config)); + } + mapFromIterator(bean, iter, json); + return json; + } + + @Override + public Object deserialize(final JSON json, final Type deserializeType) { final Class rawType = TypeUtil.getClass(deserializeType); final Type elementType = TypeUtil.getTypeArgument(deserializeType); final Collection result = CollUtil.create(rawType, TypeUtil.getClass(elementType)); @@ -65,6 +92,23 @@ public class CollectionDeserializer implements MatcherJSONDeserializer iter, final JSONArray jsonArray) { + Object next; + while (iter.hasNext()) { + next = iter.next(); + // 检查循环引用 + if (next != source) { + jsonArray.set(next); + } + } + } + /** * 将JSONObject转换为集合 * diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java new file mode 100644 index 000000000..8cede6aac --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java @@ -0,0 +1,82 @@ +/* + * 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.impl; + +import org.dromara.hutool.core.convert.ConvertUtil; +import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.util.ObjUtil; +import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.JSONConfig; +import org.dromara.hutool.json.JSONPrimitive; +import org.dromara.hutool.json.serializer.JSONContext; +import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; + +import java.lang.reflect.Type; + +/** + * {@link JSONPrimitive}相关类型适配器,用于处理数字类型的序列化和反序列化 + * + * @author Looly + * @since 6.0.0 + */ +public class JSONPrimitiveTypeAdapter implements MatcherJSONSerializer, MatcherJSONDeserializer { + + /** + * 单例 + */ + public static final JSONPrimitiveTypeAdapter INSTANCE = new JSONPrimitiveTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return JSONPrimitive.isTypeForJSONPrimitive(bean); + } + + @Override + public boolean match(final JSON json, final Type deserializeType) { + return json instanceof JSONPrimitive && JSONPrimitive.isTypeForJSONPrimitive(TypeUtil.getClass(deserializeType)); + } + + @Override + public JSON serialize(Object bean, final JSONContext context) { + if(bean instanceof Character){ + // 字符按照字符串存储 + bean = bean.toString(); + } + + final JSONPrimitive json = (JSONPrimitive) context.getContextJson(); + if (null != json) { + json.setValue(bean); + return json; + } + + return new JSONPrimitive(bean, context.config()); + } + + @Override + public Object deserialize(final JSON json, final Type deserializeType) { + final Object value = json.asJSONPrimitive().getValue(); + + + if (null != value && TypeUtil.getClass(deserializeType).isAssignableFrom(value.getClass())) { + return value; + } + + return ConvertUtil.convertWithCheck(deserializeType, value, null, + ObjUtil.apply(json.config(), JSONConfig::isIgnoreError)); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KBeanDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KBeanDeserializer.java index 6e865d126..c1774ca92 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KBeanDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KBeanDeserializer.java @@ -20,7 +20,8 @@ import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONGetter; -import org.dromara.hutool.json.convert.JSONGetterValueProvider; +import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.convert.JSONObjectValueProvider; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; import java.lang.reflect.Type; @@ -46,10 +47,9 @@ public class KBeanDeserializer implements MatcherJSONDeserializer { && KClassUtil.isKotlinClass(rawType); } - @SuppressWarnings("unchecked") @Override public Object deserialize(final JSON json, final Type deserializeType) { final Class rawType = TypeUtil.getClass(deserializeType); - return KClassUtil.newInstance(rawType, new JSONGetterValueProvider<>((JSONGetter) json)); + return KClassUtil.newInstance(rawType, new JSONObjectValueProvider((JSONObject) json)); } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java similarity index 63% rename from hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapDeserializer.java rename to hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java index b828fd853..9f4a0975f 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java @@ -17,28 +17,38 @@ package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.convert.CompositeConverter; +import org.dromara.hutool.core.convert.ConvertUtil; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.JSONUtil; +import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; +import org.dromara.hutool.json.serializer.MatcherJSONSerializer; import java.lang.reflect.Type; import java.util.LinkedHashMap; import java.util.Map; /** - * Map反序列化器,用于将JSON对象转换为Map对象。 + * Map类型适配器器,用于将JSON对象和Map对象互转。 * * @author looly * @since 6.0.0 */ -public class MapDeserializer implements MatcherJSONDeserializer> { +public class MapTypeAdapter implements MatcherJSONSerializer>, MatcherJSONDeserializer> { /** * 单例 */ - public static final MapDeserializer INSTANCE = new MapDeserializer(); + public static final MapTypeAdapter INSTANCE = new MapTypeAdapter(); + + @Override + public boolean match(final Object bean, final JSONContext context) { + return bean instanceof Map; + } @Override public boolean match(final JSON json, final Type deserializeType) { @@ -49,6 +59,19 @@ public class MapDeserializer implements MatcherJSONDeserializer> { return false; } + @Override + public JSON serialize(final Map bean, final JSONContext context) { + final JSON contextJson = context.getContextJson(); + final JSONObject result = contextJson instanceof JSONObject ? + (JSONObject) contextJson : JSONUtil.ofObj(context.config()); + + // 注入键值对 + for (final Map.Entry e : bean.entrySet()) { + result.set(ConvertUtil.toStr(e.getKey()), e.getValue()); + } + return result; + } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Map deserialize(final JSON json, final Type deserializeType) { @@ -60,7 +83,7 @@ public class MapDeserializer implements MatcherJSONDeserializer> { map.put( // key类型为String转目标类型,使用标准转换器 CompositeConverter.getInstance().convert(keyType, entry.getKey()), - entry.getValue().toBean(valueType) + ObjUtil.apply(entry.getValue(), (value)-> value.toBean(valueType)) ); } return map; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/PairDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/PairDeserializer.java new file mode 100644 index 000000000..c88dae95e --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/PairDeserializer.java @@ -0,0 +1,58 @@ +/* + * 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.impl; + +import org.dromara.hutool.core.lang.tuple.Pair; +import org.dromara.hutool.core.reflect.TypeReference; +import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.serializer.JSONDeserializer; + +import java.lang.reflect.Type; + +/** + * 二元组反序列化器 + * + * @author Looly + * @since 6.0.0 + */ +public class PairDeserializer implements JSONDeserializer> { + + /** + * 单例 + */ + public static final PairDeserializer INSTANCE = new PairDeserializer(); + + @Override + public Pair deserialize(final JSON json, Type deserializeType) { + if (deserializeType instanceof TypeReference) { + deserializeType = ((TypeReference) deserializeType).getType(); + } + final Type leftType = TypeUtil.getTypeArgument(deserializeType, 0); + final Type rightType = TypeUtil.getTypeArgument(deserializeType, 2); + + final JSONObject jsonObject = json.asJSONObject(); + final JSON left = jsonObject.get("left"); + final JSON right = jsonObject.get("right"); + + return Pair.of( + left.toBean(leftType), + right.toBean(rightType) + ); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalTypeAdapter.java index f2902bc6b..b21f29006 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TemporalTypeAdapter.java @@ -17,20 +17,20 @@ package org.dromara.hutool.json.serializer.impl; import org.dromara.hutool.core.convert.impl.TemporalAccessorConverter; +import org.dromara.hutool.core.date.TimeUtil; +import org.dromara.hutool.core.date.format.GlobalCustomFormat; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Opt; import org.dromara.hutool.core.math.NumberUtil; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.*; import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; import org.dromara.hutool.json.serializer.MatcherJSONSerializer; import java.lang.reflect.Type; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Month; +import java.time.*; import java.time.temporal.TemporalAccessor; /** @@ -70,13 +70,70 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer temporalAccessorClass = TypeUtil.getClass(deserializeType); + if (json instanceof JSONObject) { + return fromJSONObject(temporalAccessorClass, json.asJSONObject()); + } + + if (Month.class.equals(temporalAccessorClass)) { + return Month.of((Integer) json.asJSONPrimitive().getValue()); + } else if (DayOfWeek.class.equals(temporalAccessorClass)) { + return DayOfWeek.of((Integer) json.asJSONPrimitive().getValue()); + } else if (MonthDay.class.equals(temporalAccessorClass)) { + return MonthDay.parse((CharSequence) json.asJSONPrimitive().getValue()); + } + + throw new JSONException("Unsupported type from JSON {} to {}", json, deserializeType); + } + + /** + * 将{@link TemporalAccessor}转换为JSONObject + * + * @param bean {@link TemporalAccessor} + * @param json JSONObject + */ + private static void toJSONObject(final TemporalAccessor bean, final JSONObject json) { if (bean instanceof LocalDate) { final LocalDate localDate = (LocalDate) bean; json.set(YEAR_KEY, localDate.getYear()); @@ -97,27 +154,18 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer temporalAccessorClass = TypeUtil.getClass(deserializeType); - // JSONObject - final JSONObject jsonObject = (JSONObject) json; + /** + * 从JSONObject中获取时间信息,转换为{@link TemporalAccessor} + * + * @param temporalAccessorClass 目标时间类型 + * @param jsonObject JSONObject + * @return {@link TemporalAccessor} + */ + private static TemporalAccessor fromJSONObject(final Class temporalAccessorClass, final JSONObject jsonObject) { if (LocalDate.class.equals(temporalAccessorClass) || LocalDateTime.class.equals(temporalAccessorClass)) { // 年 final Integer year = jsonObject.getInt(YEAR_KEY); @@ -160,6 +208,6 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer> { + + /** + * 单例 + */ + public static final TripleDeserializer INSTANCE = new TripleDeserializer(); + + @Override + public Triple deserialize(final JSON json, Type deserializeType) { + if (deserializeType instanceof TypeReference) { + deserializeType = ((TypeReference) deserializeType).getType(); + } + final Type leftType = TypeUtil.getTypeArgument(deserializeType, 0); + final Type middileType = TypeUtil.getTypeArgument(deserializeType, 1); + final Type rightType = TypeUtil.getTypeArgument(deserializeType, 2); + + final JSONObject jsonObject = json.asJSONObject(); + final JSON left = jsonObject.get("left"); + final JSON middle = jsonObject.get("middle"); + final JSON right = jsonObject.get("right"); + + return Triple.of( + left.toBean(leftType), + middle.toBean(middileType), + right.toBean(rightType) + ); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TupleDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TupleDeserializer.java new file mode 100644 index 000000000..dc626b0fd --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TupleDeserializer.java @@ -0,0 +1,42 @@ +/* + * 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.impl; + +import org.dromara.hutool.core.lang.tuple.Tuple; +import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.serializer.JSONDeserializer; + +import java.lang.reflect.Type; + +/** + * 多元组Tuple反序列化器 + * + * @author Looly + * @since 6.0.0 + */ +public class TupleDeserializer implements JSONDeserializer { + + /** + * 单例 + */ + public static final TupleDeserializer INSTANCE = new TupleDeserializer(); + + @Override + public Tuple deserialize(final JSON json, final Type deserializeType) { + return Tuple.of(json.toBean(Object[].class)); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLSerializer.java index 12fae5abc..c0a59a928 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLSerializer.java @@ -20,10 +20,10 @@ import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.escape.EscapeUtil; +import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.JSONObject; -import org.dromara.hutool.json.JSONUtil; /** * JSON转XML字符串工具 @@ -36,65 +36,61 @@ public class JSONXMLSerializer { * 转换JSONObject为XML * Convert a JSONObject into a well-formed, element-normal XML string. * - * @param object A JSONObject. + * @param json A JSONObject. * @return A string. * @throws JSONException Thrown if there is an error parsing the string */ - public static String toXml(final Object object) throws JSONException { - return toXml(object, null); + public static String toXml(final JSON json) throws JSONException { + return toXml(json, null); } /** * 转换JSONObject为XML * - * @param object JSON对象或数组 + * @param json JSON对象或数组 * @param tagName 可选标签名称,名称为空时忽略标签 * @return A string. * @throws JSONException JSON解析异常 */ - public static String toXml(final Object object, final String tagName) throws JSONException { - return toXml(object, tagName, "content"); + public static String toXml(final JSON json, final String tagName) throws JSONException { + return toXml(json, tagName, "content"); } /** * 转换JSONObject为XML * - * @param object JSON对象或数组 + * @param json JSON对象或数组 * @param tagName 可选标签名称,名称为空时忽略标签 * @param contentKeys 标识为内容的key,遇到此key直接解析内容而不增加对应名称标签 * @return A string. * @throws JSONException JSON解析异常 */ - public static String toXml(Object object, final String tagName, final String... contentKeys) throws JSONException { - if (null == object) { + public static String toXml(JSON json, final String tagName, final String... contentKeys) throws JSONException { + if (null == json) { return null; } final StringBuilder sb = new StringBuilder(); - if (object instanceof JSONObject) { + if (json instanceof JSONObject) { // Emit appendTag(sb, tagName, false); // Loop thru the keys. - ((JSONObject) object).forEach((key, value) -> { - if (ArrayUtil.isArray(value)) { - value = JSONUtil.parseArray(value); - } - + json.asJSONObject().forEach((key, value) -> { // Emit content in body if (ArrayUtil.contains(contentKeys, key)) { if (value instanceof JSONArray) { int i = 0; - for (final Object val : (JSONArray) value) { + for (final JSON val : (JSONArray) value) { if (i > 0) { sb.append(CharUtil.LF); } - sb.append(EscapeUtil.escapeXml(val.toString())); + sb.append(EscapeUtil.escapeXml(val.toBean(String.class))); i++; } } else { - sb.append(EscapeUtil.escapeXml(value.toString())); + sb.append(EscapeUtil.escapeXml(value.toBean(String.class))); } // Emit an array of similar keys @@ -102,7 +98,7 @@ public class JSONXMLSerializer { } else if (StrUtil.isEmptyIfStr(value)) { sb.append(wrapWithTag(null, key)); } else if (value instanceof JSONArray) { - for (final Object val : (JSONArray) value) { + for (final JSON val : (JSONArray) value) { if (val instanceof JSONArray) { sb.append(wrapWithTag(toXml(val, null, contentKeys), key)); } else { @@ -119,12 +115,8 @@ public class JSONXMLSerializer { return sb.toString(); } - if (ArrayUtil.isArray(object)) { - object = JSONUtil.parseArray(object); - } - - if (object instanceof JSONArray) { - for (final Object val : (JSONArray) object) { + if (json instanceof JSONArray) { + for (final JSON val : (JSONArray) json) { // XML does not have good support for arrays. If an array // appears in a place where XML is lacking, synthesize an // element. @@ -133,7 +125,7 @@ public class JSONXMLSerializer { return sb.toString(); } - return wrapWithTag(EscapeUtil.escapeXml(object.toString()), tagName); + return wrapWithTag(EscapeUtil.escapeXml(json.toBean(String.class)), tagName); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java index a532ecbb6..bd344f9ce 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java @@ -16,6 +16,7 @@ package org.dromara.hutool.json.xml; +import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.JSONObject; @@ -75,36 +76,36 @@ public class JSONXMLUtil { /** * 转换JSONObject为XML * - * @param object JSON对象或数组 + * @param json JSON对象或数组 * @return XML字符串 * @throws JSONException JSON解析异常 */ - public static String toXml(final Object object) throws JSONException { - return toXml(object, null); + public static String toXml(final JSON json) throws JSONException { + return toXml(json, null); } /** * 转换JSONObject为XML * - * @param object JSON对象或数组 + * @param json JSON对象或数组 * @param tagName 可选标签名称,名称为空时忽略标签 * @return A string. * @throws JSONException JSON解析异常 */ - public static String toXml(final Object object, final String tagName) throws JSONException { - return toXml(object, tagName, "content"); + public static String toXml(final JSON json, final String tagName) throws JSONException { + return toXml(json, tagName, "content"); } /** * 转换JSONObject为XML * - * @param object JSON对象或数组 + * @param json JSON对象或数组 * @param tagName 可选标签名称,名称为空时忽略标签 * @param contentKeys 标识为内容的key,遇到此key直接解析内容而不增加对应名称标签 * @return A string. * @throws JSONException JSON解析异常 */ - public static String toXml(final Object object, final String tagName, final String... contentKeys) throws JSONException { - return JSONXMLSerializer.toXml(object, tagName, contentKeys); + public static String toXml(final JSON json, final String tagName, final String... contentKeys) throws JSONException { + return JSONXMLSerializer.toXml(json, tagName, contentKeys); } } 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 9e4fc5933..c8d00a057 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 @@ -17,6 +17,7 @@ package org.dromara.hutool.json; import lombok.ToString; +import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.json.serializer.JSONDeserializer; import org.dromara.hutool.json.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.TypeAdapterManager; @@ -31,8 +32,13 @@ public class CustomSerializeTest { @BeforeEach public void init() { TypeAdapterManager.getInstance().register(CustomBean.class, - (JSONSerializer) (bean, context) -> - ((JSONObject)context.getContextJson()).set("customName", bean.name)); + (JSONSerializer) (bean, context) ->{ + JSONObject contextJson = (JSONObject) context.getContextJson(); + if(null == contextJson){ + contextJson = JSONUtil.ofObj(context.config()); + } + return contextJson.set("customName", bean.name); + }); } @Test @@ -41,6 +47,7 @@ public class CustomSerializeTest { customBean.name = "testName"; final JSONObject obj = JSONUtil.parseObj(customBean); + Console.log(obj); Assertions.assertEquals("testName", obj.getStr("customName")); } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java index f5f8d6a03..788e84a83 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2090Test.java @@ -20,10 +20,7 @@ import lombok.Data; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Month; +import java.time.*; /** * https://github.com/dromara/hutool/issues/2090 @@ -76,6 +73,23 @@ public class Issue2090Test { final JSONObject jsonObject = new JSONObject(); jsonObject.set("month", Month.JANUARY); Assertions.assertEquals("{\"month\":1}", jsonObject.toString()); + + final JSON parse = JSONUtil.parse(Month.JANUARY); + Assertions.assertInstanceOf(JSONPrimitive.class, parse); + Assertions.assertTrue(((JSONPrimitive) parse).isNumber()); + Assertions.assertEquals("1", parse.toString()); + } + + @Test + public void weekTest(){ + final JSONObject jsonObject = new JSONObject(); + jsonObject.set("week", DayOfWeek.SUNDAY); + Assertions.assertEquals("{\"week\":7}", jsonObject.toString()); + + final JSON parse = JSONUtil.parse(DayOfWeek.SUNDAY); + Assertions.assertInstanceOf(JSONPrimitive.class, parse); + Assertions.assertTrue(((JSONPrimitive) parse).isNumber()); + Assertions.assertEquals("7", parse.toString()); } @Data diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2447Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2447Test.java index f93f96495..f79828f40 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2447Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2447Test.java @@ -26,10 +26,10 @@ public class Issue2447Test { @Test public void addIntegerTest() { - Time time = new Time(); + final Time time = new Time(); time.setTime(LocalDateTime.of(1970, 1, 2, 10, 0, 1, 0)); - String timeStr = JSONUtil.toJsonStr(time); - Assertions.assertEquals(timeStr, "{\"time\":93601000}"); + final String timeStr = JSONUtil.toJsonStr(time); + Assertions.assertEquals("{\"time\":93601000}", timeStr); Assertions.assertEquals(JSONUtil.toBean(timeStr, Time.class).getTime(), time.getTime()); } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3681Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3681Test.java index 9a6adb284..3cdaa764b 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3681Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3681Test.java @@ -30,7 +30,7 @@ public class Issue3681Test { Assertions.assertEquals("\"abc\"", abc); abc = JSONUtil.toJsonStr(Optional.of("123")); - Assertions.assertEquals("123", abc); + Assertions.assertEquals("\"123\"", abc); } @Test @@ -45,6 +45,6 @@ public class Issue3681Test { Assertions.assertEquals("\"abc\"", abc); abc = JSONUtil.toJsonStr(Opt.of("123")); - Assertions.assertEquals("123", abc); + Assertions.assertEquals("\"123\"", abc); } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI3BS4STest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI3BS4STest.java index cdb6d8934..9d4a774c1 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI3BS4STest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI3BS4STest.java @@ -16,7 +16,6 @@ package org.dromara.hutool.json; -import org.dromara.hutool.core.bean.BeanUtil; import lombok.Data; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -31,8 +30,7 @@ public class IssueI3BS4STest { @Test public void toBeanTest(){ final String jsonStr = "{date: '2021-03-17T06:31:33.99'}"; - final Bean1 bean1 = new Bean1(); - BeanUtil.copyProperties(JSONUtil.parseObj(jsonStr), bean1); + final Bean1 bean1 = JSONUtil.parseObj(jsonStr).toBean(Bean1.class); Assertions.assertEquals("2021-03-17T06:31:33.990", bean1.getDate().toString()); } 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 4242eccc5..2f634dab9 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 @@ -281,7 +281,7 @@ public class JSONArrayTest { .set("value3") .set(true); - final String s = json1.toJSONString(0, (pair) -> pair.getValue().equals("value2")); + final String s = json1.toJSONString(0, (pair) -> ((JSONPrimitive)pair.getValue()).getValue().equals("value2")); assertEquals("[\"value2\"]", s); } @@ -293,7 +293,7 @@ public class JSONArrayTest { .set("value3") .set(true); - final String s = json1.toJSONString(0, (pair) -> !pair.getValue().equals("value2")); + final String s = json1.toJSONString(0, (pair) -> !((JSONPrimitive)pair.getValue()).getValue().equals("value2")); assertEquals("[\"value1\",\"value3\",true]", s); } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java index 977d19fa5..0e3eed2bd 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONObjectTest.java @@ -22,6 +22,7 @@ import org.dromara.hutool.core.annotation.PropIgnore; import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.date.DatePattern; import org.dromara.hutool.core.date.DateUtil; +import org.dromara.hutool.core.date.format.GlobalCustomFormat; import org.dromara.hutool.core.io.resource.ResourceUtil; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.text.StrUtil; @@ -113,7 +114,7 @@ public class JSONObjectTest { @Test public void parseStringTest() { final String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\", \"d\": true, \"e\": null}"; - final JSONObject jsonObject = JSONUtil.parseObj(jsonStr); + final JSONObject jsonObject = JSONUtil.parseObj(jsonStr, JSONConfig.of().setIgnoreNullValue(false)); assertEquals(jsonObject.getObj("a"), "value1"); assertEquals(jsonObject.getObj("b"), "value2"); assertEquals(jsonObject.getObj("c"), "value3"); @@ -226,6 +227,13 @@ public class JSONObjectTest { assertNull(bean.getBeanValue()); } + @Test + void addListTest(){ + final JSONObject json = JSONUtil.ofObj(); + json.set("list", ListUtil.of(1, 2, 3)); + Assertions.assertEquals("{\"list\":[1,2,3]}", json.toString()); + } + @Test public void toBeanTest2() { final UserA userA = new UserA(); @@ -245,7 +253,7 @@ public class JSONObjectTest { @Test public void toBeanWithNullTest() { final String jsonStr = "{'data':{'userName':'ak','password': null}}"; - final UserWithMap user = JSONUtil.toBean(JSONUtil.parseObj(jsonStr), UserWithMap.class); + final UserWithMap user = JSONUtil.toBean(JSONUtil.parseObj(jsonStr, JSONConfig.of().setIgnoreNullValue(false)), UserWithMap.class); Assertions.assertTrue(user.getData().containsKey("password")); } @@ -323,7 +331,7 @@ public class JSONObjectTest { } @Test - public void parseBeanTest2() { + public void parseBeanWithNumberListEnumTest() { final TestBean bean = new TestBean(); bean.setDoubleValue(111.1); bean.setIntValue(123); @@ -333,8 +341,10 @@ public class JSONObjectTest { final JSONObject json = JSONUtil.parseObj(bean, JSONConfig.of().setIgnoreNullValue(false)); - // 枚举转换检查,更新:枚举原样保存,在writer时调用toString。 - assertEquals(TestEnum.TYPE_B, json.getObj("testEnum")); + + assertEquals(111.1, json.getObj("doubleValue")); + // 枚举转换检查,默认序列化枚举为其name + assertEquals(TestEnum.TYPE_B.name(), json.getObj("testEnum")); final TestBean bean2 = json.toBean(TestBean.class); assertEquals(bean.toString(), bean2.toString()); @@ -479,9 +489,9 @@ public class JSONObjectTest { } @Test - public void setDateFormatTest3() { + public void setDateFormatSecondsTest() { // 自定义格式为只有秒的时间戳,一般用于JWT - final JSONConfig jsonConfig = JSONConfig.of().setDateFormat("#sss"); + final JSONConfig jsonConfig = JSONConfig.of().setDateFormat(GlobalCustomFormat.FORMAT_SECONDS); final Date date = DateUtil.parse("2020-06-05 11:16:11"); final JSONObject json = new JSONObject(jsonConfig); @@ -497,7 +507,7 @@ public class JSONObjectTest { @Test public void setCustomDateFormatTest() { final JSONConfig jsonConfig = JSONConfig.of(); - jsonConfig.setDateFormat("#sss"); + jsonConfig.setDateFormat(GlobalCustomFormat.FORMAT_SECONDS); final Date date = DateUtil.parse("2020-06-05 11:16:11"); final JSONObject json = new JSONObject(jsonConfig); @@ -609,7 +619,7 @@ public class JSONObjectTest { @Test public void createJSONObjectTest() { - Assertions.assertThrows(JSONException.class, ()->{ + Assertions.assertThrows(ClassCastException.class, ()->{ // 集合类不支持转为JSONObject JSONUtil.parseObj(new JSONArray(), JSONConfig.of()); }); @@ -692,7 +702,8 @@ public class JSONObjectTest { final String s = json1.toJSONString(0, (pair) -> { if ("b".equals(pair.getKey())) { // 修改值为新值 - pair.setValue(pair.getValue() + "_edit"); + final JSONPrimitive value = (JSONPrimitive) pair.getValue(); + pair.setValue(value.getValue() + "_edit"); return true; } // 除了"b",其他都去掉 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 d39a4afef..ace523c24 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 @@ -102,7 +102,7 @@ public class JSONUtilTest { */ @Test public void parseNumberToJSONArrayTest() { - assertThrows(JSONException.class, () -> { + assertThrows(ClassCastException.class, () -> { final JSONArray json = JSONUtil.parseArray(123L); Assertions.assertNotNull(json); }); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONWriterTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONWriterTest.java index 7f4d8ee6f..6d2f51545 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONWriterTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONWriterTest.java @@ -31,7 +31,7 @@ public class JSONWriterTest { // 日期原样写入 final Date date = jsonObject.getDate("date"); - Assertions.assertEquals("2022-09-30 00:00:00", date.toString()); + Assertions.assertEquals("2022-09-30 00:00:00", DateUtil.date(date).toString()); // 自定义日期格式生效 Assertions.assertEquals("{\"date\":\"2022-09-30\"}", jsonObject.toString()); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/jwt/JWTTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/jwt/JWTTest.java index 20cc3d3d7..0e9ff1469 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/jwt/JWTTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/jwt/JWTTest.java @@ -161,7 +161,7 @@ public class JWTTest { Assertions.assertEquals(bean, beanRes); Assertions.assertEquals(numRes, num); Assertions.assertEquals(username, strRes); - Assertions.assertEquals(list, listRes); + Assertions.assertEquals(list.toString(), listRes.toString()); final String formattedDate = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"); final String formattedRes = DateUtil.format(dateRes, "yyyy-MM-dd HH:mm:ss"); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/xml/XMLTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/xml/XMLTest.java index 82e17c94e..7e5de4d44 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/xml/XMLTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/xml/XMLTest.java @@ -39,7 +39,7 @@ public class XMLTest { Assertions.assertEquals("{\"a\":\"•\"}", jsonObject.toString()); - final String xml2 = JSONXMLUtil.toXml(JSONUtil.parseObj(jsonObject)); + final String xml2 = JSONXMLUtil.toXml(jsonObject); Assertions.assertEquals(xml, xml2); } @@ -53,4 +53,11 @@ public class XMLTest { xml = JSONXMLUtil.toXml(jsonObject, null, new String[0]); Assertions.assertEquals("123456", xml); } + + @Test + public void xmlContentTest2(){ + final JSONObject jsonObject = JSONUtil.ofObj().set("content","123456"); + final String xml = JSONXMLUtil.toXml(jsonObject, null, new String[0]); + Assertions.assertEquals("123456", xml); + } }