add methods

This commit is contained in:
Looly 2024-10-01 22:14:02 +08:00
parent 64a04fdfd1
commit 463d8d9c6f
10 changed files with 191 additions and 71 deletions

View File

@ -117,7 +117,7 @@ public final class InternalJSONUtil {
.setIgnoreError(config.isIgnoreError())
.setIgnoreNullValue(config.isIgnoreNullValue())
.setTransientSupport(config.isTransientSupport())
.setConverter((targetType, value) -> mapper.toJSON(value));
.setConverter((targetType, value) -> mapper.toJSON(value, false));
}
/**

View File

@ -120,7 +120,8 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
* @return this.
*/
public JSONArray addObj(final Object value) {
this.add(this.factory.getMapper().toJSON(value));
// add时如果value为字符串不解析而是作为JSONPrimitive对待
this.add(this.factory.getMapper().toJSON(value, false));
return this;
}
@ -171,7 +172,8 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
* @return this
*/
public JSONArray setObj(final int index, final Object element) {
set(index, this.factory.getMapper().toJSON(element));
// set时如果value为字符串不解析而是作为JSONPrimitive对待
set(index, this.factory.getMapper().toJSON(element, false));
return this;
}

View File

@ -267,7 +267,12 @@ public class JSONFactory {
// region ----- parse
/**
* 对象转JSONObject对象
* 对象转{@link JSONObject}支持
* <ul>
* <li>{@link CharSequence}解析{...}字符串</li>
* <li>Bean解析</li>
* <li>Map解析</li>
* </ul>
*
* @param obj Bean对象或者Map
* @return JSONObject
@ -292,23 +297,37 @@ public class JSONFactory {
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 解析对象为JSON<br>
* 支持的对象
* <ul>
* <li>String: 转换为相应的对象</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* </ul>
* 注意{@link #toJSON(Object)}不同的是对象如果为字符串会被当作json字符串解析
*
* @param obj 对象
* @return JSONJSONObject or JSONArray
*/
public JSON parse(final Object obj) {
final JSONMapper mapper = this.getMapper();
if (obj instanceof CharSequence) {
return mapper.toJSON((CharSequence) obj);
return getMapper().toJSON(obj, true);
}
return mapper.toJSON(obj);
/**
* 转换对象为JSON<br>
* 支持的对象
* <ul>
* <li>String: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* </ul>
* 注意{@link #parse(Object)}不同的是对象如果为字符串则返回{@link JSONPrimitive}不会做二次解析
*
* @param obj 对象
* @return JSONJSONObject or JSONArray
*/
public JSON toJSON(final Object obj) {
return getMapper().toJSON(obj, false);
}
// endregion

View File

@ -233,7 +233,8 @@ public class JSONObject extends MapWrapper<String, JSON> implements JSON, JSONGe
* @throws JSONException 值是无穷数字抛出此异常
*/
public JSONObject putObj(final String key, final Object value) throws JSONException {
this.put(key, factory.getMapper().toJSON(value));
// put时如果value为字符串不解析而是作为JSONPrimitive对待
this.put(key, factory.getMapper().toJSON(value, false));
return this;
}

View File

@ -195,12 +195,12 @@ public class JSONUtil {
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* 解析对象为JSON持的对象
* <ul>
* <li>String: 转换为相应的对象</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* <li>String: 解析为相应的对象</li>
* <li>Numberboolean: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
@ -211,45 +211,46 @@ public class JSONUtil {
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* 解析对象为JSON持的对象
* <ul>
* <li>String: 转换为相应的对象</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* <li>String: 解析为相应的对象</li>
* <li>Numberboolean: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @return JSONJSONObject or JSONArray
* @return JSON
*/
public static JSON parse(final Object obj, final JSONConfig config) {
return parse(obj, config, null);
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* 解析对象为JSON持的对象
* <ul>
* <li>String: 转换为相应的对象</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* <li>String: 解析为相应的对象</li>
* <li>Numberboolean: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return JSONJSONObject or JSONArray
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作
* {@link Predicate#test(Object)}{@code true}保留
* @return JSON
*/
public static JSON parse(final Object obj, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
return JSONFactory.of(config, predicate).parse(obj);
}
/**
* XML字符串转为JSONObject
* XML字符串解析为{@link JSONObject}
*
* @param xmlStr XML字符串
* @return JSONObject
* @return {@link JSONObject}
*/
public static JSONObject parseFromXml(final String xmlStr) {
return JSONXMLUtil.toJSONObject(xmlStr);
@ -418,7 +419,62 @@ public class JSONUtil {
}
// endregion
// region ----- toJSON
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* <ul>
* <li>booleanNumberString: 转换为{@link JSONPrimitive}/li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
* @return JSON
*/
public static JSON toJSON(final Object obj) {
return JSONFactory.getInstance().toJSON(obj);
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* <ul>
* <li>booleanNumberString: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @return JSON
*/
public static JSON toJSON(final Object obj, final JSONConfig config) {
return toJSON(obj, config, null);
}
/**
* 转换对象为JSON如果用户不配置JSONConfig则JSON的有序与否与传入对象有关<br>
* 支持的对象
* <ul>
* <li>booleanNumberString: 转换为{@link JSONPrimitive}</li>
* <li>ArrayIterableIterator转换为{@link JSONArray}</li>
* <li>Bean对象转为{@link JSONObject}</li>
* </ul>
*
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return JSON
*/
public static JSON toJSON(final Object obj, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
return JSONFactory.of(config, predicate).toJSON(obj);
}
// endregion
// region ----- toList
/**
* 将JSONArray字符串转换为Bean的List默认为ArrayList
*
@ -601,6 +657,7 @@ public class JSONUtil {
}
// region ----- isType
/**
* 是否为JSON类型字符串首尾都为大括号或中括号判定为JSON字符串
*
@ -642,6 +699,7 @@ public class JSONUtil {
// endregion
// region ----- registerTypeAdapter
/**
* 全局注册自定义类型适配器用于自定义对象序列化和反序列化
*

View File

@ -20,6 +20,7 @@ import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.*;
import org.dromara.hutool.json.serializer.impl.CharSequenceTypeAdapter;
import org.dromara.hutool.json.serializer.impl.DefaultDeserializer;
import java.io.Serializable;
@ -29,7 +30,7 @@ import java.util.Optional;
/**
* 对象和JSON值映射器用于Java对象和JSON对象互转<br>
* <ul>
* <li>Java对象转JSON{@link #toJSON(Object)}</li>
* <li>Java对象转JSON{@link #toJSON(Object, boolean)}</li>
* <li>JSON转Java对象{@link #toBean(JSON, Type)}</li>
* </ul>
* <p>
@ -139,22 +140,23 @@ public class JSONMapper implements Serializable {
}
// region ----- toJSON
/**
* 在需要的时候转换映射对象<br>
* 包装包括
* <ul>
* <li>array or collection = JSONArray</li>
* <li>map = JSONObject</li>
* <li>standard property (Double, String, et al) = 原对象</li>
* <li>array or collection = {@link JSONArray}</li>
* <li>map or bean = {@link JSONObject}</li>
* <li>standard property (number boolean or char) = {@link JSONPrimitive}</li>
* <li>String = parseIfString为{@code true}时解析为{@link JSON}{@code false}直接包装为{@link JSONPrimitive}</li>
* <li>其它 = 尝试包装为JSONObject否则返回{@code null}</li>
* </ul>
*
* @param obj 被映射的对象
* @param parseIfString 如果提供的是字符串是否解析为JSON{@code false}则直接包装为{@link JSONPrimitive}
* @return 映射后的值null表示此值需被忽略
*/
public JSON toJSON(final Object obj) {
return mapTo(obj, null);
public JSON toJSON(final Object obj, final boolean parseIfString) {
return mapTo(obj, null, parseIfString);
}
/**
@ -169,7 +171,7 @@ public class JSONMapper implements Serializable {
* @return 映射后的值null表示此值需被忽略
*/
public JSONObject toJSONObject(final Object obj) {
return mapTo(obj, factory.ofObj());
return mapTo(obj, factory.ofObj(), false);
}
/**
@ -183,7 +185,7 @@ public class JSONMapper implements Serializable {
* @return 映射后的值null表示此值需被忽略
*/
public JSONArray toJSONArray(final Object obj) {
return mapTo(obj, factory.ofArray());
return mapTo(obj, factory.ofArray(), false);
}
// endregion
@ -191,19 +193,22 @@ public class JSONMapper implements Serializable {
* 在需要的时候转换映射对象<br>
* 包装包括
* <ul>
* <li>array or collection = JSONArray</li>
* <li>map = JSONObject</li>
* <li>standard property (Double, String, et al) = 原对象</li>
* <li>array or collection = {@link JSONArray}</li>
* <li>map or bean = {@link JSONObject}</li>
* <li>standard property (number boolean or char) = {@link JSONPrimitive}</li>
* <li>String = parseIfString为{@code true}时解析为{@link JSON}{@code false}直接包装为{@link JSONPrimitive}</li>
* <li>其它 = 尝试包装为JSONObject否则返回{@code null}</li>
* </ul>
*
* @param obj 被映射的对象
* @param json 被映射的到的对象{@code null}表示根据序列化器自动识别
* @param parseIfString 如果提供的是字符串是否解析为JSON{@code false}则直接包装为{@link JSONPrimitive},
* 只有json参数为{@code null}时有效
* @param <T> JSON类型
* @return 映射后的值null表示此值需被忽略
*/
@SuppressWarnings({"unchecked"})
private <T extends JSON> T mapTo(Object obj, final T json) {
private <T extends JSON> T mapTo(Object obj, final T json, final boolean parseIfString) {
if (null == obj) {
return null;
}
@ -224,9 +229,19 @@ public class JSONMapper implements Serializable {
// 考虑性能问题默认原始类型对象直接包装为JSONPrimitive不再查找TypeAdapter
// 如果原始类型想转为其他JSON类型依旧可以查找TypeAdapter
if (JSONPrimitive.isTypeForJSONPrimitive(obj)) {
if (null == json || json instanceof JSONPrimitive) {
if (null == json) {
// 未指定转换的JSON类型对于String产生二义性
// 通过parseIfString参数决定是解析字符串还是直接转为原始类型
if (parseIfString && obj instanceof String) {
return (T) CharSequenceTypeAdapter.INSTANCE.serialize((String)obj,
new SimpleJSONContext(null, factory));
}
return (T) factory.ofPrimitive(obj);
}
if (json instanceof JSONPrimitive) {
return (T) factory.ofPrimitive(obj);
}
// 用户想将Primitive对象转为特定JSON对象则需要查找TypeAdapter
}
// JSON对象如果与预期结果类型一致则直接返回

View File

@ -19,7 +19,6 @@ 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.JSON;
import org.dromara.hutool.json.JSONFactory;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONPrimitive;
import org.dromara.hutool.json.reader.JSONTokener;
@ -86,7 +85,7 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
}
// 按照JSON字符串解析
return parse(new JSONTokener(jsonStr), context.getFactory());
return context.getFactory().ofParser(new JSONTokener(jsonStr)).parse();
}
@Override
@ -96,15 +95,4 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
}
return json.toString();
}
/**
* {@link JSONTokener} 中读取JSON字符串并解析为JSON
*
* @param tokener {@link JSONTokener}
* @param factory JSON工厂
* @return JSON
*/
public static JSON parse(final JSONTokener tokener, final JSONFactory factory) {
return factory.ofParser(tokener).parse();
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.json;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class JSONFactoryTest {
@Test
void parseFromStringBuilderTest() {
final String jsonStr = "{\"name\":\"张三\"}";
final JSON parse = JSONFactory.getInstance().parse(new StringBuilder(jsonStr));
Assertions.assertEquals(JSONObject.class, parse.getClass());
}
@Test
void parseFromStringTest() {
final String jsonStr = "{\"name\":\"张三\"}";
final JSON parse = JSONFactory.getInstance().parse(jsonStr);
Assertions.assertEquals(JSONObject.class, parse.getClass());
}
}

View File

@ -31,7 +31,7 @@ public class Issue3681Test {
Assertions.assertEquals("\"abc\"", abc);
abc = JSONUtil.toJsonStr(Optional.of("123"));
Assertions.assertEquals("\"123\"", abc);
Assertions.assertEquals("123", abc);
}
@Test
@ -46,6 +46,7 @@ public class Issue3681Test {
Assertions.assertEquals("\"abc\"", abc);
abc = JSONUtil.toJsonStr(Opt.of("123"));
Assertions.assertEquals("\"123\"", abc);
Assertions.assertEquals("123", abc);
}
}

View File

@ -33,7 +33,7 @@ public class IssueI9DX5HTest {
entry.setKey(StrUtil.toUnderlineCase((CharSequence) entry.getKey()));
return true;
});
final JSONObject jsonObject = (JSONObject) factory.parse(xml);
final JSONObject jsonObject = factory.parseObj(xml);
Assertions.assertEquals("{\"good_msg\":\"你好\"}", jsonObject.toString());
}