mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
fix code
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user