diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/BeanPath.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/BeanPath.java index 16cfacce6..a81aa633b 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/BeanPath.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/BeanPath.java @@ -42,10 +42,11 @@ import java.util.Iterator; * ['person']['friends'][5]['name'] * * + * @param Bean类型 * @author Looly * @since 6.0.0 */ -public class BeanPath implements Iterator { +public class BeanPath implements Iterator> { /** * 表达式边界符号数组 @@ -58,21 +59,34 @@ public class BeanPath implements Iterator { * @param expression 表达式 * @return BeanPath */ - public static BeanPath of(final String expression) { - return new BeanPath(expression); + public static BeanPath of(final String expression) { + return new BeanPath<>(expression, DefaultNodeBeanFactory.INSTANCE); + } + + /** + * 创建Bean路径 + * + * @param expression 表达式 + * @param beanFactory NodeBean工厂,用于Bean的值创建、获取和设置 + * @param Bean类型 + * @return BeanPath + */ + public static BeanPath of(final String expression, final NodeBeanFactory beanFactory) { + return new BeanPath<>(expression, beanFactory); } private final Node node; private final String child; - private NodeBeanCreator beanCreator; + private final NodeBeanFactory 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 beanFactory) { + this.beanFactory = beanFactory; final int length = expression.length(); final StringBuilder builder = new StringBuilder(); @@ -127,17 +141,6 @@ public class BeanPath implements Iterator { } } - /** - * 设置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 { } @Override - public BeanPath next() { - return new BeanPath(this.child); + public BeanPath next() { + return new BeanPath<>(this.child, this.beanFactory); } /** @@ -172,15 +175,16 @@ public class BeanPath implements Iterator { * @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 { * @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 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 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; } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanCreator.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanCreator.java deleted file mode 100644 index 7640257a1..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanCreator.java +++ /dev/null @@ -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()); - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanFactory.java new file mode 100644 index 000000000..b426fb305 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/DefaultNodeBeanFactory.java @@ -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 { + + /** + * 单例 + */ + public static final DefaultNodeBeanFactory INSTANCE = new DefaultNodeBeanFactory(); + + @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()); + } + + @Override + public Object getValue(final Object bean, final BeanPath 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 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()); + } + + /** + * 获取指定名称或下标列表对应的值
+ * 如果为name列表,则获取Map或Bean中对应key或字段值列表
+ * 如果为数字列表,则获取对应下标值列表 + * + * @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 map; + if (bean instanceof Map) { + // 只支持String为key的Map + map = (Map) 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()); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanCreator.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanFactory.java similarity index 57% rename from hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanCreator.java rename to hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanFactory.java index ac1151ace..01e1ff738 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanCreator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/NodeBeanFactory.java @@ -17,22 +17,41 @@ package org.dromara.hutool.core.bean.path; /** - * BeanPath节点对应的Bean创建器
- * 用于创建Bean路径节点对应的Bean + * BeanPath节点对应的Bean工厂,提供Bean的创建、获取和设置接口
* + * @param Bean类型 * @author looly * @since 6.0.0 */ -public interface NodeBeanCreator { +public interface NodeBeanFactory { /** * 创建Bean
* beanPath对应当前的路径,即如果父对象为:a,则beanPath为:a.b,则创建的Bean为:a.b.c对应的Bean对象
* 给定的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 beanPath); + + /** + * 获取Bean对应节点的值 + * + * @param bean bean对象 + * @param beanPath 当前路径 + * @return 节点值 + */ + Object getValue(T bean, final BeanPath beanPath); + + /** + * 设置节点值 + * + * @param bean bean对象 + * @param value 节点值 + * @param beanPath 当前路径 + * @return bean对象。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean + */ + T setValue(T bean, Object value, final BeanPath beanPath); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/EmptyNode.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/EmptyNode.java index 92ac30612..68a9895bc 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/EmptyNode.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/EmptyNode.java @@ -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; - } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/ListNode.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/ListNode.java index 99bf241ab..e6893d73c 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/ListNode.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/ListNode.java @@ -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 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 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) bean, unWrappedNames); - } else { - // 一次性使用,包装Bean避免无用转换 - final Map 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 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(); + } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/NameNode.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/NameNode.java index e4e0c93d2..6b5d9e7d3 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/NameNode.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/NameNode.java @@ -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; diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/Node.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/Node.java index 9f19537b4..fb15b89fd 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/Node.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/Node.java @@ -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); } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/RangeNode.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/RangeNode.java index f87bd431b..5521b2078 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/RangeNode.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/path/node/RangeNode.java @@ -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 diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/map/concurrent/SafeConcurrentHashMap.java b/hutool-core/src/main/java/org/dromara/hutool/core/map/concurrent/SafeConcurrentHashMap.java index f540985a4..326028d69 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/map/concurrent/SafeConcurrentHashMap.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/map/concurrent/SafeConcurrentHashMap.java @@ -28,7 +28,7 @@ import java.util.function.Function; * 此类用于解决在JDK8中调用{@link ConcurrentHashMap#computeIfAbsent(Object, Function)}可能造成的死循环问题。
* 见:issues#2349
*

- * 相关bug见:@see https://bugs.openjdk.java.net/browse/JDK-8161372 + * 相关bug见:https://bugs.openjdk.java.net/browse/JDK-8161372 * * @param 键类型 * @param 值类型 diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathGetOrSetValueTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathGetOrSetValueTest.java index c7ad314f4..9ffabfd86 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathGetOrSetValueTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathGetOrSetValueTest.java @@ -70,14 +70,14 @@ public class BeanPathGetOrSetValueTest { @Test public void getValueTest() { - final BeanPath pattern = new BeanPath("$.userInfo.examInfoDict[0].id"); + final BeanPath 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 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 pattern = BeanPath.of("userInfo[id, photoPath]"); @SuppressWarnings("unchecked") final Map result = (Map)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 pattern = BeanPath.of("'aa.bb.cc'"); Assertions.assertEquals("value111111", pattern.getValue(dataMap)); } @@ -106,7 +106,7 @@ public class BeanPathGetOrSetValueTest { public void issue2362Test() { final Map map = new HashMap<>(); - BeanPath beanPath = BeanPath.of("list[0].name"); + BeanPath 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 map = new HashMap<>(); - final BeanPath beanPath = BeanPath.of("list[1].name"); + final BeanPath beanPath = BeanPath.of("list[1].name"); beanPath.setValue(map, "张三"); Assertions.assertEquals("{list=[null, {name=张三}]}", map.toString()); } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathTest.java index 07ea66b33..4a7d08faa 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/bean/path/BeanPathTest.java @@ -23,7 +23,7 @@ public class BeanPathTest { @Test void parseDotTest() { - BeanPath beanPath = new BeanPath("userInfo.examInfoDict[0].id"); + BeanPath 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 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 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 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 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 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 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 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 beanPath = BeanPath.of("[userInfo]['a', 'b', 'c']"); Assertions.assertEquals("userInfo", beanPath.getNode().toString()); Assertions.assertEquals("['a', 'b', 'c']", beanPath.getChild()); diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertTest.java index 99dc2f86f..f02b07c3a 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertTest.java @@ -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); } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SingletonTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SingletonTest.java index d59fd0b26..4f6d08fa0 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/lang/SingletonTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/SingletonTest.java @@ -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问题
+ * 但是会导致可能的对象多次创建,此处屏蔽JDK8的测试 + */ @SuppressWarnings("resource") @Test + @DisabledOnJre(JRE.JAVA_8) public void getTest(){ // 此测试中使用1000个线程获取单例对象,其间对象只被创建一次 ThreadUtil.concurrencyTest(1000, ()-> Singleton.get(TestBean.class)); diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/util/JdkUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/util/JdkUtilTest.java index 3d4bf9efb..bb367794d 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/util/JdkUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/util/JdkUtilTest.java @@ -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; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java index c10719c36..d8c6fc5bb 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java @@ -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); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java index 30d94d466..79419d39b 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONUtil.java @@ -84,6 +84,43 @@ public class JSONUtil { public static JSONArray ofArray(final JSONConfig config) { return new JSONArray(config); } + + /** + * 创建JSONPrimitive对象,用于创建非JSON对象,例如: + *
{@code
+	 *   JSONUtil.ofPrimitive(1);
+	 *   JSONUtil.ofPrimitive(1L);
+	 *   JSONUtil.ofPrimitive(1.0);
+	 *   JSONUtil.ofPrimitive(true);
+	 *   JSONUtil.ofPrimitive("str");
+	 * }
+ * + * @param value 值 + * @return JSONPrimitive对象 + * @since 6.0.0 + */ + public static JSONPrimitive ofPrimitive(final Object value) { + return ofPrimitive(value, JSONConfig.of()); + } + + /** + * 创建JSONPrimitive对象,用于创建非JSON对象,例如: + *
{@code
+	 *   JSONUtil.ofPrimitive(1, config);
+	 *   JSONUtil.ofPrimitive(1L, config);
+	 *   JSONUtil.ofPrimitive(1.0, config);
+	 *   JSONUtil.ofPrimitive(true, config);
+	 *   JSONUtil.ofPrimitive("str", config);
+	 * }
+ * + * @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> 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> 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 { *
  • Bean对象:转为JSONObject
  • * * - * @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) { diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java index 5c3db7bca..cf04c9776 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/JSONContext.java @@ -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()); + } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java index 178085562..79d61c568 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ArrayTypeAdapter.java @@ -95,13 +95,7 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer, 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); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/BeanTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/BeanTypeAdapter.java index 9d5351b43..db695bebe 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/BeanTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/BeanTypeAdapter.java @@ -60,10 +60,7 @@ public class BeanTypeAdapter implements MatcherJSONSerializer, 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, diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java index a27933238..c8a2a0d8d 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/CharSequenceTypeAdapter.java @@ -57,10 +57,7 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer>, @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 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java index 6cd35f825..35cd767a7 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/IterTypeAdapter.java @@ -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, 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; } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java index 8cede6aac..c8b441742 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/JSONPrimitiveTypeAdapter.java @@ -58,13 +58,7 @@ public class JSONPrimitiveTypeAdapter implements MatcherJSONSerializer, 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 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java index 9f4a0975f..92fb36e54 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/MapTypeAdapter.java @@ -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>, 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()); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ResourceBundleSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ResourceBundleSerializer.java index b0a6b2909..96799071d 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ResourceBundleSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/ResourceBundleSerializer.java @@ -48,15 +48,7 @@ public class ResourceBundleSerializer implements MatcherJSONSerializer { + + private final JSONConfig config; + + /** + * 构造 + * + * @param config JSON配置 + */ + public JSONNodeBeanFactory(final JSONConfig config) { + this.config = config; + } + + @Override + public JSON create(final JSON 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); + } + + @Override + public Object getValue(final JSON bean, final BeanPath 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 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()); + } + + /** + * 获取指定下标的值
    + * 如果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的值
    + * 如果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()); + } + + /** + * 获取指定下标范围的值
    + * 如果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()); + } +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java index c8d00a057..ddc96c23f 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java @@ -33,10 +33,7 @@ public class CustomSerializeTest { public void init() { TypeAdapterManager.getInstance().register(CustomBean.class, (JSONSerializer) (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); }); } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java index 3cba24eb4..f8bf285f6 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue2555Test.java @@ -57,7 +57,7 @@ public class Issue2555Test { public static class MySerializer implements JSONSerializer { @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()); } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java index 528e5251f..23eba9edd 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/Issue3086Test.java @@ -70,12 +70,7 @@ public class Issue3086Test { public JSON serialize(final TestBean bean, final JSONContext context) { final List 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); } } }