diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/BeanToBeanCopier.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/BeanToBeanCopier.java index 25e281464..2864e2485 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/BeanToBeanCopier.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/BeanToBeanCopier.java @@ -16,9 +16,11 @@ package org.dromara.hutool.core.bean.copier; +import org.dromara.hutool.core.bean.BeanException; import org.dromara.hutool.core.bean.PropDesc; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.mutable.MutableEntry; +import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.text.StrUtil; @@ -63,8 +65,21 @@ public class BeanToBeanCopier extends AbsCopier { actualEditable = copyOptions.editable; } final Map targetPropDescMap = getBeanDesc(actualEditable).getPropMap(copyOptions.ignoreCase); + if(MapUtil.isEmpty(targetPropDescMap)){ + if(copyOptions.ignoreError){ + return target; + } + throw new BeanException("No properties for target: {}", actualEditable); + } final Map sourcePropDescMap = getBeanDesc(source.getClass()).getPropMap(copyOptions.ignoreCase); + if(MapUtil.isEmpty(sourcePropDescMap)){ + if(copyOptions.ignoreError){ + return target; + } + throw new BeanException("No properties for source: {}", source.getClass()); + } + sourcePropDescMap.forEach((sFieldName, sDesc) -> { if (null == sFieldName || !sDesc.isReadable(copyOptions.transientSupport)) { // 字段空或不可读,跳过 diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java index 63e3865d7..68f944586 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java @@ -91,7 +91,7 @@ public class BeanConverter implements Converter, Serializable { private Object convertInternal(final Type targetType, final Class targetClass, final Object value) { if (value instanceof Map || value instanceof ValueProvider || - BeanUtil.isWritableBean(value.getClass())) { + BeanUtil.isReadableBean(value.getClass())) { if (value instanceof Map && targetClass.isInterface()) { // 将Map动态代理为Bean return MapProxy.of((Map) value).toProxyBean(targetClass); diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/bean/copier/BeanCopierTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/bean/copier/BeanCopierTest.java index bb2190241..eddbff950 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/bean/copier/BeanCopierTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/bean/copier/BeanCopierTest.java @@ -101,4 +101,11 @@ public class BeanCopierTest { Assertions.assertEquals("abc", b.getValue()); } + @Test + void stringToBeanTest() { + final String str = "null"; + final BeanCopier copier = BeanCopier.of(str, new A(), CopyOptions.of()); + final A copy = copier.copy(); + Assertions.assertNull(copy.value); + } } 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 92b0898ca..fde948dc5 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 @@ -85,8 +85,8 @@ public interface JSON extends Converter, Cloneable, Serializable { * @see BeanPath#getValue(Object) * @since 4.0.6 */ - default Object getByPath(final String expression) { - return BeanPath.of(expression).getValue(this); + default JSON getByPath(final String expression) { + return (JSON) BeanPath.of(expression).getValue(this); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java index e6804f1e0..d1c4d18b6 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java @@ -312,7 +312,7 @@ public class JSONArray extends ListWrapper implements JSON, JSONGetter writer.writeField(new MutableEntry<>(index, value))); - writer.end(); + writer.endArray(); } @Override diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java index e8ed62269..7571e5a17 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONConfig.java @@ -50,7 +50,12 @@ public class JSONConfig implements Serializable { */ private String dateFormat; /** - * 是否忽略null值 + * 是否忽略null值
+ * 此选项主要作用于两个阶段: + *
    + *
  1. Java对象或JSON字符串转为JSON时
  2. + *
  3. JSON写出或转为JSON字符串时
  4. + *
*/ private boolean ignoreNullValue = true; /** @@ -188,7 +193,12 @@ public class JSONConfig implements Serializable { } /** - * 设置是否忽略null值 + * 设置是否忽略null值
+ * 此选项主要作用于两个阶段: + *
    + *
  1. Java对象或JSON字符串转为JSON时
  2. + *
  3. JSON写出或转为JSON字符串时
  4. + *
* * @param ignoreNullValue 是否忽略null值 * @return this diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java index 59ea601e5..716dad05e 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java @@ -90,7 +90,7 @@ public class JSONObject extends MapWrapper implements JSON, JSONGe public void write(final JSONWriter writer) throws JSONException { writer.beginObj(); this.forEach((key, value) -> writer.writeField(new MutableEntry<>(key, value))); - writer.end(); + writer.endObj(); } // region ----- get 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 73c219592..a81a1b5bf 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 @@ -29,9 +29,9 @@ import java.math.BigInteger; /** * JSON原始类型数据封装,根据RFC8259规范,JSONPrimitive只包含以下类型: *
    - *
  • number
  • - *
  • string
  • - *
  • null
  • + *
  • Number
  • + *
  • boolean
  • + *
  • String
  • *
* * @author Looly 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 b2753662b..238a1b6de 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 @@ -461,8 +461,12 @@ public class JSONUtil { * @return 对象 * @see JSON#getByPath(String) */ - public static Object getByPath(final JSON json, final String expression) { - return getByPath(json, expression, null); + public static JSON getByPath(final JSON json, final String expression) { + if ((null == json || StrUtil.isBlank(expression))) { + return null; + } + + return json.getByPath(expression); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java index 5a69147f7..052bfdf2a 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java @@ -24,7 +24,6 @@ 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.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.*; @@ -182,8 +181,7 @@ public class JSONConverter implements Converter, Serializable { @SuppressWarnings("unchecked") private T toBean(final Type targetType, final JSON json) { // 自定义对象反序列化 - final JSONDeserializer deserializer = SerializerManager.getInstance().getDeserializer(targetType); - + final JSONDeserializer deserializer = SerializerManager.getInstance().getDeserializer(json, targetType); if (null != deserializer) { return (T) deserializer.deserialize(json, targetType); } @@ -195,11 +193,6 @@ public class JSONConverter implements Converter, Serializable { //throw new JSONException("Can not get class from type: {}", targetType); } - // issue#I5WDP0 对于Kotlin对象,由于参数可能非空限制,导致无法创建一个默认的对象再赋值 - if (KClassUtil.isKotlinClass(rawType) && json instanceof JSONGetter) { - return KClassUtil.newInstance(rawType, new JSONGetterValueProvider<>((JSONGetter) json)); - } - final Object value; // JSON原始类型 if (json instanceof JSONPrimitive) { @@ -229,7 +222,7 @@ public class JSONConverter implements Converter, Serializable { } // 尝试转Bean - if (BeanUtil.isWritableBean(rawType)) { + if (!(json instanceof JSONPrimitive) && BeanUtil.isWritableBean(rawType)) { return BeanCopier.of(value, ConstructorUtil.newInstanceIfPossible(rawType), targetType, InternalJSONUtil.toCopyOptions(config)).copy(); 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 d1ed9af41..2c7036ea3 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 @@ -84,15 +84,7 @@ class JSONArrayMapper { return; } - if (source instanceof JSONTokener) { - mapFromTokener((JSONTokener) source, JSONConfig.of(), jsonArray); - }if (source instanceof JSONParser) { - ((JSONParser)source).parseTo(jsonArray); - } else if (source instanceof Reader) { - mapFromTokener(new JSONTokener((Reader) source), jsonArray.config(), jsonArray); - } else if (source instanceof InputStream) { - mapFromTokener(new JSONTokener((InputStream) source), jsonArray.config(), jsonArray); - } else if (source instanceof byte[]) { + if (source instanceof byte[]) { final byte[] bytesSource = (byte[]) source; if ('[' == bytesSource[0] && ']' == bytesSource[bytesSource.length - 1]) { mapFromTokener(new JSONTokener(IoUtil.toStream(bytesSource)), jsonArray.config(), jsonArray); 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 11e8a3385..0a4ba47f2 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 @@ -95,13 +95,7 @@ class JSONObjectMapper { throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass()); } - if (source instanceof JSONTokener) { - // JSONTokener - mapFromTokener((JSONTokener) source, jsonObject.config(), jsonObject); - }if (source instanceof JSONParser) { - // JSONParser - ((JSONParser) source).parseTo(jsonObject); - } else if (source instanceof Map) { + if (source instanceof Map) { // Map for (final Map.Entry e : ((Map) source).entrySet()) { jsonObject.set(ConvertUtil.toStr(e.getKey()), e.getValue()); @@ -109,10 +103,6 @@ class JSONObjectMapper { } 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 Reader) { - mapFromTokener(new JSONTokener((Reader) source), jsonObject.config(), jsonObject); - } else if (source instanceof InputStream) { - mapFromTokener(new JSONTokener((InputStream) source), jsonObject.config(), jsonObject); } else if (source instanceof byte[]) { mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source)), jsonObject.config(), jsonObject); } else if (source instanceof ResourceBundle) { diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java index 5b717d980..6ce2b11a0 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONValueMapper.java @@ -32,6 +32,8 @@ import org.dromara.hutool.json.writer.ValueWriterManager; import org.dromara.hutool.json.xml.JSONXMLParser; import org.dromara.hutool.json.xml.ParseConfig; +import java.io.InputStream; +import java.io.Reader; import java.io.Serializable; import java.util.Optional; import java.util.function.Predicate; @@ -94,9 +96,8 @@ public class JSONValueMapper implements Serializable { JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject); return jsonObject; } - return JSONParser.of(new JSONTokener(source), jsonConfig) - .setPredicate(this.predicate) - .parse(); + + return mapFromTokener(new JSONTokener(source)); } /** @@ -128,12 +129,25 @@ public class JSONValueMapper implements Serializable { return (JSON) obj; } + // 读取JSON流 + if(obj instanceof JSONTokener){ + return mapFromTokener((JSONTokener) obj); + }else if(obj instanceof JSONParser){ + return ((JSONParser)obj).parse(); + } else if (obj instanceof Reader) { + return mapFromTokener(new JSONTokener((Reader) obj)); + } else if (obj instanceof InputStream) { + return mapFromTokener(new JSONTokener((InputStream) obj)); + } + // 自定义序列化 final JSONSerializer serializer = SerializerManager.getInstance().getSerializer(obj); if (null != serializer) { return serializer.serialize(obj, new SimpleJSONContext(null, this.jsonConfig)); } + // read + // 原始类型 if (null != ValueWriterManager.getInstance().get(obj)) { return new JSONPrimitive(obj, jsonConfig); @@ -161,4 +175,14 @@ public class JSONValueMapper implements Serializable { throw ExceptionUtil.wrap(exception, JSONException.class); } } + + /** + * 从{@link JSONTokener} 中读取JSON字符串,并转换为JSON + * + * @param tokener {@link JSONTokener} + * @return JSON + */ + private JSON mapFromTokener(final JSONTokener tokener) { + return JSONParser.of(tokener, jsonConfig).setPredicate(this.predicate).parse(); + } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/package-info.java b/hutool-json/src/main/java/org/dromara/hutool/json/package-info.java index 8e1385d48..862ee7ffe 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/package-info.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/package-info.java @@ -15,10 +15,13 @@ */ /** - * JSON(JavaScript Object Notation JavaScript对象表示法)封装,包含以下组件: + * JSON(JavaScript Object Notation JavaScript对象表示法)封装
+ * 规范见:https://www.rfc-editor.org/rfc/rfc8259 + * 包含以下组件: *
    - *
  • JSONObject:使用键值对表示的数据类型,使用"{}"包围
  • - *
  • JSONArray:使用列表表示的数据类型,使用"[]"包围
  • + *
  • JSONObject: 使用键值对表示的数据类型,使用"{}"包围
  • + *
  • JSONArray: 使用列表表示的数据类型,使用"[]"包围
  • + *
  • JSONPrimitive:表示boolean、String、Number等原始类型
  • *
* JSON封装主要包括JSON表示和JSON转换: * diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java index bab1d4b97..f93294a09 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONDeserializer.java @@ -21,7 +21,7 @@ import org.dromara.hutool.json.JSON; import java.lang.reflect.Type; /** - * JSON自定义反序列化接口,实现{@link JSON} to Bean,使用方式为: + * JSON自定义反序列化接口,实现{@link JSON} to Bean,主要作用于JSON转为Java对象时,使用方式为: *
    *
  • 定义好反序列化规则,关联指定类型与转换器实现反序列化。
  • *
  • 使Bean实现此接口,调用{@link #deserialize(JSON, Type)}解析字段,返回this即可。
  • diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java index d53dd1eb1..d5307a60f 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONSerializer.java @@ -20,7 +20,8 @@ import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONObject; /** - * 序列化接口,通过实现此接口,实现自定义的对象转换为JSON的操作 + * 序列化接口,通过实现此接口,实现自定义的对象转换为JSON的操作
    + * 序列化主要作用于Java对象转为JSON时 * * @param 对象类型 * @author Looly diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java index e723e8260..539c65b7d 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONDeserializer.java @@ -31,7 +31,8 @@ import java.lang.reflect.Type; public interface MatcherJSONDeserializer extends JSONDeserializer { /** - * 匹配反序列化器是否匹配 + * 匹配反序列化器是否匹配
    + * 根据JSON的内容、类型,和目标类型,精准匹配反序列化器 * * @param json JSON对象 * @param deserializeType 反序列化类型 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java index 3ede9fa8f..f1359f296 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java @@ -26,7 +26,8 @@ package org.dromara.hutool.json.serializer; public interface MatcherJSONSerializer extends JSONSerializer { /** - * 判断是否匹配 + * 判断是否匹配
    + * 根据Java对象内容、类型等信息,配合当前JSON所处位置判断是否匹配,用于决定是否执行序列化 * * @param bean 对象 * @param context JSON上下文 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java index 52926cc4d..81f508dc5 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/SerializerManager.java @@ -16,11 +16,14 @@ 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.map.concurrent.SafeConcurrentHashMap; 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.serializer.impl.KotlinDeserializer; import org.dromara.hutool.json.serializer.impl.TemporalAccessorSerializer; import org.dromara.hutool.json.serializer.impl.TimeZoneSerializer; @@ -33,7 +36,19 @@ import java.util.Set; import java.util.TimeZone; /** - * JSON序列化和反序列化管理器,用于管理JSON序列化器,注册和注销自定义序列化器和反序列化器。 + * JSON序列化和反序列化管理器,用于管理JSON序列化器,注册和注销自定义序列化器和反序列化器。
    + * 此管理器管理着两种类型的序列化器和反序列化器: + *
      + *
    • 类型精准匹配方式。通过Java对象类型匹配,只会匹配查找的类型,而不匹配子类。可以调用{@link #register(Type, JSONSerializer)} 和 {@link #register(Type, JSONDeserializer)}注册。
    • + *
    • 匹配器(Matcher)方式。通过判断序列化和反序列化器中match方法,找到自定义的序列化和反序列化器,可以调用{@link #register(MatcherJSONSerializer)} 和 {@link #register(MatcherJSONDeserializer)}注册。
    • + *
    + * + * 管理器的使用分为三种方式: + *
      + *
    • 全局模式: 使用{@link SerializerManager#getInstance()}调用单例,全局可用。
    • + *
    • 实例模式: 使用{@link SerializerManager#of()}创建实例,局部可用。
    • + *
    • 自定义模式:使用{@code new SerializerManager()}创建实例,不加载默认的转换器。
    • + *
    * * @author looly * @since 6.0.0 @@ -48,7 +63,7 @@ public class SerializerManager { */ private static final SerializerManager INSTANCE = new SerializerManager(); static { - registerDefault(); + registerDefault(INSTANCE); } } @@ -61,6 +76,17 @@ public class SerializerManager { return SerializerManager.SingletonHolder.INSTANCE; } + /** + * 创建SerializerManager,附带默认的序列化器和反序列化器 + * + * @return SerializerManager + */ + public static SerializerManager of() { + final SerializerManager serializerManager = new SerializerManager(); + registerDefault(serializerManager); + return serializerManager; + } + /** * 用户自定义序列化器,存储自定义匹配规则的一类对象的转换器 */ @@ -162,10 +188,12 @@ public class SerializerManager { * @return JSONSerializer */ @SuppressWarnings({"unchecked"}) - public JSONSerializer getSerializer(final Object bean) { - for (final MatcherJSONSerializer serializer : this.serializerSet) { - if (serializer.match(bean, null)) { - return (JSONSerializer) serializer; + public MatcherJSONSerializer getSerializer(final Object bean) { + if(CollUtil.isNotEmpty(this.serializerSet)){ + for (final MatcherJSONSerializer serializer : this.serializerSet) { + if (serializer.match(bean, null)) { + return (MatcherJSONSerializer) serializer; + } } } return null; @@ -179,20 +207,21 @@ public class SerializerManager { */ @SuppressWarnings("unchecked") public JSONSerializer getSerializer(final Type type) { - if(null == type){ + if(null == type || CollUtil.isEmpty(this.serializerMap)){ return null; } - return (JSONSerializer) getSerializerMap().get(type); + return (JSONSerializer) this.serializerMap.get(type); } /** * 获取匹配器对应的反序列化器 * + * @param json JSON * @param type 类型 * @return JSONDeserializer */ @SuppressWarnings("unchecked") - public JSONDeserializer getDeserializer(final Type type) { + public JSONDeserializer getDeserializer(final JSON json, final Type type) { final Class rawType = TypeUtil.getClass(type); if(null == rawType){ return null; @@ -201,7 +230,23 @@ public class SerializerManager { return (JSONDeserializer) ConstructorUtil.newInstanceIfPossible(rawType); } - return (JSONDeserializer) getDeserializerMap().get(type); + if(CollUtil.isNotEmpty(this.deserializerMap)){ + final JSONDeserializer jsonDeserializer = this.deserializerMap.get(type); + if(null != jsonDeserializer){ + return (JSONDeserializer) jsonDeserializer; + } + } + + // Matcher + if(CollUtil.isNotEmpty(this.deserializerSet)){ + for (final MatcherJSONDeserializer deserializer : this.deserializerSet) { + if (deserializer.match(json, type)) { + return (JSONDeserializer) deserializer; + } + } + } + + return null; } // endregion @@ -252,9 +297,9 @@ public class SerializerManager { /** * 注册默认的序列化器和反序列化器 + * @param manager {@code SerializerManager} */ - private static void registerDefault() { - final SerializerManager manager = SingletonHolder.INSTANCE; + private static void registerDefault(final SerializerManager manager) { manager.register(LocalDate.class, (JSONSerializer) new TemporalAccessorSerializer(LocalDate.class)); manager.register(LocalDate.class, (JSONDeserializer) new TemporalAccessorSerializer(LocalDate.class)); @@ -266,6 +311,9 @@ public class SerializerManager { manager.register((MatcherJSONSerializer) TimeZoneSerializer.INSTANCE); manager.register((MatcherJSONDeserializer) TimeZoneSerializer.INSTANCE); + + // issue#I5WDP0 对于Kotlin对象,由于参数可能非空限制,导致无法创建一个默认的对象再赋值 + manager.register(KotlinDeserializer.INSTANCE); } // endregion } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KotlinDeserializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KotlinDeserializer.java new file mode 100644 index 000000000..09a227cfd --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/KotlinDeserializer.java @@ -0,0 +1,55 @@ +/* + * 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.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.serializer.MatcherJSONDeserializer; + +import java.lang.reflect.Type; + +/** + * Kotlin对象反序列化器
    + * issue#I5WDP0 对于Kotlin对象,由于参数可能非空限制,导致无法创建一个默认的对象再赋值 + * + * @author looly + * @since 6.0.0 + */ +public class KotlinDeserializer implements MatcherJSONDeserializer { + + /** + * 单例 + */ + public static final MatcherJSONDeserializer INSTANCE = new KotlinDeserializer(); + + @Override + public boolean match(final JSON json, final Type deserializeType) { + final Class rawType = TypeUtil.getClass(deserializeType); + return json instanceof JSONGetter + && 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)); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java index 84f319626..ccad73471 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/JSONWriter.java @@ -77,10 +77,6 @@ public class JSONWriter implements Appendable, Flushable, Closeable { * 写出当前值是否需要分隔符 */ private boolean needSeparator; - /** - * 是否为JSONArray模式 - */ - private boolean arrayMode; /** * 本级别缩进量 */ @@ -129,12 +125,20 @@ public class JSONWriter implements Appendable, Flushable, Closeable { @SuppressWarnings("resource") public JSONWriter beginObj() { append(CharUtil.DELIM_START); - arrayMode = false; needSeparator = false; indent += indentFactor; return this; } + /** + * 结束JSON对象,默认根据开始的类型,补充"}" + * + * @return this + */ + public JSONWriter endObj() { + return end(false); + } + /** * JSONArray写出开始,默认写出"[" * @@ -143,36 +147,24 @@ public class JSONWriter implements Appendable, Flushable, Closeable { @SuppressWarnings("resource") public JSONWriter beginArray() { append(CharUtil.BRACKET_START); - arrayMode = true; needSeparator = false; indent += indentFactor; return this; } /** - * 结束,默认根据开始的类型,补充"}"或"]" + * 结束JSON数组,默认根据开始的类型,补充"]" * * @return this */ - @SuppressWarnings("resource") - public JSONWriter end() { - // 结束子缩进 - indent -= indentFactor; - // 换行缩进 - writeLF().writeSpace(indent); - append(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END); - flush(); - arrayMode = false; - // 当前对象或数组结束,当新的 - needSeparator = true; - return this; + public JSONWriter endArray() { + return end(true); } /** * 写出字段名及字段值,如果字段值是{@code null}且忽略null值,则不写出任何内容
    - * 在{@link #arrayMode} 为 {@code true} 时,key是数字,此时不写出键,只写值 * - * @param pair 键值对 + * @param pair 键值对 * @return this * @since 6.0.0 */ @@ -189,12 +181,15 @@ public class JSONWriter implements Appendable, Flushable, Closeable { } } - if (!arrayMode) { - // JSONObject模式,写出键,否则只输出值 - writeKey(StrUtil.toString(pair.getKey())); + final Object key = pair.getKey(); + if (key instanceof Integer) { + // 数组模式,只写出值 + return writeValueDirect(pair.getValue(), true); } - return writeValueDirect(pair.getValue()); + // 键值对模式 + writeKey(StrUtil.toString(key)); + return writeValueDirect(pair.getValue(), false); } /** @@ -326,13 +321,33 @@ public class JSONWriter implements Appendable, Flushable, Closeable { // ------------------------------------------------------------------------------ Private methods + /** + * 结束,默认根据开始的类型,补充"}"或"]" + * + * @param arrayMode 数组模式,true表示数组模式,false表示对象模式 + * @return this + */ + @SuppressWarnings("resource") + private JSONWriter end(final boolean arrayMode) { + // 结束子缩进 + indent -= indentFactor; + // 换行缩进 + writeLF().writeSpace(indent); + append(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END); + flush(); + // 当前对象或数组结束,当新的 + needSeparator = true; + return this; + } + /** * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值 * * @param value 值 + * @param arrayMode 是否数组模式 * @return this */ - private JSONWriter writeValueDirect(final Object value) { + private JSONWriter writeValueDirect(final Object value, final boolean arrayMode) { if (arrayMode) { if (needSeparator) { //noinspection resource @@ -352,7 +367,7 @@ public class JSONWriter implements Appendable, Flushable, Closeable { /** * 写出JSON的值,根据值类型不同,输出不同内容 * - * @param value 值 + * @param value 值 * @return this */ @SuppressWarnings("resource") diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/writer/ValueWriterManager.java b/hutool-json/src/main/java/org/dromara/hutool/json/writer/ValueWriterManager.java index 8bae636c8..09625d146 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/writer/ValueWriterManager.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/writer/ValueWriterManager.java @@ -100,7 +100,7 @@ public class ValueWriterManager { private static void registerDefault() { final ValueWriterManager manager = SingletonHolder.INSTANCE; // JDK对象最后判断 - // manager.register(JdkValueWriter.INSTANCE); + manager.register(JdkValueWriter.INSTANCE); manager.register(NumberValueWriter.INSTANCE); manager.register(DateValueWriter.INSTANCE); manager.register(BooleanValueWriter.INSTANCE); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3504Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3504Test.java index e769fd52d..f1450bc5c 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3504Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3504Test.java @@ -17,6 +17,7 @@ package org.dromara.hutool.json; import lombok.Data; +import org.dromara.hutool.core.lang.Console; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -27,6 +28,7 @@ public class Issue3504Test { jsonBean.setName("test"); jsonBean.setClasses(new Class[]{String.class}); final String huToolJsonStr = JSONUtil.toJsonStr(jsonBean); + Console.log(huToolJsonStr); final JsonBean bean = JSONUtil.toBean(huToolJsonStr, JsonBean.class); Assertions.assertNotNull(bean); Assertions.assertEquals("test", bean.getName()); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI5OMSCTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI5OMSCTest.java index d7dfd0285..5587421f9 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI5OMSCTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI5OMSCTest.java @@ -18,10 +18,10 @@ package org.dromara.hutool.json; import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.io.resource.ResourceUtil; -import org.dromara.hutool.core.lang.Console; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Predicate多层过滤 */ @@ -30,7 +30,6 @@ public class IssueI5OMSCTest { @Test public void filterTest(){ final JSONObject json = JSONUtil.parseObj(ResourceUtil.readUtf8Str("issueI5OMSC.json")); - Console.log(json.toStringPretty()); final String s = json.toJSONString(0, (entry) -> { final Object key = entry.getKey(); @@ -39,6 +38,6 @@ public class IssueI5OMSCTest { } return true; }); - Assertions.assertEquals("{\"store\":{\"bicycle\":{\"color\":\"red\"},\"book\":[{\"author\":\"Evelyn Waugh\"},{\"author\":\"Evelyn Waugh02\"}]}}", s); + assertEquals("{\"store\":{\"bicycle\":{\"color\":\"red\"},\"book\":[{\"author\":\"Evelyn Waugh\"},{\"author\":\"Evelyn Waugh02\"}]}}", s); } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONConvertTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONConvertTest.java index 94974c029..96d1c8d08 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONConvertTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONConvertTest.java @@ -20,7 +20,6 @@ import org.dromara.hutool.core.io.resource.ResourceUtil; import org.dromara.hutool.json.test.bean.ExamInfoDict; import org.dromara.hutool.json.test.bean.PerfectEvaluationProductResVo; import org.dromara.hutool.json.test.bean.UserInfoDict; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -28,6 +27,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * JSON转换单元测试 * @@ -39,6 +41,60 @@ public class JSONConvertTest { @Test public void testBean2Json() { + final UserInfoDict userInfoDict = getUserInfoDict(); + + final Map tempMap = new HashMap<>(); + tempMap.put("userInfoDict", userInfoDict); + tempMap.put("toSendManIdCard", 1); + + final JSONObject obj = JSONUtil.parseObj(tempMap); + assertEquals(Integer.valueOf(1), obj.getInt("toSendManIdCard")); + + final JSONObject examInfoDictsJson = obj.getJSONObject("userInfoDict"); + assertEquals(Integer.valueOf(1), examInfoDictsJson.getInt("id")); + assertEquals("质量过关", examInfoDictsJson.getStr("realName")); + + final JSONPrimitive id = (JSONPrimitive) JSONUtil.getByPath(obj, "userInfoDict.examInfoDict[0].id"); + assertEquals(1, id.getValue()); + } + + @Test + public void testJson2Bean() { + // language=JSON + final String examJson = "{\n" + " \"examInfoDicts\": {\n" + " \"id\": 1,\n" + " \"realName\": \"质量过关\",\n" // + + " \"examInfoDict\": [\n" + " {\n" + " \"id\": 1,\n" + " \"answerIs\": 1,\n" + " \"examType\": 0\n" // + + " },\n" + " {\n" + " \"id\": 2,\n" + " \"answerIs\": 0,\n" + " \"examType\": 0\n" + " },\n" // + + " {\n" + " \"id\": 3,\n" + " \"answerIs\": 0,\n" + " \"examType\": 1\n" + " }\n" + " ],\n" // + + " \"photoPath\": \"yx.mm.com\"\n" + " },\n" + " \"toSendManIdCard\": 1\n" + "}"; + + final JSONObject jsonObject = JSONUtil.parseObj(examJson).getJSONObject("examInfoDicts"); + final UserInfoDict userInfoDict = jsonObject.toBean(UserInfoDict.class); + + assertEquals(userInfoDict.getId(), Integer.valueOf(1)); + assertEquals(userInfoDict.getRealName(), "质量过关"); + + //============ + + final String jsonStr = "{\"id\":null,\"examInfoDict\":[{\"answerIs\":1, \"id\":null}]}";//JSONUtil.toJsonStr(userInfoDict1); + final JSONObject jsonObject2 = JSONUtil.parseObj(jsonStr);//.getJSONObject("examInfoDicts"); + final UserInfoDict userInfoDict2 = jsonObject2.toBean(UserInfoDict.class); + assertNull(userInfoDict2.getId()); + } + + /** + * 针对Bean中Setter返回this测试是否可以成功调用Setter方法并注入 + */ + @Test + public void testJson2Bean2() { + final String jsonStr = ResourceUtil.readUtf8Str("evaluation.json"); + final JSONObject obj = JSONUtil.parseObj(jsonStr); + final PerfectEvaluationProductResVo vo = obj.toBean(PerfectEvaluationProductResVo.class); + + assertEquals(obj.getStr("HA001"), vo.getHA001()); + assertEquals(obj.getInt("costTotal"), vo.getCostTotal()); + } + + private static UserInfoDict getUserInfoDict() { final UserInfoDict userInfoDict = new UserInfoDict(); userInfoDict.setId(1); userInfoDict.setPhotoPath("yx.mm.com"); @@ -65,55 +121,6 @@ public class JSONConvertTest { examInfoDicts.add(examInfoDict2); userInfoDict.setExamInfoDict(examInfoDicts); - - final Map tempMap = new HashMap<>(); - tempMap.put("userInfoDict", userInfoDict); - tempMap.put("toSendManIdCard", 1); - - final JSONObject obj = JSONUtil.parseObj(tempMap); - Assertions.assertEquals(new Integer(1), obj.getInt("toSendManIdCard")); - - final JSONObject examInfoDictsJson = obj.getJSONObject("userInfoDict"); - Assertions.assertEquals(new Integer(1), examInfoDictsJson.getInt("id")); - Assertions.assertEquals("质量过关", examInfoDictsJson.getStr("realName")); - - final Object id = JSONUtil.getByPath(obj, "userInfoDict.examInfoDict[0].id"); - Assertions.assertEquals(1, id); - } - - @Test - public void testJson2Bean() { - // language=JSON - final String examJson = "{\n" + " \"examInfoDicts\": {\n" + " \"id\": 1,\n" + " \"realName\": \"质量过关\",\n" // - + " \"examInfoDict\": [\n" + " {\n" + " \"id\": 1,\n" + " \"answerIs\": 1,\n" + " \"examType\": 0\n" // - + " },\n" + " {\n" + " \"id\": 2,\n" + " \"answerIs\": 0,\n" + " \"examType\": 0\n" + " },\n" // - + " {\n" + " \"id\": 3,\n" + " \"answerIs\": 0,\n" + " \"examType\": 1\n" + " }\n" + " ],\n" // - + " \"photoPath\": \"yx.mm.com\"\n" + " },\n" + " \"toSendManIdCard\": 1\n" + "}"; - - final JSONObject jsonObject = JSONUtil.parseObj(examJson).getJSONObject("examInfoDicts"); - final UserInfoDict userInfoDict = jsonObject.toBean(UserInfoDict.class); - - Assertions.assertEquals(userInfoDict.getId(), new Integer(1)); - Assertions.assertEquals(userInfoDict.getRealName(), "质量过关"); - - //============ - - final String jsonStr = "{\"id\":null,\"examInfoDict\":[{\"answerIs\":1, \"id\":null}]}";//JSONUtil.toJsonStr(userInfoDict1); - final JSONObject jsonObject2 = JSONUtil.parseObj(jsonStr);//.getJSONObject("examInfoDicts"); - final UserInfoDict userInfoDict2 = jsonObject2.toBean(UserInfoDict.class); - Assertions.assertNull(userInfoDict2.getId()); - } - - /** - * 针对Bean中Setter返回this测试是否可以成功调用Setter方法并注入 - */ - @Test - public void testJson2Bean2() { - final String jsonStr = ResourceUtil.readUtf8Str("evaluation.json"); - final JSONObject obj = JSONUtil.parseObj(jsonStr); - final PerfectEvaluationProductResVo vo = obj.toBean(PerfectEvaluationProductResVo.class); - - Assertions.assertEquals(obj.getStr("HA001"), vo.getHA001()); - Assertions.assertEquals(obj.getInt("costTotal"), vo.getCostTotal()); + return userInfoDict; } } 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 9a4d3c943..977d19fa5 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 @@ -40,6 +40,9 @@ import java.nio.charset.StandardCharsets; import java.sql.Timestamp; import java.util.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * JSONObject单元测试 * @@ -52,9 +55,9 @@ public class JSONObjectTest { final String str = "{\"code\": 500, \"data\":null}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject jsonObject = JSONUtil.parseObj(str, JSONConfig.of().setIgnoreNullValue(false)); - Assertions.assertEquals("{\"code\":500,\"data\":null}", jsonObject.toString()); + assertEquals("{\"code\":500,\"data\":null}", jsonObject.toString()); jsonObject.config().setIgnoreNullValue(true); - Assertions.assertEquals("{\"code\":500}", jsonObject.toString()); + assertEquals("{\"code\":500}", jsonObject.toString()); } @Test @@ -62,7 +65,7 @@ public class JSONObjectTest { final String str = "{\"test\":\"关于开展2018年度“文明集体”、“文明职工”评选表彰活动的通知\"}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(str); - Assertions.assertEquals(str, json.toString()); + assertEquals(str, json.toString()); } /** @@ -72,18 +75,18 @@ public class JSONObjectTest { public void toStringTest3() { final JSONObject json = JSONUtil.ofObj(JSONConfig.of().setDateFormat(DatePattern.NORM_DATE_PATTERN))// .set("dateTime", DateUtil.parse("2019-05-02 22:12:01")); - Assertions.assertEquals("{\"dateTime\":\"2019-05-02\"}", json.toString()); + assertEquals("{\"dateTime\":\"2019-05-02\"}", json.toString()); } @Test public void toStringWithDateTest() { JSONObject json = JSONUtil.ofObj().set("date", DateUtil.parse("2019-05-08 19:18:21")); assert json != null; - Assertions.assertEquals("{\"date\":1557314301000}", json.toString()); + assertEquals("{\"date\":1557314301000}", json.toString()); json = JSONUtil.ofObj(JSONConfig.of().setDateFormat(DatePattern.NORM_DATE_PATTERN)) .set("date", DateUtil.parse("2019-05-08 19:18:21")); - Assertions.assertEquals("{\"date\":\"2019-05-08\"}", json.toString()); + assertEquals("{\"date\":\"2019-05-08\"}", json.toString()); } @@ -102,22 +105,22 @@ public class JSONObjectTest { // putAll操作会覆盖相同key的值,因此a,b两个key的值改变,c的值不变 json1.putAll(json2); - Assertions.assertEquals(json1.getObj("a"), "value21"); - Assertions.assertEquals(json1.getObj("b"), "value22"); - Assertions.assertEquals(json1.getObj("c"), "value3"); + assertEquals(json1.getObj("a"), "value21"); + assertEquals(json1.getObj("b"), "value22"); + assertEquals(json1.getObj("c"), "value3"); } @Test public void parseStringTest() { final String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\", \"d\": true, \"e\": null}"; final JSONObject jsonObject = JSONUtil.parseObj(jsonStr); - Assertions.assertEquals(jsonObject.getObj("a"), "value1"); - Assertions.assertEquals(jsonObject.getObj("b"), "value2"); - Assertions.assertEquals(jsonObject.getObj("c"), "value3"); - Assertions.assertEquals(jsonObject.getObj("d"), true); + assertEquals(jsonObject.getObj("a"), "value1"); + assertEquals(jsonObject.getObj("b"), "value2"); + assertEquals(jsonObject.getObj("c"), "value3"); + assertEquals(jsonObject.getObj("d"), true); Assertions.assertTrue(jsonObject.containsKey("e")); - Assertions.assertNull(jsonObject.get("e")); + assertNull(jsonObject.get("e")); } @Test @@ -125,8 +128,8 @@ public class JSONObjectTest { final String jsonStr = "{\"file_name\":\"RMM20180127009_731.000\",\"error_data\":\"201121151350701001252500000032 18973908335 18973908335 13601893517 201711211700152017112115135420171121 6594000000010100000000000000000000000043190101701001910072 100001100 \",\"error_code\":\"F140\",\"error_info\":\"最早发送时间格式错误,该字段可以为空,当不为空时正确填写格式为“YYYYMMDDHHMISS”\",\"app_name\":\"inter-pre-check\"}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(jsonStr); - Assertions.assertEquals("F140", json.getStr("error_code")); - Assertions.assertEquals("最早发送时间格式错误,该字段可以为空,当不为空时正确填写格式为“YYYYMMDDHHMISS”", json.getStr("error_info")); + assertEquals("F140", json.getStr("error_code")); + assertEquals("最早发送时间格式错误,该字段可以为空,当不为空时正确填写格式为“YYYYMMDDHHMISS”", json.getStr("error_info")); } @Test @@ -134,7 +137,7 @@ public class JSONObjectTest { final String jsonStr = "{\"test\":\"体”、“文\"}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(jsonStr); - Assertions.assertEquals("体”、“文", json.getStr("test")); + assertEquals("体”、“文", json.getStr("test")); } @Test @@ -142,8 +145,8 @@ public class JSONObjectTest { final String jsonStr = "{'msg':'这里还没有内容','data':{'cards':[]},'ok':0}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(jsonStr); - Assertions.assertEquals(Integer.valueOf(0), json.getInt("ok")); - Assertions.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); + assertEquals(Integer.valueOf(0), json.getInt("ok")); + assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); } @Test @@ -151,8 +154,8 @@ public class JSONObjectTest { final String jsonStr = "{'msg':'这里还没有内容','data':{'cards':[]},'ok':0}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(jsonStr.getBytes(StandardCharsets.UTF_8)); - Assertions.assertEquals(Integer.valueOf(0), json.getInt("ok")); - Assertions.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); + assertEquals(Integer.valueOf(0), json.getInt("ok")); + assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); } @Test @@ -162,8 +165,8 @@ public class JSONObjectTest { //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(stringReader); - Assertions.assertEquals(Integer.valueOf(0), json.getInt("ok")); - Assertions.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); + assertEquals(Integer.valueOf(0), json.getInt("ok")); + assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); } @Test @@ -173,8 +176,8 @@ public class JSONObjectTest { //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(in); - Assertions.assertEquals(Integer.valueOf(0), json.getInt("ok")); - Assertions.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); + assertEquals(Integer.valueOf(0), json.getInt("ok")); + assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards")); } @Test @@ -183,8 +186,8 @@ public class JSONObjectTest { final String jsonStr = "{\"a\":\"
    aaa
    \"}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject json = JSONUtil.parseObj(jsonStr); - Assertions.assertEquals("
    aaa
    ", json.getObj("a")); - Assertions.assertEquals(jsonStr, json.toString()); + assertEquals("
    aaa
    ", json.getObj("a")); + assertEquals(jsonStr, json.toString()); } @Test @@ -197,14 +200,14 @@ public class JSONObjectTest { .set("list", JSONUtil.ofArray().set("a").set("b")).set("testEnum", "TYPE_A"); final TestBean bean = json.toBean(TestBean.class); - Assertions.assertEquals("a", bean.getList().get(0)); - Assertions.assertEquals("b", bean.getList().get(1)); + assertEquals("a", bean.getList().get(0)); + assertEquals("b", bean.getList().get(1)); - Assertions.assertEquals("strValue1", bean.getBeanValue().getValue1()); + assertEquals("strValue1", bean.getBeanValue().getValue1()); // BigDecimal转换检查 - Assertions.assertEquals(new BigDecimal("234"), bean.getBeanValue().getValue2()); + assertEquals(new BigDecimal("234"), bean.getBeanValue().getValue2()); // 枚举转换检查 - Assertions.assertEquals(TestEnum.TYPE_A, bean.getTestEnum()); + assertEquals(TestEnum.TYPE_A, bean.getTestEnum()); } @Test @@ -218,9 +221,9 @@ public class JSONObjectTest { final TestBean bean = json.toBean(TestBean.class); // 当JSON中为字符串"null"时应被当作字符串处理 - Assertions.assertEquals("null", bean.getStrValue()); + assertEquals("null", bean.getStrValue()); // 当JSON中为字符串"null"时Bean中的字段类型不匹配应在ignoreError模式下忽略注入 - Assertions.assertNull(bean.getBeanValue()); + assertNull(bean.getBeanValue()); } @Test @@ -234,7 +237,7 @@ public class JSONObjectTest { final JSONObject json = JSONUtil.parseObj(userA); final UserA userA2 = json.toBean(UserA.class); // 测试数组 - Assertions.assertEquals("seq1", userA2.getSqs().get(0).getSeq()); + assertEquals("seq1", userA2.getSqs().get(0).getSeq()); // 测试带换行符等特殊字符转换是否成功 Assertions.assertTrue(StrUtil.isNotBlank(userA2.getName())); } @@ -251,7 +254,7 @@ public class JSONObjectTest { final String json = "{\"data\":{\"b\": \"c\"}}"; final UserWithMap map = JSONUtil.toBean(json, UserWithMap.class); - Assertions.assertEquals("c", map.getData().get("b")); + assertEquals("c", map.getData().get("b")); } @Test @@ -284,13 +287,13 @@ public class JSONObjectTest { .set("userId", "测试用户1")); final TokenAuthWarp2 bean = json.toBean(TokenAuthWarp2.class); - Assertions.assertEquals("http://test.com", bean.getTargetUrl()); - Assertions.assertEquals("true", bean.getSuccess()); + assertEquals("http://test.com", bean.getTargetUrl()); + assertEquals("true", bean.getSuccess()); final TokenAuthResponse result = bean.getResult(); Assertions.assertNotNull(result); - Assertions.assertEquals("tokenTest", result.getToken()); - Assertions.assertEquals("测试用户1", result.getUserId()); + assertEquals("tokenTest", result.getToken()); + assertEquals("测试用户1", result.getUserId()); } /** @@ -303,7 +306,7 @@ public class JSONObjectTest { "\"secret\":\"dsadadqwdqs121d1e2\",\"message\":\"hello world\"},\"code\":100,\"" + "message\":\"validate message\"}"; final ResultDto dto = JSONUtil.toBean(jsonStr, ResultDto.class); - Assertions.assertEquals("validate message", dto.getMessage()); + assertEquals("validate message", dto.getMessage()); } @Test @@ -331,10 +334,10 @@ public class JSONObjectTest { final JSONObject json = JSONUtil.parseObj(bean, JSONConfig.of().setIgnoreNullValue(false)); // 枚举转换检查,更新:枚举原样保存,在writer时调用toString。 - Assertions.assertEquals(TestEnum.TYPE_B, json.getObj("testEnum")); + assertEquals(TestEnum.TYPE_B, json.getObj("testEnum")); final TestBean bean2 = json.toBean(TestBean.class); - Assertions.assertEquals(bean.toString(), bean2.toString()); + assertEquals(bean.toString(), bean2.toString()); } @Test @@ -344,9 +347,9 @@ public class JSONObjectTest { .set("data", "{\"jobId\": \"abc\", \"videoUrl\": \"http://a.com/a.mp4\"}"); final JSONBean bean = json.toBean(JSONBean.class); - Assertions.assertEquals(22, bean.getCode()); - Assertions.assertEquals("abc", bean.getData().getObj("jobId")); - Assertions.assertEquals("http://a.com/a.mp4", bean.getData().getObj("videoUrl")); + assertEquals(22, bean.getCode()); + assertEquals("abc", bean.getData().getObj("jobId")); + assertEquals("http://a.com/a.mp4", bean.getData().getObj("videoUrl")); } @Test @@ -359,8 +362,8 @@ public class JSONObjectTest { final JSONObject userAJson = JSONUtil.parseObj(userA); final UserB userB = JSONUtil.toBean(userAJson, UserB.class); - Assertions.assertEquals(userA.getName(), userB.getName()); - Assertions.assertEquals(userA.getDate(), userB.getDate()); + assertEquals(userA.getName(), userB.getName()); + assertEquals(userA.getDate(), userB.getDate()); } @Test @@ -374,7 +377,7 @@ public class JSONObjectTest { final JSONObject userAJson = JSONUtil.parseObj(userA, JSONConfig.of().setDateFormat("yyyy-MM-dd")); final UserA bean = JSONUtil.toBean(userAJson.toString(), UserA.class); - Assertions.assertEquals(DateUtil.parse("2018-10-25"), bean.getDate()); + assertEquals(DateUtil.parse("2018-10-25"), bean.getDate()); } @Test @@ -384,7 +387,7 @@ public class JSONObjectTest { .set("name", "nameValue") .set("date", "08:00:00"); final UserA bean = JSONUtil.toBean(userAJson.toString(), UserA.class); - Assertions.assertEquals(DateUtil.formatToday() + " 08:00:00", DateUtil.date(bean.getDate()).toString()); + assertEquals(DateUtil.formatToday() + " 08:00:00", DateUtil.date(bean.getDate()).toString()); } @Test @@ -407,8 +410,8 @@ public class JSONObjectTest { public void specialCharTest() { final String json = "{\"pattern\": \"[abc]\b\u2001\", \"pattern2Json\": {\"patternText\": \"[ab]\\b\"}}"; final JSONObject obj = JSONUtil.parseObj(json); - Assertions.assertEquals("[abc]\\b\\u2001", obj.getStrEscaped("pattern")); - Assertions.assertEquals("{\"patternText\":\"[ab]\\b\"}", obj.getStrEscaped("pattern2Json")); + assertEquals("[abc]\\b\\u2001", obj.getStrEscaped("pattern")); + assertEquals("{\"patternText\":\"[ab]\\b\"}", obj.getStrEscaped("pattern2Json")); } @Test @@ -417,12 +420,12 @@ public class JSONObjectTest { final JSONObject jsonObject = JSONUtil.parseObj(json); // 没有转义按照默认规则显示 - Assertions.assertEquals("yyb\nbbb", jsonObject.getStr("name")); + assertEquals("yyb\nbbb", jsonObject.getStr("name")); // 转义按照字符串显示 - Assertions.assertEquals("yyb\\nbbb", jsonObject.getStrEscaped("name")); + assertEquals("yyb\\nbbb", jsonObject.getStrEscaped("name")); final String bbb = jsonObject.getStr("bbb", "defaultBBB"); - Assertions.assertEquals("defaultBBB", bbb); + assertEquals("defaultBBB", bbb); } @Test @@ -432,15 +435,15 @@ public class JSONObjectTest { beanWithAlias.setValue2(35); final JSONObject jsonObject = JSONUtil.parseObj(beanWithAlias); - Assertions.assertEquals("张三", jsonObject.getStr("name")); - Assertions.assertEquals(Integer.valueOf(35), jsonObject.getInt("age")); + assertEquals("张三", jsonObject.getStr("name")); + assertEquals(Integer.valueOf(35), jsonObject.getInt("age")); final JSONObject json = JSONUtil.ofObj() .set("name", "张三") .set("age", 35); final BeanWithAlias bean = JSONUtil.toBean(Objects.requireNonNull(json).toString(), BeanWithAlias.class); - Assertions.assertEquals("张三", bean.getValue1()); - Assertions.assertEquals(Integer.valueOf(35), bean.getValue2()); + assertEquals("张三", bean.getValue1()); + assertEquals(Integer.valueOf(35), bean.getValue2()); } @Test @@ -452,7 +455,7 @@ public class JSONObjectTest { json.append("date", DateUtil.parse("2020-06-05 11:16:11")); json.append("bbb", "222"); json.append("aaa", "123"); - Assertions.assertEquals("{\"date\":\"2020-06-05 11:16:11\",\"bbb\":\"222\",\"aaa\":\"123\"}", json.toString()); + assertEquals("{\"date\":\"2020-06-05 11:16:11\",\"bbb\":\"222\",\"aaa\":\"123\"}", json.toString()); } @Test @@ -468,11 +471,11 @@ public class JSONObjectTest { final String jsonStr = "{\"date\":\"2020#06#05\",\"bbb\":\"222\",\"aaa\":\"123\"}"; - Assertions.assertEquals(jsonStr, json.toString()); + assertEquals(jsonStr, json.toString()); // 解析测试 final JSONObject parse = JSONUtil.parseObj(jsonStr, jsonConfig); - Assertions.assertEquals(DateUtil.beginOfDay(date), parse.getDate("date")); + assertEquals(DateUtil.beginOfDay(date), parse.getDate("date")); } @Test @@ -484,11 +487,11 @@ public class JSONObjectTest { final JSONObject json = new JSONObject(jsonConfig); json.set("date", date); - Assertions.assertEquals("{\"date\":1591326971}", json.toString()); + assertEquals("{\"date\":1591326971}", json.toString()); // 解析测试 final JSONObject parse = JSONUtil.parseObj(json.toString(), jsonConfig); - Assertions.assertEquals(date, DateUtil.date(parse.getDate("date"))); + assertEquals(date, DateUtil.date(parse.getDate("date"))); } @Test @@ -504,11 +507,11 @@ public class JSONObjectTest { final String jsonStr = "{\"date\":1591326971,\"bbb\":\"222\",\"aaa\":\"123\"}"; - Assertions.assertEquals(jsonStr, json.toString()); + assertEquals(jsonStr, json.toString()); // 解析测试 final JSONObject parse = JSONUtil.parseObj(jsonStr, jsonConfig); - Assertions.assertEquals(date, parse.getDate("date")); + assertEquals(date, parse.getDate("date")); } @Test @@ -516,7 +519,7 @@ public class JSONObjectTest { final String timeStr = "1970-01-01 00:00:00"; final JSONObject jsonObject = JSONUtil.ofObj().set("time", timeStr); final Timestamp time = jsonObject.get("time", Timestamp.class); - Assertions.assertEquals("1970-01-01 00:00:00.0", time.toString()); + assertEquals("1970-01-01 00:00:00.0", time.toString()); } public enum TestEnum { @@ -561,11 +564,11 @@ public class JSONObjectTest { public void parseBeanSameNameTest() { final SameNameBean sameNameBean = new SameNameBean(); final JSONObject parse = JSONUtil.parseObj(sameNameBean); - Assertions.assertEquals("123", parse.getStr("username")); - Assertions.assertEquals("abc", parse.getStr("userName")); + assertEquals("123", parse.getStr("username")); + assertEquals("abc", parse.getStr("userName")); // 测试ignore注解是否有效 - Assertions.assertNull(parse.getStr("fieldToIgnore")); + assertNull(parse.getStr("fieldToIgnore")); } /** @@ -601,7 +604,7 @@ public class JSONObjectTest { final Map.Entry next = entries.iterator().next(); final JSONObject jsonObject = JSONUtil.parseObj(next); - Assertions.assertEquals("{\"test\":\"testValue\"}", jsonObject.toString()); + assertEquals("{\"test\":\"testValue\"}", jsonObject.toString()); } @Test @@ -618,26 +621,26 @@ public class JSONObjectTest { map.put("c", 2.0F); final String s = JSONUtil.toJsonStr(map); - Assertions.assertEquals("{\"c\":2}", s); + assertEquals("{\"c\":2}", s); } @Test public void appendTest() { final JSONObject jsonObject = JSONUtil.ofObj().append("key1", "value1"); - Assertions.assertEquals("{\"key1\":\"value1\"}", jsonObject.toString()); + assertEquals("{\"key1\":\"value1\"}", jsonObject.toString()); jsonObject.append("key1", "value2"); - Assertions.assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString()); + assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString()); jsonObject.append("key1", "value3"); - Assertions.assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString()); + assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString()); } @Test public void putByPathTest() { final JSONObject json = new JSONObject(); json.putByPath("aa.bb", "BB"); - Assertions.assertEquals("{\"aa\":{\"bb\":\"BB\"}}", json.toString()); + assertEquals("{\"aa\":{\"bb\":\"BB\"}}", json.toString()); } @@ -645,7 +648,7 @@ public class JSONObjectTest { public void bigDecimalTest() { final String jsonStr = "{\"orderId\":\"1704747698891333662002277\"}"; final BigDecimalBean bigDecimalBean = JSONUtil.toBean(jsonStr, BigDecimalBean.class); - Assertions.assertEquals("{\"orderId\":1704747698891333662002277}", JSONUtil.toJsonStr(bigDecimalBean)); + assertEquals("{\"orderId\":1704747698891333662002277}", JSONUtil.toJsonStr(bigDecimalBean)); } @Data @@ -663,7 +666,7 @@ public class JSONObjectTest { .set("d", true); final String s = json1.toJSONString(0, (pair) -> pair.getKey().equals("b")); - Assertions.assertEquals("{\"b\":\"value2\"}", s); + assertEquals("{\"b\":\"value2\"}", s); } @Test @@ -675,7 +678,7 @@ public class JSONObjectTest { .set("d", true); final String s = json1.toJSONString(0, (pair) -> !pair.getKey().equals("b")); - Assertions.assertEquals("{\"a\":\"value1\",\"c\":\"value3\",\"d\":true}", s); + assertEquals("{\"a\":\"value1\",\"c\":\"value3\",\"d\":true}", s); } @Test @@ -695,7 +698,7 @@ public class JSONObjectTest { // 除了"b",其他都去掉 return false; }); - Assertions.assertEquals("{\"b\":\"value2_edit\"}", s); + assertEquals("{\"b\":\"value2_edit\"}", s); } @Test @@ -710,7 +713,7 @@ public class JSONObjectTest { pair.setKey(StrUtil.toUnderlineCase((String)pair.getKey())); return true; }); - Assertions.assertEquals("{\"a_key\":\"value1\",\"b_job\":\"value2\",\"c_good\":\"value3\",\"d\":true}", s); + assertEquals("{\"a_key\":\"value1\",\"b_job\":\"value2\",\"c_good\":\"value3\",\"d\":true}", s); } @Test @@ -723,7 +726,7 @@ public class JSONObjectTest { pair.setValue(ObjUtil.defaultIfNull(pair.getValue(), StrUtil.EMPTY)); return true; }); - Assertions.assertEquals("{\"a\":\"\",\"b\":\"value2\"}", s); + assertEquals("{\"a\":\"\",\"b\":\"value2\"}", s); } @Test @@ -731,8 +734,8 @@ public class JSONObjectTest { final String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\", \"d\": true, \"e\": null}"; //noinspection MismatchedQueryAndUpdateOfCollection final JSONObject jsonObject = JSONUtil.parseObj(jsonStr, null, (pair)-> "b".equals(pair.getKey())); - Assertions.assertEquals(1, jsonObject.size()); - Assertions.assertEquals("value2", jsonObject.getObj("b")); + assertEquals(1, jsonObject.size()); + assertEquals("value2", jsonObject.getObj("b")); } @Test @@ -746,6 +749,6 @@ public class JSONObjectTest { } return true; }); - Assertions.assertEquals("value2_edit", jsonObject.getObj("b")); + assertEquals("value2_edit", jsonObject.getObj("b")); } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONTokenerTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONTokenerTest.java index 6b31e854f..0b098d4b5 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONTokenerTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONTokenerTest.java @@ -18,7 +18,6 @@ package org.dromara.hutool.json; import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.resource.ResourceUtil; -import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.json.reader.JSONTokener; import org.junit.jupiter.api.Test; @@ -30,7 +29,7 @@ public class JSONTokenerTest { void parseTest() { final JSONObject jsonObject = JSONUtil.parseObj(ResourceUtil.getUtf8Reader("issue1200.json")); assertNotNull(jsonObject); - Console.log(jsonObject.toStringPretty()); + //Console.log(jsonObject.toStringPretty()); } @Test diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java index 2e2576684..c9975a6db 100755 --- a/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test; public class JsonToBeanTest { @Test - void toBeanTest() { + void toKotlinBeanTest() { final String jsonStr = "{\"code\": \"201\", \"status\": \"ok\"}"; final ERPProduct bean = JSONUtil.toBean(jsonStr, ERPProduct.class); Assertions.assertNotNull(bean); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java index a96a96e07..d8b7a7191 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java @@ -16,7 +16,9 @@ package org.dromara.hutool.json.reader; +import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.json.JSON; +import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONObject; import org.junit.jupiter.api.Assertions; @@ -36,4 +38,14 @@ public class JSONParserTest { final String jsonStr = "{\"a\": 1}"; JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of()).parseTo(new JSONObject()); } + + @Test + void parseArrayTest() { + final String jsonStr = "[{},2,3]"; + final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of()); + final JSONArray jsonArray = new JSONArray(); + jsonParser.parseTo(jsonArray); + + Console.log(jsonArray); + } }