mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
4afb8c581e
commit
1b92f58bae
@ -42,10 +42,11 @@ import java.util.Iterator;
|
||||
* ['person']['friends'][5]['name']
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> Bean类型
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class BeanPath implements Iterator<BeanPath> {
|
||||
public class BeanPath<T> implements Iterator<BeanPath<T>> {
|
||||
|
||||
/**
|
||||
* 表达式边界符号数组
|
||||
@ -58,21 +59,34 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
* @param expression 表达式
|
||||
* @return BeanPath
|
||||
*/
|
||||
public static BeanPath of(final String expression) {
|
||||
return new BeanPath(expression);
|
||||
public static BeanPath<Object> of(final String expression) {
|
||||
return new BeanPath<>(expression, DefaultNodeBeanFactory.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Bean路径
|
||||
*
|
||||
* @param expression 表达式
|
||||
* @param beanFactory NodeBean工厂,用于Bean的值创建、获取和设置
|
||||
* @param <T> Bean类型
|
||||
* @return BeanPath
|
||||
*/
|
||||
public static <T> BeanPath<T> of(final String expression, final NodeBeanFactory<T> beanFactory) {
|
||||
return new BeanPath<>(expression, beanFactory);
|
||||
}
|
||||
|
||||
private final Node node;
|
||||
private final String child;
|
||||
private NodeBeanCreator beanCreator;
|
||||
private final NodeBeanFactory<T> beanFactory;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param expression 表达式
|
||||
* @param expression 表达式
|
||||
* @param beanFactory NodeBean工厂,用于Bean的值创建、获取和设置
|
||||
*/
|
||||
public BeanPath(final String expression) {
|
||||
this.beanCreator = DefaultNodeBeanCreator.INSTANCE;
|
||||
public BeanPath(final String expression, final NodeBeanFactory<T> beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
final int length = expression.length();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
@ -127,17 +141,6 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点
|
||||
*
|
||||
@ -162,8 +165,8 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanPath next() {
|
||||
return new BeanPath(this.child);
|
||||
public BeanPath<T> next() {
|
||||
return new BeanPath<>(this.child, this.beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,15 +175,16 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
* @param bean Bean对象
|
||||
* @return 路径对应的值
|
||||
*/
|
||||
public Object getValue(final Object bean) {
|
||||
final Object value = this.node.getValue(bean);
|
||||
if(null == value){
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getValue(final T bean) {
|
||||
final Object value = beanFactory.getValue(bean, this);
|
||||
if (null == value) {
|
||||
return null;
|
||||
}
|
||||
if (!hasNext()) {
|
||||
return value;
|
||||
}
|
||||
return next().getValue(value);
|
||||
return next().getValue((T) value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,25 +194,27 @@ public class BeanPath implements Iterator<BeanPath> {
|
||||
* @param value 设置的值
|
||||
* @return bean。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean
|
||||
*/
|
||||
public Object setValue(final Object bean, final Object value) {
|
||||
@SuppressWarnings({"ReassignedVariable", "unchecked"})
|
||||
public Object setValue(final T bean, final Object value) {
|
||||
final NodeBeanFactory<T> beanFactory = this.beanFactory;
|
||||
if (!hasNext()) {
|
||||
// 根节点,直接赋值
|
||||
return this.node.setValue(bean, value);
|
||||
return beanFactory.setValue(bean, value, this);
|
||||
}
|
||||
|
||||
final BeanPath childBeanPath = next();
|
||||
Object subBean = this.node.getValue(bean);
|
||||
final BeanPath<T> childBeanPath = next();
|
||||
Object subBean = beanFactory.getValue(bean, this);
|
||||
if (null == subBean) {
|
||||
subBean = beanCreator.create(bean, this);
|
||||
this.node.setValue(bean, subBean);
|
||||
subBean = beanFactory.create(bean, this);
|
||||
beanFactory.setValue(bean, subBean, this);
|
||||
// 如果自定义put方法修改了value,返回修改后的value,避免值丢失
|
||||
subBean = this.node.getValue(bean);
|
||||
subBean = beanFactory.getValue(bean, this);
|
||||
}
|
||||
// 递归逐层查找子节点,赋值
|
||||
final Object newSubBean = childBeanPath.setValue(subBean, value);
|
||||
if(newSubBean != subBean){
|
||||
final Object newSubBean = childBeanPath.setValue((T) subBean, value);
|
||||
if (newSubBean != subBean) {
|
||||
//对于数组对象,set新值后,会返回新的数组,此时将新对象再加入父bean中,覆盖旧数组
|
||||
this.node.setValue(bean, newSubBean);
|
||||
beanFactory.setValue(bean, newSubBean, this);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
@ -1,69 +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.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,167 @@
|
||||
/*
|
||||
* 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.BeanUtil;
|
||||
import org.dromara.hutool.core.bean.DynaBean;
|
||||
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.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.reflect.ConstructorUtil;
|
||||
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 默认的Bean创建器
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DefaultNodeBeanFactory implements NodeBeanFactory<Object> {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final DefaultNodeBeanFactory INSTANCE = new DefaultNodeBeanFactory();
|
||||
|
||||
@Override
|
||||
public Object create(final Object parent, final BeanPath<Object> 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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final Object bean, final BeanPath<Object> 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 Object setValue(final Object bean, final Object value, final BeanPath<Object> beanPath) {
|
||||
final Node node = beanPath.getNode();
|
||||
if (null == node || node instanceof EmptyNode) {
|
||||
return bean;
|
||||
} else if (node instanceof NameNode) {
|
||||
return DynaBean.of(bean).set(((NameNode) node).getName(), value).getBean();
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported node type: " + node.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称或下标列表对应的值<br>
|
||||
* 如果为name列表,则获取Map或Bean中对应key或字段值列表<br>
|
||||
* 如果为数字列表,则获取对应下标值列表
|
||||
*
|
||||
* @param bean Bean
|
||||
* @param node 列表节点
|
||||
* @return 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Object getValueByListNode(final Object bean, final ListNode node) {
|
||||
final String[] names = node.getUnWrappedNames();
|
||||
|
||||
if (bean instanceof Collection) {
|
||||
return CollUtil.getAny((Collection<?>) bean, ConvertUtil.convert(int[].class, names));
|
||||
} else if (ArrayUtil.isArray(bean)) {
|
||||
return ArrayUtil.getAny(bean, ConvertUtil.convert(int[].class, names));
|
||||
} else {
|
||||
final Map<String, Object> map;
|
||||
if (bean instanceof Map) {
|
||||
// 只支持String为key的Map
|
||||
map = (Map<String, Object>) bean;
|
||||
} else {
|
||||
// 一次性使用,包装Bean避免无用转换
|
||||
map = BeanUtil.toBeanMap(bean);
|
||||
}
|
||||
return MapUtil.getAny(map, names);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称的值,支持Map、Bean等
|
||||
*
|
||||
* @param bean Bean
|
||||
* @param node 节点
|
||||
* @return 值
|
||||
*/
|
||||
private static Object getValueByNameNode(final Object bean, final NameNode node) {
|
||||
final String name = node.getName();
|
||||
if ("$".equals(name)) {
|
||||
return bean;
|
||||
}
|
||||
Object value = DynaBean.of(bean).get(name);
|
||||
if (null == value && StrUtil.lowerFirst(ClassUtil.getClassName(bean, true)).equals(name)) {
|
||||
// 如果bean类名与属性名相同,则返回bean本身
|
||||
value = bean;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定范围的值,只支持集合和数组
|
||||
*
|
||||
* @param bean Bean
|
||||
* @param node 范围节点
|
||||
* @return 值
|
||||
*/
|
||||
private static Object getValueByRangeNode(final Object bean, final RangeNode node) {
|
||||
if (bean instanceof Collection) {
|
||||
return CollUtil.sub((Collection<?>) bean, node.getStart(), node.getEnd(), node.getStep());
|
||||
} else if (ArrayUtil.isArray(bean)) {
|
||||
return ArrayUtil.sub(bean, node.getStart(), node.getEnd(), node.getStep());
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Can not get range value for: " + bean.getClass());
|
||||
}
|
||||
}
|
@ -17,22 +17,41 @@
|
||||
package org.dromara.hutool.core.bean.path;
|
||||
|
||||
/**
|
||||
* BeanPath节点对应的Bean创建器<br>
|
||||
* 用于创建Bean路径节点对应的Bean
|
||||
* BeanPath节点对应的Bean工厂,提供Bean的创建、获取和设置接口<br>
|
||||
*
|
||||
* @param <T> Bean类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface NodeBeanCreator {
|
||||
public interface NodeBeanFactory<T> {
|
||||
|
||||
/**
|
||||
* 创建Bean<br>
|
||||
* beanPath对应当前的路径,即如果父对象为:a,则beanPath为:a.b,则创建的Bean为:a.b.c对应的Bean对象<br>
|
||||
* 给定的a一定存在,但是本路径中b对应的Bean不存在,则创建的对象是b的值,这个值用c表示
|
||||
*
|
||||
* @param parent 父Bean
|
||||
* @param beanPath 当前路径
|
||||
* @param parent 父Bean
|
||||
* @param beanPath 当前路径
|
||||
* @return Bean
|
||||
*/
|
||||
Object create(final Object parent, final BeanPath beanPath);
|
||||
T create(final T parent, final BeanPath<T> beanPath);
|
||||
|
||||
/**
|
||||
* 获取Bean对应节点的值
|
||||
*
|
||||
* @param bean bean对象
|
||||
* @param beanPath 当前路径
|
||||
* @return 节点值
|
||||
*/
|
||||
Object getValue(T bean, final BeanPath<T> beanPath);
|
||||
|
||||
/**
|
||||
* 设置节点值
|
||||
*
|
||||
* @param bean bean对象
|
||||
* @param value 节点值
|
||||
* @param beanPath 当前路径
|
||||
* @return bean对象。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean
|
||||
*/
|
||||
T setValue(T bean, Object value, final BeanPath<T> beanPath);
|
||||
}
|
@ -27,15 +27,4 @@ public class EmptyNode implements Node {
|
||||
* 单例
|
||||
*/
|
||||
public static EmptyNode INSTANCE = new EmptyNode();
|
||||
|
||||
@Override
|
||||
public Object getValue(final Object bean) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object bean, final Object value) {
|
||||
// do nothing
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
@ -16,18 +16,11 @@
|
||||
|
||||
package org.dromara.hutool.core.bean.path.node;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
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.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 列表节点
|
||||
@ -35,56 +28,34 @@ import java.util.Map;
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class ListNode implements Node{
|
||||
public class ListNode implements Node {
|
||||
|
||||
final List<String> names;
|
||||
|
||||
/**
|
||||
* 列表节点
|
||||
*
|
||||
* @param expression 表达式
|
||||
*/
|
||||
public ListNode(final String expression) {
|
||||
this.names = SplitUtil.splitTrim(expression, StrUtil.COMMA);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object getValue(final Object bean) {
|
||||
final List<String> names = this.names;
|
||||
|
||||
if (bean instanceof Collection) {
|
||||
return CollUtil.getAny((Collection<?>) bean, ConvertUtil.convert(int[].class, names));
|
||||
} else if (ArrayUtil.isArray(bean)) {
|
||||
return ArrayUtil.getAny(bean, ConvertUtil.convert(int[].class, names));
|
||||
} else {
|
||||
final String[] unWrappedNames = getUnWrappedNames(names);
|
||||
if (bean instanceof Map) {
|
||||
// 只支持String为key的Map
|
||||
return MapUtil.getAny((Map<String, ?>) bean, unWrappedNames);
|
||||
} else {
|
||||
// 一次性使用,包装Bean避免无用转换
|
||||
final Map<String, Object> map = BeanUtil.toBeanMap(bean);
|
||||
return MapUtil.getAny(map, unWrappedNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object bean, final Object value) {
|
||||
throw new UnsupportedOperationException("Can not set value to multi names.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.names.toString();
|
||||
/**
|
||||
* 获取列表中的name,不去除单引号
|
||||
*
|
||||
* @return name列表
|
||||
*/
|
||||
public String[] getNames() {
|
||||
return this.names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将列表中的name,去除单引号
|
||||
* @param names name列表
|
||||
*
|
||||
* @return 处理后的name列表
|
||||
*/
|
||||
private String[] getUnWrappedNames(final List<String> names){
|
||||
public String[] getUnWrappedNames() {
|
||||
final String[] unWrappedNames = new String[names.size()];
|
||||
for (int i = 0; i < unWrappedNames.length; i++) {
|
||||
unWrappedNames[i] = StrUtil.unWrap(names.get(i), CharUtil.SINGLE_QUOTE);
|
||||
@ -92,4 +63,9 @@ public class ListNode implements Node{
|
||||
|
||||
return unWrappedNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.names.toString();
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,7 @@
|
||||
|
||||
package org.dromara.hutool.core.bean.path.node;
|
||||
|
||||
import org.dromara.hutool.core.bean.DynaBean;
|
||||
import org.dromara.hutool.core.math.NumberUtil;
|
||||
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
/**
|
||||
* 处理名称节点或序号节点,如:
|
||||
@ -61,27 +58,6 @@ public class NameNode implements Node {
|
||||
return NumberUtil.isInteger(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final Object bean) {
|
||||
if(null == bean){
|
||||
return null;
|
||||
}
|
||||
if ("$".equals(name)) {
|
||||
return bean;
|
||||
}
|
||||
Object value = DynaBean.of(bean).get(this.name);
|
||||
if(null == value && StrUtil.lowerFirst(ClassUtil.getClassName(bean, true)).equals(this.name)){
|
||||
// 如果bean类名与属性名相同,则返回bean本身
|
||||
value = bean;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object bean, final Object value) {
|
||||
return DynaBean.of(bean).set(this.name, value).getBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
|
@ -22,20 +22,5 @@ package org.dromara.hutool.core.bean.path.node;
|
||||
* @author looly
|
||||
*/
|
||||
public interface Node {
|
||||
/**
|
||||
* 获取Bean对应节点的值
|
||||
*
|
||||
* @param bean bean对象
|
||||
* @return 节点值
|
||||
*/
|
||||
Object getValue(Object bean);
|
||||
|
||||
/**
|
||||
* 设置节点值
|
||||
*
|
||||
* @param bean bean对象
|
||||
* @param value 节点值
|
||||
* @return bean对象。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean
|
||||
*/
|
||||
Object setValue(Object bean, Object value);
|
||||
}
|
||||
|
@ -16,12 +16,9 @@
|
||||
|
||||
package org.dromara.hutool.core.bean.path.node;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -51,20 +48,31 @@ public class RangeNode implements Node {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(final Object bean) {
|
||||
if (bean instanceof Collection) {
|
||||
return CollUtil.sub((Collection<?>) bean, this.start, this.end, this.step);
|
||||
} else if (ArrayUtil.isArray(bean)) {
|
||||
return ArrayUtil.sub(bean, this.start, this.end, this.step);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Can not get range value for: " + bean.getClass());
|
||||
/**
|
||||
* 获取起始值
|
||||
*
|
||||
* @return 起始值
|
||||
*/
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(final Object bean, final Object value) {
|
||||
throw new UnsupportedOperationException("Can not set value with step name.");
|
||||
/**
|
||||
* 获取结束值
|
||||
*
|
||||
* @return 结束值
|
||||
*/
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取步进值
|
||||
*
|
||||
* @return 步进值
|
||||
*/
|
||||
public int getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,7 +28,7 @@ import java.util.function.Function;
|
||||
* 此类用于解决在JDK8中调用{@link ConcurrentHashMap#computeIfAbsent(Object, Function)}可能造成的死循环问题。<br>
|
||||
* 见:issues#2349<br>
|
||||
* <p>
|
||||
* 相关bug见:@see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">https://bugs.openjdk.java.net/browse/JDK-8161372</a>
|
||||
* 相关bug见:https://bugs.openjdk.java.net/browse/JDK-8161372
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
|
@ -70,14 +70,14 @@ public class BeanPathGetOrSetValueTest {
|
||||
|
||||
@Test
|
||||
public void getValueTest() {
|
||||
final BeanPath pattern = new BeanPath("$.userInfo.examInfoDict[0].id");
|
||||
final BeanPath<Object> pattern = BeanPath.of("$.userInfo.examInfoDict[0].id");
|
||||
final Object result = pattern.getValue(tempMap);
|
||||
Assertions.assertEquals(1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setValueTest() {
|
||||
final BeanPath pattern = new BeanPath("userInfo.examInfoDict[0].id");
|
||||
final BeanPath<Object> pattern = BeanPath.of("userInfo.examInfoDict[0].id");
|
||||
pattern.setValue(tempMap, 2);
|
||||
final Object result = pattern.getValue(tempMap);
|
||||
Assertions.assertEquals(2, result);
|
||||
@ -85,7 +85,7 @@ public class BeanPathGetOrSetValueTest {
|
||||
|
||||
@Test
|
||||
public void getMapTest () {
|
||||
final BeanPath pattern = new BeanPath("userInfo[id, photoPath]");
|
||||
final BeanPath<Object> pattern = BeanPath.of("userInfo[id, photoPath]");
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, Object> result = (Map<String, Object>)pattern.getValue(tempMap);
|
||||
Assertions.assertEquals(1, result.get("id"));
|
||||
@ -98,7 +98,7 @@ public class BeanPathGetOrSetValueTest {
|
||||
dataMap.put("aa", "value0");
|
||||
dataMap.put("aa.bb.cc", "value111111");// key 是类名 格式 带 ' . '
|
||||
|
||||
final BeanPath pattern = new BeanPath("'aa.bb.cc'");
|
||||
final BeanPath<Object> pattern = BeanPath.of("'aa.bb.cc'");
|
||||
Assertions.assertEquals("value111111", pattern.getValue(dataMap));
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ public class BeanPathGetOrSetValueTest {
|
||||
public void issue2362Test() {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
|
||||
BeanPath beanPath = BeanPath.of("list[0].name");
|
||||
BeanPath<Object> beanPath = BeanPath.of("list[0].name");
|
||||
beanPath.setValue(map, "张三");
|
||||
Assertions.assertEquals("{list=[{name=张三}]}", map.toString());
|
||||
|
||||
@ -125,7 +125,7 @@ public class BeanPathGetOrSetValueTest {
|
||||
public void putTest() {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
|
||||
final BeanPath beanPath = BeanPath.of("list[1].name");
|
||||
final BeanPath<Object> beanPath = BeanPath.of("list[1].name");
|
||||
beanPath.setValue(map, "张三");
|
||||
Assertions.assertEquals("{list=[null, {name=张三}]}", map.toString());
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseDotTest() {
|
||||
BeanPath beanPath = new BeanPath("userInfo.examInfoDict[0].id");
|
||||
BeanPath<Object> beanPath = BeanPath.of("userInfo.examInfoDict[0].id");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("examInfoDict[0].id", beanPath.getChild());
|
||||
|
||||
@ -42,7 +42,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseDotWithQuoteTest() {
|
||||
BeanPath beanPath = new BeanPath("'userInfo'.examInfoDict[0].'id'");
|
||||
BeanPath<Object> beanPath = BeanPath.of("'userInfo'.examInfoDict[0].'id'");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("examInfoDict[0].'id'", beanPath.getChild());
|
||||
|
||||
@ -61,7 +61,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseDotWithQuoteTest2() {
|
||||
BeanPath beanPath = new BeanPath("userInfo.'examInfoDict'[0].id");
|
||||
BeanPath<Object> beanPath = BeanPath.of("userInfo.'examInfoDict'[0].id");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("'examInfoDict'[0].id", beanPath.getChild());
|
||||
|
||||
@ -80,7 +80,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseBucketTest() {
|
||||
BeanPath beanPath = new BeanPath("[userInfo][examInfoDict][0][id]");
|
||||
BeanPath<Object> beanPath = BeanPath.of("[userInfo][examInfoDict][0][id]");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("[examInfoDict][0][id]", beanPath.getChild());
|
||||
|
||||
@ -99,7 +99,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseBucketWithQuoteTest() {
|
||||
BeanPath beanPath = new BeanPath("['userInfo']['examInfoDict'][0][id]");
|
||||
BeanPath<Object> beanPath = BeanPath.of("['userInfo']['examInfoDict'][0][id]");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("['examInfoDict'][0][id]", beanPath.getChild());
|
||||
|
||||
@ -118,7 +118,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void parseBucketWithQuoteTest2() {
|
||||
BeanPath beanPath = new BeanPath("[userInfo][examInfoDict][0]['id']");
|
||||
BeanPath<Object> beanPath = BeanPath.of("[userInfo][examInfoDict][0]['id']");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("[examInfoDict][0]['id']", beanPath.getChild());
|
||||
|
||||
@ -137,7 +137,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void rangePathTest() {
|
||||
BeanPath beanPath = new BeanPath("[userInfo][2:3]");
|
||||
BeanPath<Object> beanPath = BeanPath.of("[userInfo][2:3]");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("[2:3]", beanPath.getChild());
|
||||
|
||||
@ -148,7 +148,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void listPathTest() {
|
||||
BeanPath beanPath = new BeanPath("[userInfo][1,2,3]");
|
||||
BeanPath<Object> beanPath = BeanPath.of("[userInfo][1,2,3]");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("[1,2,3]", beanPath.getChild());
|
||||
|
||||
@ -159,7 +159,7 @@ public class BeanPathTest {
|
||||
|
||||
@Test
|
||||
void listKeysPathTest() {
|
||||
BeanPath beanPath = new BeanPath("[userInfo]['a', 'b', 'c']");
|
||||
BeanPath<Object> beanPath = BeanPath.of("[userInfo]['a', 'b', 'c']");
|
||||
Assertions.assertEquals("userInfo", beanPath.getNode().toString());
|
||||
Assertions.assertEquals("['a', 'b', 'c']", beanPath.getChild());
|
||||
|
||||
|
@ -329,7 +329,7 @@ public class ConvertTest {
|
||||
|
||||
@Test
|
||||
public void toClassTest(){
|
||||
final Class<?> convert = ConvertUtil.convert(Class.class, "org.dromara.hutool.core.support.ConvertTest.Product");
|
||||
final Class<?> convert = ConvertUtil.convert(Class.class, "org.dromara.hutool.core.convert.ConvertTest.Product");
|
||||
Assertions.assertSame(Product.class, convert);
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,14 @@
|
||||
|
||||
package org.dromara.hutool.core.lang;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.hutool.core.exception.HutoolException;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnJre;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@ -30,8 +32,13 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SingletonTest {
|
||||
|
||||
/**
|
||||
* JDK8下,使用了SafeConcurrentHashMap,为了解决JDK-8161372问题<br>
|
||||
* 但是会导致可能的对象多次创建,此处屏蔽JDK8的测试
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Test
|
||||
@DisabledOnJre(JRE.JAVA_8)
|
||||
public void getTest(){
|
||||
// 此测试中使用1000个线程获取单例对象,其间对象只被创建一次
|
||||
ThreadUtil.concurrencyTest(1000, ()-> Singleton.get(TestBean.class));
|
||||
|
@ -17,7 +17,6 @@
|
||||
package org.dromara.hutool.core.util;
|
||||
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.util.JdkUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 JSON(JSONObject or JSONArray)
|
||||
*/
|
||||
public static JSON parse(final Object obj, final JSONConfig config) {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user