This commit is contained in:
Looly
2024-09-24 00:35:58 +08:00
parent 4afb8c581e
commit 1b92f58bae
32 changed files with 554 additions and 374 deletions

View File

@@ -21,7 +21,7 @@ import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.json.serializer.JSONDeserializer;
import org.dromara.hutool.json.serializer.JSONMapper;
import org.dromara.hutool.json.serializer.TypeAdapterManager;
import org.dromara.hutool.json.support.JSONNodeBeanCreator;
import org.dromara.hutool.json.support.JSONNodeBeanFactory;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.Serializable;
@@ -139,7 +139,7 @@ public interface JSON extends Serializable {
* @param value 值
*/
default void putByPath(final String expression, final Object value) {
BeanPath.of(expression).setBeanCreator(new JSONNodeBeanCreator(config())).setValue(this, value);
BeanPath.of(expression, new JSONNodeBeanFactory(config())).setValue(this, value);
}
/**

View File

@@ -84,6 +84,43 @@ public class JSONUtil {
public static JSONArray ofArray(final JSONConfig config) {
return new JSONArray(config);
}
/**
* 创建JSONPrimitive对象用于创建非JSON对象例如
* <pre>{@code
* JSONUtil.ofPrimitive(1);
* JSONUtil.ofPrimitive(1L);
* JSONUtil.ofPrimitive(1.0);
* JSONUtil.ofPrimitive(true);
* JSONUtil.ofPrimitive("str");
* }</pre>
*
* @param value 值
* @return JSONPrimitive对象
* @since 6.0.0
*/
public static JSONPrimitive ofPrimitive(final Object value) {
return ofPrimitive(value, JSONConfig.of());
}
/**
* 创建JSONPrimitive对象用于创建非JSON对象例如
* <pre>{@code
* JSONUtil.ofPrimitive(1, config);
* JSONUtil.ofPrimitive(1L, config);
* JSONUtil.ofPrimitive(1.0, config);
* JSONUtil.ofPrimitive(true, config);
* JSONUtil.ofPrimitive("str", config);
* }</pre>
*
* @param value 值
* @param config 配置
* @return JSONPrimitive对象
* @since 6.0.0
*/
public static JSONPrimitive ofPrimitive(final Object value, final JSONConfig config) {
return new JSONPrimitive(value, config);
}
// endregion
// region ----- parse
@@ -121,7 +158,7 @@ public class JSONUtil {
* @return JSONObject
*/
public static JSONObject parseObj(Object obj, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
if(obj instanceof byte[]){
if (obj instanceof byte[]) {
obj = new ByteArrayInputStream((byte[]) obj);
}
return (JSONObject) parse(obj, config, predicate);
@@ -155,12 +192,12 @@ public class JSONUtil {
*
* @param arrayOrCollection 数组或集合对象
* @param config JSON配置
* @param predicate index和值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}为{@code true}保留
* @param predicate index和值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}为{@code true}保留
* @return JSONArray
* @since 5.3.1
*/
public static JSONArray parseArray(final Object arrayOrCollection, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
if(arrayOrCollection instanceof JSONObject){
if (arrayOrCollection instanceof JSONObject) {
final JSONMapper jsonMapper = JSONMapper.of(config, predicate);
return jsonMapper.mapFromJSONObject((JSONObject) arrayOrCollection);
}
@@ -192,8 +229,8 @@ public class JSONUtil {
* <li>Bean对象转为JSONObject</li>
* </ul>
*
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @param obj 对象
* @param config JSON配置{@code null}使用默认配置
* @return JSONJSONObject or JSONArray
*/
public static JSON parse(final Object obj, final JSONConfig config) {

View File

@@ -17,8 +17,7 @@
package org.dromara.hutool.json.serializer;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.*;
/**
* JSON序列化上下文用于获取当前JSON对象以便在序列化过程中获取配置信息
@@ -43,4 +42,45 @@ public interface JSONContext {
default JSONConfig config() {
return ObjUtil.apply(getContextJson(), JSON::config);
}
/**
* 获取当前JSON对象如果为非JSONObject则创建一个JSONObject对象
*
* @return JSON对象
*/
default JSONObject getOrCreateObj() {
final JSON contextJson = getContextJson();
if (contextJson instanceof JSONObject) {
return (JSONObject) contextJson;
}
return JSONUtil.ofObj(config());
}
/**
* 获取当前JSON对象如果为非JSONArray则创建一个JSONArray对象
*
* @return JSON对象
*/
default JSONArray getOrCreateArray() {
final JSON contextJson = getContextJson();
if (contextJson instanceof JSONArray) {
return (JSONArray) contextJson;
}
return JSONUtil.ofArray(config());
}
/**
* 获取当前JSON对象如果为非JSONPrimitive则创建一个JSONPrimitive对象
*
* @param value 值
* @return JSON对象
*/
default JSONPrimitive getOrCreatePrimitive(final Object value) {
final JSON contextJson = getContextJson();
if (contextJson instanceof JSONPrimitive) {
return ((JSONPrimitive) contextJson).setValue(value);
}
return JSONUtil.ofPrimitive(value, config());
}
}

View File

@@ -95,13 +95,7 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJ
// https://github.com/dromara/hutool/issues/2369
// 非标准的二进制流,则按照普通数组对待
final JSONArray result;
final JSON contextJson = context.getContextJson();
if (contextJson instanceof JSONArray) {
result = (JSONArray) contextJson;
} else {
result = JSONUtil.ofArray(config);
}
final JSONArray result = context.getOrCreateArray();
for (final byte b : bytes) {
result.set(b);
}

View File

@@ -60,10 +60,7 @@ public class BeanTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJS
@Override
public JSON serialize(final Object bean, final JSONContext context) {
JSONObject contextJson = (JSONObject) ObjUtil.apply(context, JSONContext::getContextJson);
if(null == contextJson){
contextJson = new JSONObject(context.config());
}
final JSONObject contextJson = context.getOrCreateObj();
final BeanToMapCopier copier = new BeanToMapCopier(
bean,

View File

@@ -57,10 +57,7 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
final String jsonStr = StrUtil.trim(bean);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
JSONObject jsonObject = (JSONObject) context.getContextJson();
if(null == jsonObject){
jsonObject = JSONUtil.ofObj(context.config());
}
final JSONObject jsonObject = context.getOrCreateObj();
JSONXMLParser.of(ParseConfig.of(), null).parseJSONObject(jsonStr, jsonObject);
return jsonObject;
}

View File

@@ -22,7 +22,6 @@ 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;
@@ -59,15 +58,8 @@ public class EntryTypeAdapter implements MatcherJSONSerializer<Map.Entry<?, ?>>,
@Override
public JSON serialize(final Map.Entry<?, ?> 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;
return context.getOrCreateObj()
.set(ConvertUtil.toStr(bean.getKey()), bean.getValue());
}
@Override

View File

@@ -19,11 +19,9 @@ package org.dromara.hutool.json.serializer.impl;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.MapWrapper;
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;
@@ -72,10 +70,7 @@ public class IterTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJS
iter = ((Iterable<?>) bean).iterator();
}
JSONArray json = (JSONArray) context.getContextJson();
if(null == json){
json = JSONUtil.ofArray(ObjUtil.apply(context, JSONContext::config));
}
final JSONArray json = context.getOrCreateArray();
mapFromIterator(bean, iter, json);
return json;
}

View File

@@ -58,13 +58,7 @@ public class JSONPrimitiveTypeAdapter implements MatcherJSONSerializer<Object>,
bean = bean.toString();
}
final JSONPrimitive json = (JSONPrimitive) context.getContextJson();
if (null != json) {
json.setValue(bean);
return json;
}
return new JSONPrimitive(bean, context.config());
return context.getOrCreatePrimitive(bean);
}
@Override

View File

@@ -23,7 +23,6 @@ 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;
@@ -61,10 +60,7 @@ public class MapTypeAdapter implements MatcherJSONSerializer<Map<?, ?>>, Matcher
@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());
final JSONObject result = context.getOrCreateObj();
// 注入键值对
for (final Map.Entry<?, ?> e : bean.entrySet()) {
result.set(ConvertUtil.toStr(e.getKey()), e.getValue());

View File

@@ -48,15 +48,7 @@ public class ResourceBundleSerializer implements MatcherJSONSerializer<ResourceB
@Override
public JSON serialize(final ResourceBundle bean, final JSONContext context) {
final JSONObject result;
final JSON json = context.getContextJson();
if (json instanceof JSONObject) {
result = (JSONObject) json;
} else {
result = JSONUtil.ofObj(context.config());
}
final JSONObject result = context.getOrCreateObj();
mapFromResourceBundle(bean, result);
return result;
}

View File

@@ -70,23 +70,22 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer<TemporalAccess
@Override
public JSON serialize(final TemporalAccessor bean, final JSONContext context) {
final JSONConfig config = context.config();
// 如果上下文为JSONObject转为键值对形式
final JSON contextJson = context.getContextJson();
if(contextJson instanceof JSONObject){
if (contextJson instanceof JSONObject) {
toJSONObject(bean, contextJson.asJSONObject());
return contextJson;
}
if (bean instanceof Month) {
return new JSONPrimitive(((Month) bean).getValue(), config);
return context.getOrCreatePrimitive(((Month) bean).getValue());
} else if (bean instanceof DayOfWeek) {
return new JSONPrimitive(((DayOfWeek) bean).getValue(), config);
return context.getOrCreatePrimitive(((DayOfWeek) bean).getValue());
} else if (bean instanceof MonthDay) {
return new JSONPrimitive(((MonthDay) bean).toString(), config);
return context.getOrCreatePrimitive(((MonthDay) bean).toString());
}
final String format = ObjUtil.apply(config, JSONConfig::getDateFormat);
final String format = ObjUtil.apply(context.config(), JSONConfig::getDateFormat);
final Object value;
// 默认为时间戳
@@ -98,7 +97,7 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer<TemporalAccess
value = TimeUtil.format(bean, format);
}
return new JSONPrimitive(value, config);
return context.getOrCreatePrimitive(value);
}
@Override
@@ -130,7 +129,7 @@ public class TemporalTypeAdapter implements MatcherJSONSerializer<TemporalAccess
/**
* 将{@link TemporalAccessor}转换为JSONObject
*
* @param bean {@link TemporalAccessor}
* @param bean {@link TemporalAccessor}
* @param json JSONObject
*/
private static void toJSONObject(final TemporalAccessor bean, final JSONObject json) {

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.json.support;
import org.dromara.hutool.core.bean.path.BeanPath;
import org.dromara.hutool.core.bean.path.NodeBeanCreator;
import org.dromara.hutool.core.bean.path.node.NameNode;
import org.dromara.hutool.core.bean.path.node.Node;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONUtil;
/**
* JSON节点Bean创建器
*
* @author looly
* @since 6.0.0
*/
public class JSONNodeBeanCreator implements NodeBeanCreator {
private final JSONConfig config;
/**
* 构造
*
* @param config JSON配置
*/
public JSONNodeBeanCreator(final JSONConfig config) {
this.config = config;
}
@Override
public Object create(final Object parent, final BeanPath beanPath) {
final BeanPath next = beanPath.next();
if (null != next) {
final Node node = next.getNode();
if (node instanceof NameNode) {
final NameNode nameNode = (NameNode) node;
if (nameNode.isNumber()) {
return JSONUtil.ofArray(config);
}
return JSONUtil.ofObj(config);
}
}
return JSONUtil.ofObj(config);
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.support;
import org.dromara.hutool.core.bean.path.BeanPath;
import org.dromara.hutool.core.bean.path.NodeBeanFactory;
import org.dromara.hutool.core.bean.path.node.*;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.json.*;
/**
* JSON节点Bean创建器
*
* @author looly
* @since 6.0.0
*/
public class JSONNodeBeanFactory implements NodeBeanFactory<JSON> {
private final JSONConfig config;
/**
* 构造
*
* @param config JSON配置
*/
public JSONNodeBeanFactory(final JSONConfig config) {
this.config = config;
}
@Override
public JSON create(final JSON parent, final BeanPath<JSON> beanPath) {
final BeanPath<JSON> next = beanPath.next();
if (null != next) {
final Node node = next.getNode();
if (node instanceof NameNode) {
final NameNode nameNode = (NameNode) node;
if (nameNode.isNumber()) {
return JSONUtil.ofArray(config);
}
return JSONUtil.ofObj(config);
}
}
return JSONUtil.ofObj(config);
}
@Override
public Object getValue(final JSON bean, final BeanPath<JSON> beanPath) {
final Node node = beanPath.getNode();
if (null == node || node instanceof EmptyNode) {
return null;
} else if (node instanceof ListNode) {
return getValueByListNode(bean, (ListNode) node);
} else if (node instanceof NameNode) {
return getValueByNameNode(bean, (NameNode) node);
} else if (node instanceof RangeNode) {
return getValueByRangeNode(bean, (RangeNode) node);
}
throw new UnsupportedOperationException("Unsupported node type: " + node.getClass());
}
@Override
public JSON setValue(final JSON bean, final Object value, final BeanPath<JSON> beanPath) {
final Node node = beanPath.getNode();
if (node instanceof EmptyNode) {
return bean;
} else if (node instanceof NameNode) {
if(bean instanceof JSONObject){
((JSONObject) bean).set(((NameNode) node).getName(), value);
} else if(bean instanceof JSONArray){
((JSONArray) bean).setValue(Integer.parseInt(((NameNode) node).getName()), value);
}
return bean;
}
throw new UnsupportedOperationException("Unsupported node type: " + node.getClass());
}
/**
* 获取指定下标的值<br>
* 如果Bean为JSONArray则返回指定下标数组的值如果Bean为JSONObject则返回指定key数组的值
*
* @param bean Bean
* @param node 下标节点
* @return 值
*/
private Object getValueByListNode(final JSON bean, final ListNode node) {
final String[] names = node.getUnWrappedNames();
if (bean instanceof JSONArray) {
return CollUtil.getAny((JSONArray) bean, ConvertUtil.convert(int[].class, names));
} else if (bean instanceof JSONObject) {
MapUtil.getAny((JSONObject) bean, names);
}
throw new UnsupportedOperationException("Can not get by list for: " + bean.getClass());
}
/**
* 获取指定key的值<br>
* 如果Bean为JSONObject则返回指定key的值如果Bean为JSONArray则返回指定下标数组的值
*
* @param bean Bean
* @param node key节点
* @return 值
*/
private Object getValueByNameNode(final JSON bean, final NameNode node) {
final String name = node.getName();
if ("$".equals(name)) {
return bean;
}
if (bean instanceof JSONObject) {
return ((JSONObject) bean).get(name);
} else if (bean instanceof JSONArray) {
return ((JSONArray) bean).get(Integer.parseInt(name));
}
throw new UnsupportedOperationException("Can not get by name for: " + bean.getClass());
}
/**
* 获取指定下标范围的值<br>
* 如果Bean为JSONArray则返回指定下标范围的值
*
* @param bean Bean
* @param node 下标range节点
* @return 值
*/
private Object getValueByRangeNode(final JSON bean, final RangeNode node) {
if (bean instanceof JSONArray) {
return CollUtil.sub((JSONArray) bean, node.getStart(), node.getEnd(), node.getStep());
}
throw new UnsupportedOperationException("Can not get range value for: " + bean.getClass());
}
}

View File

@@ -33,10 +33,7 @@ public class CustomSerializeTest {
public void init() {
TypeAdapterManager.getInstance().register(CustomBean.class,
(JSONSerializer<CustomBean>) (bean, context) ->{
JSONObject contextJson = (JSONObject) context.getContextJson();
if(null == contextJson){
contextJson = JSONUtil.ofObj(context.config());
}
final JSONObject contextJson = context.getOrCreateObj();
return contextJson.set("customName", bean.name);
});
}

View File

@@ -57,7 +57,7 @@ public class Issue2555Test {
public static class MySerializer implements JSONSerializer<MyType> {
@Override
public JSON serialize(final MyType bean, final JSONContext context) {
return ((JSONObject)context.getContextJson()).set("addr", bean.getAddress());
return context.getOrCreateObj().set("addr", bean.getAddress());
}
}

View File

@@ -70,12 +70,7 @@ public class Issue3086Test {
public JSON serialize(final TestBean bean, final JSONContext context) {
final List<String> strings = bean.getAuthorities()
.stream().map(SimpleGrantedAuthority::getAuthority).collect(Collectors.toList());
JSONObject contextJson = (JSONObject) context.getContextJson();
if(null == contextJson){
contextJson = new JSONObject(context.config());
}
contextJson.set("authorities",strings);
return contextJson;
return context.getOrCreateObj().set("authorities",strings);
}
}
}