mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
ff187f6fde
commit
2872f15e91
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,12 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Bean和JSON之间的映射封装,包括:
|
||||
* <ul>
|
||||
* <li>JSONObjectMapper: 转换对象为JSONObject</li>
|
||||
* <li>JSONArrayMapper: 转换对象为JSONArray</li>
|
||||
* <li>JSONValueMapper: 转换对象为JSON值</li>
|
||||
* </ul>
|
||||
* 标记可读Bean<br>
|
||||
* 即包含有可读字段的Bean使用此注解标记,如含有public的字段或getter方法
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
package org.dromara.hutool.json.mapper;
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface ReadableBean {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.core.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 标记可写Bean<br>
|
||||
* 即包含有可写字段的Bean使用此注解标记,如含有public的字段或setter方法
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface WritableBean {
|
||||
}
|
@ -16,6 +16,9 @@
|
||||
|
||||
package org.dromara.hutool.core.bean;
|
||||
|
||||
import org.dromara.hutool.core.annotation.AnnotationUtil;
|
||||
import org.dromara.hutool.core.annotation.ReadableBean;
|
||||
import org.dromara.hutool.core.annotation.WritableBean;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.copier.BeanCopier;
|
||||
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
||||
@ -687,6 +690,11 @@ public class BeanUtil {
|
||||
// String中有getter方法,但为字符串,不是Bean
|
||||
return false;
|
||||
}
|
||||
|
||||
if(AnnotationUtil.hasAnnotation(clazz, ReadableBean.class)){
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasGetter(clazz) || hasPublicField(clazz);
|
||||
}
|
||||
|
||||
@ -712,6 +720,10 @@ public class BeanUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(AnnotationUtil.hasAnnotation(clazz, WritableBean.class)){
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasSetter(clazz) || hasPublicField(clazz);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public interface ValueProvider<K>{
|
||||
|
||||
/**
|
||||
* 获取值<br>
|
||||
* 返回值一般需要匹配被注入类型,如果不匹配会调用默认转换 Convert#convert(Type, Object)实现转换
|
||||
* 返回值一般需要匹配被注入类型,如果不匹配会调用默认转换 Convert#support(Type, Object)实现转换
|
||||
*
|
||||
* @param key Bean对象中参数名
|
||||
* @param valueType 被注入的值的类型
|
||||
|
@ -17,14 +17,11 @@
|
||||
package org.dromara.hutool.core.bean.path;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.path.node.NameNode;
|
||||
import org.dromara.hutool.core.bean.path.node.Node;
|
||||
import org.dromara.hutool.core.bean.path.node.NodeFactory;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
@ -67,6 +64,7 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
|
||||
private final Node node;
|
||||
private final String child;
|
||||
private NodeBeanCreator beanCreator;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
@ -74,6 +72,7 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
* @param expression 表达式
|
||||
*/
|
||||
public BeanPath(final String expression) {
|
||||
this.beanCreator = DefaultNodeBeanCreator.INSTANCE;
|
||||
final int length = expression.length();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
@ -128,6 +127,17 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Bean创建器,用于创建Bean对象,默认为{@link DefaultNodeBeanCreator}
|
||||
*
|
||||
* @param beanCreator Bean创建器
|
||||
* @return this
|
||||
*/
|
||||
public BeanPath setBeanCreator(final NodeBeanCreator beanCreator) {
|
||||
this.beanCreator = beanCreator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点
|
||||
*
|
||||
@ -189,7 +199,7 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
final BeanPath childBeanPath = next();
|
||||
Object subBean = this.node.getValue(bean);
|
||||
if (null == subBean) {
|
||||
subBean = isListNode(childBeanPath.node) ? new ArrayList<>() : new HashMap<>();
|
||||
subBean = beanCreator.create(bean, this);
|
||||
this.node.setValue(bean, subBean);
|
||||
// 如果自定义put方法修改了value,返回修改后的value,避免值丢失
|
||||
subBean = this.node.getValue(bean);
|
||||
@ -210,17 +220,4 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
", child='" + child + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* 子节点值是否为列表
|
||||
*
|
||||
* @param node 节点
|
||||
* @return 是否为列表
|
||||
*/
|
||||
private static boolean isListNode(final Node node) {
|
||||
if (node instanceof NameNode) {
|
||||
return ((NameNode) node).isNumber();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.core.bean.path;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.path.node.NameNode;
|
||||
import org.dromara.hutool.core.bean.path.node.Node;
|
||||
import org.dromara.hutool.core.reflect.ConstructorUtil;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 默认的Bean创建器
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DefaultNodeBeanCreator implements NodeBeanCreator {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final NodeBeanCreator INSTANCE = new DefaultNodeBeanCreator();
|
||||
|
||||
@Override
|
||||
public Object create(final Object parent, final BeanPath beanPath) {
|
||||
if(parent instanceof Map || parent instanceof List || ArrayUtil.isArray(parent)){
|
||||
// 根据下一个节点类型,判断当前节点名称对应类型
|
||||
final Node node = beanPath.next().getNode();
|
||||
if (node instanceof NameNode) {
|
||||
return ((NameNode) node).isNumber() ? new ArrayList<>() : new HashMap<>();
|
||||
}
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
// 普通Bean
|
||||
final Node node = beanPath.getNode();
|
||||
if(node instanceof NameNode){
|
||||
final String name = ((NameNode) node).getName();
|
||||
|
||||
final Field field = FieldUtil.getField(parent.getClass(), name);
|
||||
if(null == field){
|
||||
throw new IllegalArgumentException("No field found for name: " + name);
|
||||
}
|
||||
return ConstructorUtil.newInstanceIfPossible(field.getType());
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported node type: " + node.getClass());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.core.bean.path;
|
||||
|
||||
/**
|
||||
* BeanPath节点对应的Bean创建器<br>
|
||||
* 用于创建Bean路径节点对应的Bean
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface NodeBeanCreator {
|
||||
|
||||
/**
|
||||
* 创建Bean<br>
|
||||
* beanPath对应当前的路径,即如果父对象为:a,则beanPath为:a.b,则创建的Bean为:a.b.c对应的Bean对象<br>
|
||||
* 给定的a一定存在,但是本路径中b对应的Bean不存在,则创建的对象是b的值,这个值用c表示
|
||||
*
|
||||
* @param parent 父Bean
|
||||
* @param beanPath 当前路径
|
||||
* @return Bean
|
||||
*/
|
||||
Object create(final Object parent, final BeanPath beanPath);
|
||||
}
|
@ -34,6 +34,15 @@ public class NameNode implements Node {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 获取节点名
|
||||
*
|
||||
* @return 节点名
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
|
@ -505,7 +505,7 @@ public class Hashids implements Encoder<long[], String>, Decoder<String, long[]>
|
||||
return IntStream.range(0, separators.length)
|
||||
.mapToObj(idx -> (separators[idx]))
|
||||
.filter(valid::contains)
|
||||
// ugly way to convert back to char[]
|
||||
// ugly way to support back to char[]
|
||||
.map(c -> Character.toString(c))
|
||||
.collect(Collectors.joining())
|
||||
.toCharArray();
|
||||
|
@ -135,7 +135,7 @@ public class PercentCodec implements Encoder<byte[], byte[]>, Serializable {
|
||||
// 对于空格单独处理
|
||||
rewrittenPath.append('+');
|
||||
} else {
|
||||
// convert to external encoding before hex conversion
|
||||
// support to external encoding before hex conversion
|
||||
try {
|
||||
writer.write(c);
|
||||
writer.flush();
|
||||
|
@ -67,7 +67,7 @@ public class Z85Codec implements Encoder<byte[], String>, Decoder<String, byte[]
|
||||
// Support inputs that are not divisible by 4 with no remainder.
|
||||
final int padding = 4 - (remainder == 0 ? 4 : remainder);
|
||||
|
||||
// SPEC: 4 octets convert into 5 printable characters.
|
||||
// SPEC: 4 octets support into 5 printable characters.
|
||||
// char.length = length + 1/4 length == 5/4 length.
|
||||
final char[] chars = new char[length + (length >>> 2) + (remainder == 0 ? 0 : 1)];
|
||||
int idx = 0;
|
||||
|
@ -45,7 +45,7 @@ public abstract class AbstractConverter implements Converter, Serializable {
|
||||
return null;
|
||||
}
|
||||
if (TypeUtil.isUnknown(targetType)) {
|
||||
throw new ConvertException("Unsupported convert to unKnown type: {}", targetType);
|
||||
throw new ConvertException("Unsupported support to unKnown type: {}", targetType);
|
||||
}
|
||||
|
||||
final Class<?> targetClass = TypeUtil.getClass(targetType);
|
||||
|
@ -201,6 +201,6 @@ public class CompositeConverter implements Converter, Serializable {
|
||||
}
|
||||
|
||||
// 无法转换
|
||||
throw new ConvertException("Can not convert from {}: [{}] to [{}]", value.getClass().getName(), value, type.getTypeName());
|
||||
throw new ConvertException("Can not support from {}: [{}] to [{}]", value.getClass().getName(), value, type.getTypeName());
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class RegisterConverter extends ConverterWithRoot implements Serializable
|
||||
}
|
||||
|
||||
// 无法转换
|
||||
throw new ConvertException("Can not convert from {}: [{}] to [{}]", value.getClass().getName(), value, targetType.getTypeName());
|
||||
throw new ConvertException("Can not support from {}: [{}] to [{}]", value.getClass().getName(), value, targetType.getTypeName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +108,7 @@ public class DateConverter extends AbstractConverter implements MatcherConverter
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConvertException("Can not convert {}:[{}] to {}", value.getClass().getName(), value, targetClass.getName());
|
||||
throw new ConvertException("Can not support {}:[{}] to {}", value.getClass().getName(), value, targetClass.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ public class EnumConverter extends AbstractConverter implements MatcherConverter
|
||||
return enumValue;
|
||||
}
|
||||
|
||||
throw new ConvertException("Can not convert {} to {}", value, targetClass);
|
||||
throw new ConvertException("Can not support {} to {}", value, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,7 @@ public class NumberConverter extends AbstractConverter implements MatcherConvert
|
||||
protected String convertToStr(final Object value) {
|
||||
final String result = StrUtil.trim(super.convertToStr(value));
|
||||
if(StrUtil.isEmpty(result)){
|
||||
throw new ConvertException("Can not convert empty value to Number!");
|
||||
throw new ConvertException("Can not support empty value to Number!");
|
||||
}
|
||||
|
||||
if (result.length() > 1) {
|
||||
|
@ -76,7 +76,7 @@ public class PrimitiveConverter extends AbstractConverter implements MatcherConv
|
||||
}
|
||||
|
||||
if(null == result){
|
||||
throw new ConvertException("Can not convert {} to {}", value, primitiveClass);
|
||||
throw new ConvertException("Can not support {} to {}", value, primitiveClass);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -408,7 +408,7 @@ public class FastDateFormat extends Format implements PositionDateParser, DatePr
|
||||
return printer.getMaxLengthEstimate();
|
||||
}
|
||||
|
||||
// convert DateTimeFormatter
|
||||
// support DateTimeFormatter
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -266,7 +266,7 @@ public class Version implements Comparable<Version>, Serializable {
|
||||
}
|
||||
return c;
|
||||
}
|
||||
// Types differ, so convert number to string form
|
||||
// Types differ, so support number to string form
|
||||
final int c = o1.toString().compareTo(o2.toString());
|
||||
if (c == 0){
|
||||
continue;
|
||||
|
@ -329,7 +329,7 @@ public class ConvertTest {
|
||||
|
||||
@Test
|
||||
public void toClassTest(){
|
||||
final Class<?> convert = ConvertUtil.convert(Class.class, "org.dromara.hutool.core.convert.ConvertTest.Product");
|
||||
final Class<?> convert = ConvertUtil.convert(Class.class, "org.dromara.hutool.core.support.ConvertTest.Product");
|
||||
Assertions.assertSame(Product.class, convert);
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ public class ByteUtilTest {
|
||||
final byte[] bytes = new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0x01, (byte) 0x00};
|
||||
final int expectedValue = 130815;
|
||||
final int actualValue = ByteUtil.toInt(bytes, 0, ByteOrder.LITTLE_ENDIAN);
|
||||
assertEquals(expectedValue, actualValue, "Failed to convert bytes to int using LITTLE_ENDIAN");
|
||||
assertEquals(expectedValue, actualValue, "Failed to support bytes to int using LITTLE_ENDIAN");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -228,6 +228,6 @@ public class ByteUtilTest {
|
||||
final byte[] bytes = new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0x01, (byte) 0x00};
|
||||
final int expectedValue = -130816;
|
||||
final int actualValue = ByteUtil.toInt(bytes, 0, ByteOrder.BIG_ENDIAN);
|
||||
assertEquals(expectedValue, actualValue, "Failed to convert bytes to int using BIG_ENDIAN");
|
||||
assertEquals(expectedValue, actualValue, "Failed to support bytes to int using BIG_ENDIAN");
|
||||
}
|
||||
}
|
||||
|
@ -16,24 +16,23 @@
|
||||
|
||||
package org.dromara.hutool.json;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
||||
import org.dromara.hutool.core.codec.binary.HexUtil;
|
||||
import org.dromara.hutool.core.convert.ConvertUtil;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveLinkedMap;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveTreeMap;
|
||||
import org.dromara.hutool.core.math.NumberUtil;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.mapper.JSONValueMapper;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 内部JSON工具类,仅用于JSON内部使用
|
||||
@ -88,65 +87,6 @@ public final class InternalJSONUtil {
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 值转为String,用于JSON中。规则为:
|
||||
* <ul>
|
||||
* <li>对象如果是数组或Collection,包装为{@link JSONArray}</li>
|
||||
* <li>对象如果是Map,包装为{@link JSONObject}</li>
|
||||
* <li>对象如果是数字,使用{@link NumberUtil#toStr(Number)}转换为字符串</li>
|
||||
* <li>其他情况调用toString并使用双引号包装</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param value 需要转为字符串的对象
|
||||
* @return 字符串
|
||||
* @throws JSONException If the value is or contains an invalid number.
|
||||
*/
|
||||
static String valueToString(final Object value) throws JSONException {
|
||||
if (value == null) {
|
||||
return StrUtil.NULL;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return NumberUtil.toStr((Number) value);
|
||||
} else if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {
|
||||
return value.toString();
|
||||
} else if (value instanceof Map) {
|
||||
final Map<?, ?> map = (Map<?, ?>) value;
|
||||
return JSONUtil.parseObj(map).toString();
|
||||
} else if (value instanceof Collection) {
|
||||
final Collection<?> coll = (Collection<?>) value;
|
||||
return JSONUtil.parseArray(coll).toString();
|
||||
} else if (ArrayUtil.isArray(value)) {
|
||||
return JSONUtil.parseArray(value).toString();
|
||||
} else {
|
||||
return quote(value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Property的键转化为JSON形式<br>
|
||||
* 用于识别类似于:org.dromara.hutool.json这类用点隔开的键<br>
|
||||
* 注意:不允许重复键
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value) {
|
||||
final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT);
|
||||
final int last = path.length - 1;
|
||||
JSONObject target = jsonObject;
|
||||
for (int i = 0; i < last; i += 1) {
|
||||
final String segment = path[i];
|
||||
JSONObject nextTarget = target.getJSONObject(segment);
|
||||
if (nextTarget == null) {
|
||||
nextTarget = new JSONObject(target.config());
|
||||
target.set(segment, nextTarget);
|
||||
}
|
||||
target = nextTarget;
|
||||
}
|
||||
target.set(path[last], value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认情况下是否忽略null值的策略选择,以下对象不忽略null值,其它对象忽略:
|
||||
*
|
||||
@ -179,7 +119,7 @@ public final class InternalJSONUtil {
|
||||
.setIgnoreError(config.isIgnoreError())
|
||||
.setIgnoreNullValue(config.isIgnoreNullValue())
|
||||
.setTransientSupport(config.isTransientSupport())
|
||||
.setConverter((targetType, value) -> JSONValueMapper.of(config, null).map(value));
|
||||
.setConverter((targetType, value) -> JSONMapper.of(config, null).map(value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,9 +18,10 @@ package org.dromara.hutool.json;
|
||||
|
||||
import org.dromara.hutool.core.bean.path.BeanPath;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.serializer.JSONDeserializer;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.dromara.hutool.json.serializer.TypeAdapterManager;
|
||||
import org.dromara.hutool.json.support.JSONNodeBeanCreator;
|
||||
import org.dromara.hutool.json.writer.JSONWriter;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -138,7 +139,7 @@ public interface JSON extends Serializable {
|
||||
* @param value 值
|
||||
*/
|
||||
default void putByPath(final String expression, final Object value) {
|
||||
BeanPath.of(expression).setValue(this, value);
|
||||
BeanPath.of(expression).setBeanCreator(new JSONNodeBeanCreator(config())).setValue(this, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,33 +229,8 @@ public interface JSON extends Serializable {
|
||||
* @param <T> Bean类型
|
||||
* @param type {@link Type}
|
||||
* @return 实体类对象
|
||||
* @since 4.3.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> T toBean(final Type type) {
|
||||
if(null == type || Object.class == type){
|
||||
if(this instanceof JSONPrimitive){
|
||||
return (T) ((JSONPrimitive) this).getValue();
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
final JSONDeserializer<Object> deserializer = TypeAdapterManager.getInstance().getDeserializer(this, type);
|
||||
final boolean ignoreError = ObjUtil.defaultIfNull(config(), JSONConfig::isIgnoreError, false);
|
||||
if(null == deserializer){
|
||||
if(ignoreError){
|
||||
return null;
|
||||
}
|
||||
throw new JSONException("No deserializer for type: " + type);
|
||||
}
|
||||
|
||||
try{
|
||||
return (T) deserializer.deserialize(this, type);
|
||||
} catch (final Exception e){
|
||||
if(ignoreError){
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return JSONMapper.of(config(), null).toBean(this, type);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import org.dromara.hutool.core.convert.impl.ArrayConverter;
|
||||
import org.dromara.hutool.core.lang.Validator;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.mapper.JSONValueMapper;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.dromara.hutool.json.writer.JSONWriter;
|
||||
|
||||
import java.util.*;
|
||||
@ -52,7 +52,7 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
|
||||
* 配置项
|
||||
*/
|
||||
private final JSONConfig config;
|
||||
private final JSONValueMapper mapper;
|
||||
private final JSONMapper mapper;
|
||||
|
||||
// region ----- Constructors
|
||||
|
||||
@ -97,7 +97,7 @@ public class JSONArray extends ListWrapper<JSON> implements JSON, JSONGetter<Int
|
||||
public JSONArray(final int initialCapacity, final JSONConfig config) {
|
||||
super(new ArrayList<>(initialCapacity));
|
||||
this.config = ObjUtil.defaultIfNull(config, JSONConfig::of);
|
||||
this.mapper = JSONValueMapper.of(config, null);
|
||||
this.mapper = JSONMapper.of(config, null);
|
||||
}
|
||||
// endregion
|
||||
|
||||
|
@ -25,7 +25,7 @@ import org.dromara.hutool.core.map.MapUtil;
|
||||
import org.dromara.hutool.core.map.MapWrapper;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.mapper.JSONValueMapper;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.dromara.hutool.json.writer.JSONWriter;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -53,7 +53,7 @@ public class JSONObject extends MapWrapper<String, JSON> implements JSON, JSONGe
|
||||
* 配置项
|
||||
*/
|
||||
private final JSONConfig config;
|
||||
private final JSONValueMapper mapper;
|
||||
private final JSONMapper mapper;
|
||||
|
||||
/**
|
||||
* 构造,初始容量为 {@link #DEFAULT_CAPACITY},KEY有序
|
||||
@ -81,7 +81,7 @@ public class JSONObject extends MapWrapper<String, JSON> implements JSON, JSONGe
|
||||
public JSONObject(final int capacity, final JSONConfig config) {
|
||||
super(InternalJSONUtil.createRawMap(capacity, config));
|
||||
this.config = ObjUtil.defaultIfNull(config, JSONConfig::of);
|
||||
this.mapper = JSONValueMapper.of(config, null);
|
||||
this.mapper = JSONMapper.of(config, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,7 +23,8 @@ import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.reflect.TypeReference;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.mapper.JSONValueMapper;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.dromara.hutool.json.support.JSONStrFormatter;
|
||||
import org.dromara.hutool.json.writer.JSONWriter;
|
||||
import org.dromara.hutool.json.xml.JSONXMLUtil;
|
||||
|
||||
@ -160,8 +161,8 @@ public class JSONUtil {
|
||||
*/
|
||||
public static JSONArray parseArray(final Object arrayOrCollection, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
if(arrayOrCollection instanceof JSONObject){
|
||||
final JSONValueMapper jsonValueMapper = JSONValueMapper.of(config, predicate);
|
||||
return jsonValueMapper.mapFromJSONObject((JSONObject) arrayOrCollection);
|
||||
final JSONMapper jsonMapper = JSONMapper.of(config, predicate);
|
||||
return jsonMapper.mapFromJSONObject((JSONObject) arrayOrCollection);
|
||||
}
|
||||
return (JSONArray) parse(arrayOrCollection, config, predicate);
|
||||
}
|
||||
@ -214,11 +215,11 @@ public class JSONUtil {
|
||||
* @return JSON(JSONObject or JSONArray)
|
||||
*/
|
||||
public static JSON parse(final Object obj, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
final JSONValueMapper jsonValueMapper = JSONValueMapper.of(config, predicate);
|
||||
final JSONMapper jsonMapper = JSONMapper.of(config, predicate);
|
||||
if (obj instanceof CharSequence) {
|
||||
return jsonValueMapper.map((CharSequence) obj);
|
||||
return jsonMapper.map((CharSequence) obj);
|
||||
}
|
||||
return jsonValueMapper.map(obj);
|
||||
return jsonMapper.map(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.mapper;
|
||||
|
||||
import org.dromara.hutool.core.io.IoUtil;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.json.JSONArray;
|
||||
import org.dromara.hutool.json.JSONConfig;
|
||||
import org.dromara.hutool.json.JSONException;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 对象和JSONArray映射器,用于转换对象为JSONArray,支持:
|
||||
* <ul>
|
||||
* <li>JSONTokener 转 JSONArray,直接解析</li>
|
||||
* <li>Iterable 转 JSONArray</li>
|
||||
* <li>Iterator 转 JSONArray</li>
|
||||
* <li>数组 转 JSONArray</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
class JSONArrayMapper {
|
||||
/**
|
||||
* 创建ArrayMapper
|
||||
*
|
||||
* @param source 来源对象
|
||||
* @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static JSONArrayMapper of(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
return new JSONArrayMapper(source, predicate);
|
||||
}
|
||||
|
||||
private final Object source;
|
||||
private final Predicate<MutableEntry<Object, Object>> predicate;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param source 来源对象
|
||||
* @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public JSONArrayMapper(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将给定对象转换为{@link JSONArray}
|
||||
*
|
||||
* @param jsonArray 目标{@link JSONArray}
|
||||
* @throws JSONException 非数组或集合
|
||||
*/
|
||||
public void mapTo(final JSONArray jsonArray) throws JSONException {
|
||||
final Object source = this.source;
|
||||
if (null == source) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
// https://github.com/dromara/hutool/issues/2369
|
||||
// 非标准的二进制流,则按照普通数组对待
|
||||
for (final byte b : bytesSource) {
|
||||
jsonArray.set(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new JSONException("Unsupported [{}] to JSONArray", source.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JSONTokener中读取数据,并添加到JSONArray中
|
||||
*
|
||||
* @param x {@link JSONTokener}
|
||||
* @param jsonArray {@link JSONArray}
|
||||
*/
|
||||
private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONArray jsonArray) {
|
||||
JSONParser.of(x, config).setPredicate(this.predicate).parseTo(jsonArray);
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.mapper;
|
||||
|
||||
import org.dromara.hutool.core.io.IoUtil;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.json.InternalJSONUtil;
|
||||
import org.dromara.hutool.json.JSONConfig;
|
||||
import org.dromara.hutool.json.JSONException;
|
||||
import org.dromara.hutool.json.JSONObject;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 对象和JSONObject映射器,用于转换对象为JSONObject,支持:
|
||||
* <ul>
|
||||
* <li>Map 转 JSONObject,将键值对加入JSON对象</li>
|
||||
* <li>Map.Entry 转 JSONObject</li>
|
||||
* <li>JSONTokener 转 JSONObject,直接解析</li>
|
||||
* <li>ResourceBundle 转 JSONObject</li>
|
||||
* <li>Bean 转 JSONObject,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
class JSONObjectMapper {
|
||||
|
||||
/**
|
||||
* 创建ObjectMapper
|
||||
*
|
||||
* @param source 来源对象
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static JSONObjectMapper of(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
return new JSONObjectMapper(source, predicate);
|
||||
}
|
||||
|
||||
private final Object source;
|
||||
private final Predicate<MutableEntry<Object, Object>> predicate;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param source 来源对象
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public JSONObjectMapper(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
this.source = source;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将给定对象转换为{@link JSONObject}
|
||||
*
|
||||
* @param jsonObject 目标{@link JSONObject}
|
||||
*/
|
||||
public void mapTo(final JSONObject jsonObject) {
|
||||
final Object source = this.source;
|
||||
if (null == source) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (source instanceof byte[]) {
|
||||
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source)), jsonObject.config(), jsonObject);
|
||||
} else if (source instanceof ResourceBundle) {
|
||||
// ResourceBundle
|
||||
mapFromResourceBundle((ResourceBundle) source, jsonObject);
|
||||
} else {
|
||||
if (!jsonObject.config().isIgnoreError()) {
|
||||
// 不支持对象类型转换为JSONObject
|
||||
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
|
||||
}
|
||||
}
|
||||
// 如果用户选择跳过异常,则跳过此值转换
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@link ResourceBundle}转换
|
||||
*
|
||||
* @param bundle ResourceBundle
|
||||
* @param jsonObject {@link JSONObject}
|
||||
*/
|
||||
private void mapFromResourceBundle(final ResourceBundle bundle, final JSONObject jsonObject) {
|
||||
final Enumeration<String> keys = bundle.getKeys();
|
||||
while (keys.hasMoreElements()) {
|
||||
final String key = keys.nextElement();
|
||||
if (key != null) {
|
||||
InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@link JSONTokener}转换
|
||||
*
|
||||
* @param x JSONTokener
|
||||
* @param config JSON配置
|
||||
* @param jsonObject {@link JSONObject}
|
||||
*/
|
||||
private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONObject jsonObject) {
|
||||
JSONParser.of(x, config).setPredicate(this.predicate).parseTo(jsonObject);
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.mapper;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.lang.Opt;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.map.MapWrapper;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.*;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
import org.dromara.hutool.json.serializer.JSONSerializer;
|
||||
import org.dromara.hutool.json.serializer.SimpleJSONContext;
|
||||
import org.dromara.hutool.json.serializer.TypeAdapterManager;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 对象和JSON值映射器,用于转换对象为JSON对象中的值<br>
|
||||
* 有效的JSON值包括:
|
||||
* <ul>
|
||||
* <li>JSONObject</li>
|
||||
* <li>JSONArray</li>
|
||||
* <li>String</li>
|
||||
* <li>数字(int、long等)</li>
|
||||
* <li>Boolean值,如true或false</li>
|
||||
* <li>{@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class JSONValueMapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6714488573738940582L;
|
||||
|
||||
/**
|
||||
* 创建ObjectMapper
|
||||
*
|
||||
* @param jsonConfig 来源对象
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static JSONValueMapper of(final JSONConfig jsonConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
return new JSONValueMapper(jsonConfig, predicate);
|
||||
}
|
||||
|
||||
private final JSONConfig jsonConfig;
|
||||
private final Predicate<MutableEntry<Object, Object>> predicate;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param jsonConfig JSON配置
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public JSONValueMapper(final JSONConfig jsonConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
this.jsonConfig = ObjUtil.defaultIfNull(jsonConfig, JSONConfig::of);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JSONObject转换为JSONArray
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @return JSONArray
|
||||
*/
|
||||
public JSONArray mapFromJSONObject(final JSONObject jsonObject){
|
||||
final JSONArray array = new JSONArray(jsonConfig);
|
||||
JSONArrayMapper.of(jsonObject, this.predicate)
|
||||
.mapTo(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON字符串或XML字符串为JSON结构
|
||||
*
|
||||
* @param source JSON字符串或XML字符串
|
||||
* @return JSON对象
|
||||
*/
|
||||
public JSON map(final CharSequence source) {
|
||||
final String jsonStr = StrUtil.trim(source);
|
||||
if (StrUtil.startWith(jsonStr, '<')) {
|
||||
// 可能为XML
|
||||
final JSONObject jsonObject = new JSONObject(jsonConfig);
|
||||
JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
return mapFromTokener(new JSONTokener(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在需要的时候转换映射对象<br>
|
||||
* 包装包括:
|
||||
* <ul>
|
||||
* <li>array or collection =》 JSONArray</li>
|
||||
* <li>map =》 JSONObject</li>
|
||||
* <li>standard property (Double, String, et al) =》 原对象</li>
|
||||
* <li>来自于java包 =》 字符串</li>
|
||||
* <li>其它 =》 尝试包装为JSONObject,否则返回{@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param obj 被映射的对象
|
||||
* @return 映射后的值,null表示此值需被忽略
|
||||
*/
|
||||
public JSON map(Object obj) {
|
||||
if (null == obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj instanceof Optional) {
|
||||
obj = ((Optional<?>) obj).orElse(null);
|
||||
} else if (obj instanceof Opt) {
|
||||
obj = ((Opt<?>) obj).getOrNull();
|
||||
}
|
||||
|
||||
if (obj instanceof JSON) {
|
||||
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<Object> serializer = TypeAdapterManager.getInstance()
|
||||
.getSerializer(obj, obj.getClass());
|
||||
if (null != serializer) {
|
||||
return serializer.serialize(obj, new SimpleJSONContext(null, this.jsonConfig));
|
||||
}
|
||||
|
||||
// 原始类型
|
||||
if (JSONPrimitive.isTypeForJSONPrimitive(obj)) {
|
||||
return new JSONPrimitive(obj, jsonConfig);
|
||||
}
|
||||
|
||||
// 特定对象转换
|
||||
try {
|
||||
// JSONArray
|
||||
if (// MapWrapper实现了Iterable会被当作JSONArray,此处做修正
|
||||
!(obj instanceof MapWrapper) &&
|
||||
(obj instanceof Iterable || ArrayUtil.isArray(obj))) {
|
||||
final JSONArray jsonArray = new JSONArray(jsonConfig);
|
||||
JSONArrayMapper.of(obj, predicate).mapTo(jsonArray);
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
// 默认按照JSONObject对待
|
||||
final JSONObject jsonObject = new JSONObject(jsonConfig);
|
||||
JSONObjectMapper.of(obj, predicate).mapTo(jsonObject);
|
||||
return jsonObject;
|
||||
} catch (final Exception exception) {
|
||||
if (jsonConfig.isIgnoreError()) {
|
||||
return null;
|
||||
}
|
||||
throw exception instanceof JSONException ? (JSONException) exception : new JSONException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@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();
|
||||
}
|
||||
}
|
@ -26,9 +26,9 @@
|
||||
* JSON封装主要包括JSON表示和JSON转换:
|
||||
*
|
||||
* <pre>{@code
|
||||
* <--JSONConverter-- <---JSONParser----
|
||||
* Java对象 <=================> JSON对象 <=================> JSON字符串
|
||||
* ------mapper-----> ---JSONWriter---->
|
||||
* <-----JSONMapper----- <---JSONParser----
|
||||
* Java对象 <====================> JSON对象 <=================> JSON字符串
|
||||
* -----JSONMapper-----> ---JSONWriter---->
|
||||
* }</pre>
|
||||
*
|
||||
* 当然,为了高效转换,如果没有自定义需求,Java对象可以不通过JSON对象与JSON字符串转换:
|
||||
|
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.serializer;
|
||||
|
||||
import org.dromara.hutool.core.lang.Opt;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.*;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
import org.dromara.hutool.json.xml.JSONXMLParser;
|
||||
import org.dromara.hutool.json.xml.ParseConfig;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 对象和JSON值映射器,用于Java对象和JSON对象互转<br>
|
||||
* <ul>
|
||||
* <li>Java对象转JSON:{@link #map(Object)}</li>
|
||||
* <li>JSON转Java对象:{@link #toBean(JSON, Type)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 转换依赖于{@link JSONSerializer}和{@link JSONDeserializer}的实现,通过{@link TypeAdapterManager}统一管理<br>
|
||||
* 序列化和反序列化定义于两个作用域,首先查找本类中定义的,如果没有,使用{@link TypeAdapterManager#getInstance()} 查找全局定义的。
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class JSONMapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6714488573738940582L;
|
||||
|
||||
/**
|
||||
* 创建ObjectMapper
|
||||
*
|
||||
* @param jsonConfig 来源对象
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
* @return ObjectMapper
|
||||
*/
|
||||
public static JSONMapper of(final JSONConfig jsonConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
return new JSONMapper(jsonConfig, predicate);
|
||||
}
|
||||
|
||||
private final JSONConfig jsonConfig;
|
||||
private final Predicate<MutableEntry<Object, Object>> predicate;
|
||||
private TypeAdapterManager typeAdapterManager;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param jsonConfig JSON配置
|
||||
* @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留
|
||||
*/
|
||||
public JSONMapper(final JSONConfig jsonConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
|
||||
this.jsonConfig = ObjUtil.defaultIfNull(jsonConfig, JSONConfig::of);
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义类型转换器,用于将自定义类型转换为JSONObject
|
||||
*
|
||||
* @return 类型转换器管理器
|
||||
*/
|
||||
public TypeAdapterManager getTypeAdapterManager() {
|
||||
return this.typeAdapterManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自定义类型转换器,用于将自定义类型转换为JSONObject
|
||||
*
|
||||
* @param typeAdapterManager 类型转换器管理器
|
||||
* @return this
|
||||
*/
|
||||
public JSONMapper setTypeAdapterManager(final TypeAdapterManager typeAdapterManager) {
|
||||
this.typeAdapterManager = typeAdapterManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为实体类对象
|
||||
*
|
||||
* @param <T> Bean类型
|
||||
* @param json JSON
|
||||
* @param type {@link Type}
|
||||
* @return 实体类对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T toBean(final JSON json, final Type type) {
|
||||
if (null == type || Object.class == type) {
|
||||
if (json instanceof JSONPrimitive) {
|
||||
return (T) ((JSONPrimitive) json).getValue();
|
||||
}
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
JSONDeserializer<Object> deserializer = null;
|
||||
// 自定义反序列化
|
||||
if (null != this.typeAdapterManager) {
|
||||
deserializer = this.typeAdapterManager.getDeserializer(json, type);
|
||||
}
|
||||
// 全局自定义反序列化
|
||||
if (null == deserializer) {
|
||||
deserializer = TypeAdapterManager.getInstance().getDeserializer(json, type);
|
||||
}
|
||||
final boolean ignoreError = ObjUtil.defaultIfNull(this.jsonConfig, JSONConfig::isIgnoreError, false);
|
||||
if (null == deserializer) {
|
||||
if (ignoreError) {
|
||||
return null;
|
||||
}
|
||||
throw new JSONException("No deserializer for type: " + type);
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) deserializer.deserialize(json, type);
|
||||
} catch (final Exception e) {
|
||||
if (ignoreError) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JSONObject转换为JSONArrayM<br>
|
||||
* 在普通的Serializer中,JSONObject会被直接返回,如果想转为JSONArray,
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @return JSONArray
|
||||
*/
|
||||
public JSONArray mapFromJSONObject(final JSONObject jsonObject) {
|
||||
final JSONArray array = JSONUtil.ofArray(jsonConfig);
|
||||
for (final Map.Entry<String, JSON> entry : jsonObject) {
|
||||
array.add(entry.getValue());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON字符串或XML字符串为JSON结构<br>
|
||||
* 在普通的Serializer中,字符串会被作为普通字符串转为{@link JSONPrimitive},此处做区分
|
||||
*
|
||||
* @param source JSON字符串或XML字符串
|
||||
* @return JSON对象
|
||||
*/
|
||||
public JSON map(final CharSequence source) {
|
||||
final String jsonStr = StrUtil.trim(source);
|
||||
if (StrUtil.startWith(jsonStr, '<')) {
|
||||
// 可能为XML
|
||||
final JSONObject jsonObject = JSONUtil.ofObj(jsonConfig);
|
||||
JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
return mapFromTokener(new JSONTokener(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在需要的时候转换映射对象<br>
|
||||
* 包装包括:
|
||||
* <ul>
|
||||
* <li>array or collection =》 JSONArray</li>
|
||||
* <li>map =》 JSONObject</li>
|
||||
* <li>standard property (Double, String, et al) =》 原对象</li>
|
||||
* <li>来自于java包 =》 字符串</li>
|
||||
* <li>其它 =》 尝试包装为JSONObject,否则返回{@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param obj 被映射的对象
|
||||
* @return 映射后的值,null表示此值需被忽略
|
||||
*/
|
||||
public JSON map(Object obj) {
|
||||
if (null == obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj instanceof Optional) {
|
||||
obj = ((Optional<?>) obj).orElse(null);
|
||||
if (null == obj) {
|
||||
return null;
|
||||
}
|
||||
} else if (obj instanceof Opt) {
|
||||
obj = ((Opt<?>) obj).getOrNull();
|
||||
if (null == obj) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj instanceof JSON) {
|
||||
return (JSON) obj;
|
||||
}
|
||||
|
||||
final Class<?> clazz = obj.getClass();
|
||||
JSONSerializer<Object> serializer = null;
|
||||
// 自定义序列化
|
||||
if (null != this.typeAdapterManager) {
|
||||
serializer = this.typeAdapterManager.getSerializer(obj, clazz);
|
||||
}
|
||||
// 全局自定义序列化
|
||||
if (null == serializer) {
|
||||
serializer = TypeAdapterManager.getInstance().getSerializer(obj, clazz);
|
||||
}
|
||||
final boolean ignoreError = ObjUtil.defaultIfNull(this.jsonConfig, JSONConfig::isIgnoreError, false);
|
||||
if (null == serializer) {
|
||||
if (ignoreError) {
|
||||
return null;
|
||||
}
|
||||
throw new JSONException("No deserializer for type: " + obj.getClass());
|
||||
}
|
||||
|
||||
try {
|
||||
return serializer.serialize(obj, new SimpleJSONContext(null, this.jsonConfig));
|
||||
} catch (final Exception e) {
|
||||
if (ignoreError) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@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();
|
||||
}
|
||||
}
|
@ -284,6 +284,8 @@ public class TypeAdapterManager {
|
||||
private static TypeAdapterManager registerDefault(final TypeAdapterManager manager) {
|
||||
|
||||
// 自定义序列化器
|
||||
manager.register(ResourceBundleSerializer.INSTANCE);
|
||||
manager.register(TokenerSerializer.INSTANCE);
|
||||
|
||||
// 自定义反序列化器
|
||||
manager.register(KBeanDeserializer.INSTANCE);
|
||||
|
@ -18,10 +18,11 @@ package org.dromara.hutool.json.serializer.impl;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.collection.iter.ArrayIter;
|
||||
import org.dromara.hutool.core.io.IoUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.json.JSON;
|
||||
import org.dromara.hutool.json.JSONArray;
|
||||
import org.dromara.hutool.json.JSONObject;
|
||||
import org.dromara.hutool.json.*;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
import org.dromara.hutool.json.serializer.JSONContext;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONSerializer;
|
||||
@ -58,6 +59,9 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJ
|
||||
|
||||
@Override
|
||||
public JSON serialize(final Object bean, final JSONContext context) {
|
||||
if (bean instanceof byte[]) {
|
||||
return serializeBytes((byte[]) bean, context);
|
||||
}
|
||||
return IterTypeAdapter.INSTANCE.serialize(new ArrayIter<>(bean), context);
|
||||
}
|
||||
|
||||
@ -74,6 +78,36 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJ
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化二进制流为JSON
|
||||
*
|
||||
* @param bytes 二进制流
|
||||
* @param context JSON上下文
|
||||
* @return JSONArray
|
||||
*/
|
||||
private JSON serializeBytes(final byte[] bytes, final JSONContext context) {
|
||||
final JSONConfig config = context.config();
|
||||
switch (bytes[0]) {
|
||||
case '{':
|
||||
case '[':
|
||||
return JSONParser.of(new JSONTokener(IoUtil.toStream(bytes)), config).parse();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
for (final byte b : bytes) {
|
||||
result.set(b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JSONObject填充到数组
|
||||
*
|
||||
|
@ -26,7 +26,7 @@ import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.InternalJSONUtil;
|
||||
import org.dromara.hutool.json.JSON;
|
||||
import org.dromara.hutool.json.JSONObject;
|
||||
import org.dromara.hutool.json.convert.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.support.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.serializer.JSONContext;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONSerializer;
|
||||
|
@ -17,6 +17,7 @@
|
||||
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;
|
||||
@ -46,6 +47,9 @@ public class IterTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJS
|
||||
|
||||
@Override
|
||||
public boolean match(final Object bean, final JSONContext context) {
|
||||
if(bean instanceof MapWrapper){
|
||||
return false;
|
||||
}
|
||||
return bean instanceof Iterable || bean instanceof Iterator;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ 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.JSONObject;
|
||||
import org.dromara.hutool.json.convert.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.support.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -20,7 +20,7 @@ import org.dromara.hutool.core.bean.RecordUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.json.JSON;
|
||||
import org.dromara.hutool.json.JSONObject;
|
||||
import org.dromara.hutool.json.convert.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.support.JSONObjectValueProvider;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.serializer.impl;
|
||||
|
||||
import org.dromara.hutool.core.convert.ConvertUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
||||
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.MatcherJSONSerializer;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* {@link ResourceBundle}序列化器
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class ResourceBundleSerializer implements MatcherJSONSerializer<ResourceBundle> {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final ResourceBundleSerializer INSTANCE = new ResourceBundleSerializer();
|
||||
|
||||
@Override
|
||||
public boolean match(final Object bean, final JSONContext context) {
|
||||
return bean instanceof ResourceBundle;
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
mapFromResourceBundle(bean, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@link ResourceBundle}转换
|
||||
*
|
||||
* @param bundle ResourceBundle
|
||||
* @param jsonObject {@link JSONObject}
|
||||
*/
|
||||
private void mapFromResourceBundle(final ResourceBundle bundle, final JSONObject jsonObject) {
|
||||
final Enumeration<String> keys = bundle.getKeys();
|
||||
while (keys.hasMoreElements()) {
|
||||
final String key = keys.nextElement();
|
||||
if (key != null) {
|
||||
propertyPut(jsonObject, key, bundle.getString(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Property的键转化为JSON形式<br>
|
||||
* 用于识别类似于:org.dromara.hutool.json这类用点隔开的键<br>
|
||||
* 注意:不允许重复键
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
private static void propertyPut(final JSONObject jsonObject, final Object key, final Object value) {
|
||||
final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT);
|
||||
final int last = path.length - 1;
|
||||
JSONObject target = jsonObject;
|
||||
for (int i = 0; i < last; i += 1) {
|
||||
final String segment = path[i];
|
||||
JSONObject nextTarget = target.getJSONObject(segment);
|
||||
if (nextTarget == null) {
|
||||
nextTarget = JSONUtil.ofObj(target.config());
|
||||
target.set(segment, nextTarget);
|
||||
}
|
||||
target = nextTarget;
|
||||
}
|
||||
target.set(path[last], value);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.json.JSON;
|
||||
import org.dromara.hutool.json.JSONConfig;
|
||||
import org.dromara.hutool.json.reader.JSONParser;
|
||||
import org.dromara.hutool.json.reader.JSONTokener;
|
||||
import org.dromara.hutool.json.serializer.JSONContext;
|
||||
import org.dromara.hutool.json.serializer.MatcherJSONSerializer;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
* JSONTokener及其读取流的JSON序列化器实现
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class TokenerSerializer implements MatcherJSONSerializer<Object> {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final TokenerSerializer INSTANCE = new TokenerSerializer();
|
||||
|
||||
@Override
|
||||
public boolean match(final Object bean, final JSONContext context) {
|
||||
return bean instanceof Reader
|
||||
|| bean instanceof InputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON serialize(final Object bean, final JSONContext context) {
|
||||
// 读取JSON流
|
||||
if (bean instanceof JSONTokener) {
|
||||
return mapFromTokener((JSONTokener) bean, context.config());
|
||||
} else if (bean instanceof JSONParser) {
|
||||
return ((JSONParser) bean).parse();
|
||||
} else if (bean instanceof Reader) {
|
||||
return mapFromTokener(new JSONTokener((Reader) bean), context.config());
|
||||
} else if (bean instanceof InputStream) {
|
||||
return mapFromTokener(new JSONTokener((InputStream) bean), context.config());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unsupported source: " + bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从{@link JSONTokener} 中读取JSON字符串,并转换为JSON
|
||||
*
|
||||
* @param tokener {@link JSONTokener}
|
||||
* @return JSON
|
||||
*/
|
||||
private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) {
|
||||
return JSONParser.of(tokener, config).setPredicate(null).parse();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -14,16 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json.convert;
|
||||
package org.dromara.hutool.json.support;
|
||||
|
||||
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.json.JSON;
|
||||
import org.dromara.hutool.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* JSONObject值提供者,用于将JSONObject中的值注入Bean
|
||||
* JSONObject值提供者,用于将JSONObject中的值注入Bean<br>
|
||||
* 兼容下划线模式的JSON转换为驼峰模式
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
@ -42,16 +44,19 @@ public class JSONObjectValueProvider implements ValueProvider<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object value(final String key, final Type valueType) {
|
||||
final JSON value = jsonObject.get(key);
|
||||
if (null == value) {
|
||||
return null;
|
||||
}
|
||||
return value.toBean(valueType);
|
||||
public boolean containsKey(final String key) {
|
||||
return jsonObject.containsKey(key) || jsonObject.containsKey(StrUtil.toUnderlineCase(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(final String key) {
|
||||
return jsonObject.containsKey(key);
|
||||
public Object value(final String key, final Type valueType) {
|
||||
JSON value = jsonObject.get(key);
|
||||
if (null == value) {
|
||||
value = jsonObject.get(StrUtil.toUnderlineCase(key));
|
||||
if(null == value){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return value.toBean(valueType);
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.json;
|
||||
package org.dromara.hutool.json.support;
|
||||
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
@ -15,9 +15,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* JSON中对象、值类型转换封装
|
||||
* JSON的支持类,如用于转换和BeanPath操作的对象,还有用于格式化的对象等
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
package org.dromara.hutool.json.convert;
|
||||
package org.dromara.hutool.json.support;
|
@ -35,7 +35,12 @@ public class Issue1200Test {
|
||||
JSONConfig.of().setIgnoreError(true));
|
||||
|
||||
final ResultBean resultBean = jsonObject.toBean(ResultBean.class);
|
||||
Assertions.assertNull(resultBean.getItems().get(0).get(0));
|
||||
// json对象转ItemsBean,但是字段对应不上,保留空对象
|
||||
Assertions.assertNull(resultBean.getItems().get(0).get(0).get(0).getDetail());
|
||||
|
||||
// 字符串转对象,失败,为null
|
||||
Assertions.assertNull(resultBean.getItems().get(0).get(0).get(1));
|
||||
Assertions.assertNull(resultBean.getItems().get(0).get(0).get(2));
|
||||
}
|
||||
|
||||
@Data
|
||||
|
@ -21,6 +21,10 @@ import org.dromara.hutool.core.annotation.Alias;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* 兼容下划线模式的JSON转换为驼峰模式<br>
|
||||
* 逻辑见:JSONObjectValueProvider
|
||||
*/
|
||||
public class Issue867Test {
|
||||
|
||||
@Test
|
||||
|
@ -17,7 +17,7 @@
|
||||
package org.dromara.hutool.json;
|
||||
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.json.mapper.JSONValueMapper;
|
||||
import org.dromara.hutool.json.serializer.JSONMapper;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -27,7 +27,7 @@ public class IssueI9DX5HTest {
|
||||
@Test
|
||||
void xmlToJSONTest() {
|
||||
final String xml = "<GoodMsg>你好</GoodMsg>";
|
||||
final JSONValueMapper mapper = JSONValueMapper.of(JSONConfig.of(), entry -> {
|
||||
final JSONMapper mapper = JSONMapper.of(JSONConfig.of(), entry -> {
|
||||
entry.setKey(StrUtil.toUnderlineCase((CharSequence) entry.getKey()));
|
||||
return true;
|
||||
});
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.dromara.hutool.json;
|
||||
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.json.support.JSONStrFormatter;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -564,7 +564,7 @@ public class ImgUtil {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- convert
|
||||
// region ----- support
|
||||
|
||||
/**
|
||||
* 图像类型转换:GIF=》JPG、GIF=》PNG、PNG=》JPG、PNG=》GIF(X)、BMP=》PNG
|
||||
|
Loading…
x
Reference in New Issue
Block a user