mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
修复CopyOptions.setFieldValueEditor后生成null值setIgnoreNullValue无效问题\
This commit is contained in:
parent
8bc2677267
commit
41dc63b580
@ -66,10 +66,6 @@ public class MapToMapCopier extends AbsCopier<Map, Map> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sValue = entry.getValue();
|
sValue = entry.getValue();
|
||||||
// 忽略空值
|
|
||||||
if (copyOptions.ignoreNullValue && sValue == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object targetValue = target.get(sKey);
|
final Object targetValue = target.get(sKey);
|
||||||
// 非覆盖模式下,如果目标值存在,则跳过
|
// 非覆盖模式下,如果目标值存在,则跳过
|
||||||
@ -83,6 +79,11 @@ public class MapToMapCopier extends AbsCopier<Map, Map> {
|
|||||||
sValue = this.copyOptions.convertField(typeArguments[1], sValue);
|
sValue = this.copyOptions.convertField(typeArguments[1], sValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 忽略空值
|
||||||
|
if (copyOptions.ignoreNullValue && sValue == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 目标赋值
|
// 目标赋值
|
||||||
target.put(sKey, sValue);
|
target.put(sKey, sValue);
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package org.dromara.hutool.core.map.multi;
|
package org.dromara.hutool.core.map.multi;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.exception.HutoolException;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权重有向图
|
* 权重有向图
|
||||||
* 基于 SPFA 算法实现 可以处理负边 可以进行负权环路检查
|
* 基于 SPFA 算法实现 可以处理负边 可以进行负权环路检查
|
||||||
*
|
*
|
||||||
|
* @param <T> 点对象类型
|
||||||
* @author NewshiJ
|
* @author NewshiJ
|
||||||
* @date 2024/8/16 09:01
|
|
||||||
*/
|
*/
|
||||||
public class DirectedWeightGraph<T> {
|
public class DirectedWeightGraph<T> {
|
||||||
|
|
||||||
@ -15,35 +17,46 @@ public class DirectedWeightGraph<T> {
|
|||||||
private final Set<T> allPoints = new HashSet<>();
|
private final Set<T> allPoints = new HashSet<>();
|
||||||
|
|
||||||
// 邻接边
|
// 邻接边
|
||||||
private final Map<T, Map<T,Edge<T>>> neighborEdgeMap = new HashMap<>();
|
private final Map<T, Map<T, Edge<T>>> neighborEdgeMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全部点
|
||||||
|
*
|
||||||
|
* @return 全部点
|
||||||
|
*/
|
||||||
|
public Set<T> getAllPoints() {
|
||||||
|
return allPoints;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加边
|
* 添加边
|
||||||
|
*
|
||||||
* @param fromPoint 开始点
|
* @param fromPoint 开始点
|
||||||
* @param nextPoint 结束点
|
* @param nextPoint 结束点
|
||||||
* @param weight 权重
|
* @param weight 权重
|
||||||
*/
|
*/
|
||||||
public void putEdge(T fromPoint, T nextPoint, long weight) {
|
public void putEdge(final T fromPoint, final T nextPoint, final long weight) {
|
||||||
allPoints.add(fromPoint);
|
allPoints.add(fromPoint);
|
||||||
allPoints.add(nextPoint);
|
allPoints.add(nextPoint);
|
||||||
Map<T, Edge<T>> nextPointMap = neighborEdgeMap.computeIfAbsent(fromPoint, k -> new HashMap<>());
|
final Map<T, Edge<T>> nextPointMap = neighborEdgeMap.computeIfAbsent(fromPoint, k -> new HashMap<>());
|
||||||
nextPointMap.put(nextPoint, new Edge<>(fromPoint, nextPoint, weight));
|
nextPointMap.put(nextPoint, new Edge<>(fromPoint, nextPoint, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除边
|
* 删除边
|
||||||
* @param fromPoint
|
*
|
||||||
* @param nextPoint
|
* @param fromPoint 开始点
|
||||||
|
* @param nextPoint 结束点
|
||||||
*/
|
*/
|
||||||
public void removeEdge(T fromPoint, T nextPoint) {
|
public void removeEdge(final T fromPoint, final T nextPoint) {
|
||||||
Map<T, Edge<T>> nextPointMap = neighborEdgeMap.computeIfAbsent(fromPoint, k -> new HashMap<>());
|
final Map<T, Edge<T>> nextPointMap = neighborEdgeMap.computeIfAbsent(fromPoint, k -> new HashMap<>());
|
||||||
nextPointMap.remove(nextPoint);
|
nextPointMap.remove(nextPoint);
|
||||||
|
|
||||||
// 重新计算 所有点位
|
// 重新计算 所有点位
|
||||||
allPoints.clear();
|
allPoints.clear();
|
||||||
neighborEdgeMap.forEach((f,m) -> {
|
neighborEdgeMap.forEach((f, m) -> {
|
||||||
allPoints.add(f);
|
allPoints.add(f);
|
||||||
m.forEach((t,e) -> {
|
m.forEach((t, e) -> {
|
||||||
allPoints.add(t);
|
allPoints.add(t);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -51,21 +64,22 @@ public class DirectedWeightGraph<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除点
|
* 删除点
|
||||||
* @param point
|
*
|
||||||
|
* @param point 点
|
||||||
*/
|
*/
|
||||||
public void removePoint(T point){
|
public void removePoint(final T point) {
|
||||||
allPoints.remove(point);
|
allPoints.remove(point);
|
||||||
neighborEdgeMap.remove(point);
|
neighborEdgeMap.remove(point);
|
||||||
neighborEdgeMap.forEach((f,m) -> {
|
neighborEdgeMap.forEach((f, m) -> {
|
||||||
m.remove(point);
|
m.remove(point);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
neighborEdgeMap.forEach((from,edgeMap) -> {
|
neighborEdgeMap.forEach((from, edgeMap) -> {
|
||||||
edgeMap.forEach((to,edge) -> {
|
edgeMap.forEach((to, edge) -> {
|
||||||
builder.append(edge);
|
builder.append(edge);
|
||||||
builder.append("\r\n");
|
builder.append("\r\n");
|
||||||
});
|
});
|
||||||
@ -79,106 +93,106 @@ public class DirectedWeightGraph<T> {
|
|||||||
* 基于 SPFA 算法实现
|
* 基于 SPFA 算法实现
|
||||||
*
|
*
|
||||||
* @param startPoint 开始节点
|
* @param startPoint 开始节点
|
||||||
* @throws NegativeRingException 存在负权环路
|
|
||||||
* @return 最佳路径集合 如果无可触达顶点 返回空 map
|
* @return 最佳路径集合 如果无可触达顶点 返回空 map
|
||||||
|
* @throws NegativeRingException 存在负权环路
|
||||||
*/
|
*/
|
||||||
public Map<T, Path<T>> bestPathMap(T startPoint) throws NegativeRingException{
|
public Map<T, Path<T>> bestPathMap(final T startPoint) throws NegativeRingException {
|
||||||
// 全部节点数量
|
// 全部节点数量
|
||||||
int pointSize = allPoints.size();
|
//final int pointSize = allPoints.size();
|
||||||
// 待访问队列
|
// 待访问队列
|
||||||
LinkedList<T> pointQueue = new LinkedList<>();
|
final LinkedList<T> pointQueue = new LinkedList<>();
|
||||||
// 待访问队列中的节点 加速判断
|
// 待访问队列中的节点 加速判断
|
||||||
HashSet<T> inQueuePoints = new HashSet<>();
|
final HashSet<T> inQueuePoints = new HashSet<>();
|
||||||
// 最佳路径集合
|
// 最佳路径集合
|
||||||
HashMap<T, Path<T>> bestPathMap = new HashMap<>();
|
final HashMap<T, Path<T>> bestPathMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
Map<T, Edge<T>> map = neighborEdgeMap.get(startPoint);
|
final Map<T, Edge<T>> map = neighborEdgeMap.get(startPoint);
|
||||||
// 无可触达路径
|
// 无可触达路径
|
||||||
if(map == null || map.isEmpty()){
|
if (map == null || map.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
map.forEach((to,edge) -> {
|
map.forEach((to, edge) -> {
|
||||||
Path<T> path = new Path<>(edge);
|
final Path<T> path = new Path<>(edge);
|
||||||
bestPathMap.put(to, path);
|
bestPathMap.put(to, path);
|
||||||
pointQueue.add(to);
|
pointQueue.add(to);
|
||||||
inQueuePoints.add(to);
|
inQueuePoints.add(to);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
while (!pointQueue.isEmpty()){
|
while (!pointQueue.isEmpty()) {
|
||||||
// 当前节点 开始对 currentPoint 进行扩展
|
// 当前节点 开始对 currentPoint 进行扩展
|
||||||
T currentPoint = pointQueue.removeFirst();
|
final T currentPoint = pointQueue.removeFirst();
|
||||||
// 到当前节点的最短路径
|
// 到当前节点的最短路径
|
||||||
Path<T> currentPath = bestPathMap.get(currentPoint);
|
final Path<T> currentPath = bestPathMap.get(currentPoint);
|
||||||
// 标记已出队列
|
// 标记已出队列
|
||||||
inQueuePoints.remove(currentPoint);
|
inQueuePoints.remove(currentPoint);
|
||||||
|
|
||||||
Map<T, Edge<T>> edgeMap = neighborEdgeMap.get(currentPoint);
|
final Map<T, Edge<T>> edgeMap = neighborEdgeMap.get(currentPoint);
|
||||||
if(edgeMap == null){
|
if (edgeMap == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扩展当前点的边
|
// 扩展当前点的边
|
||||||
Set<Map.Entry<T, Edge<T>>> entrySet = edgeMap.entrySet();
|
final Set<Map.Entry<T, Edge<T>>> entrySet = edgeMap.entrySet();
|
||||||
for (Map.Entry<T, Edge<T>> entry : entrySet) {
|
for (final Map.Entry<T, Edge<T>> entry : entrySet) {
|
||||||
T nextPoint = entry.getKey();
|
final T nextPoint = entry.getKey();
|
||||||
Edge<T> edge = entry.getValue();
|
final Edge<T> edge = entry.getValue();
|
||||||
|
|
||||||
// 不存在路径 第一次访问 将当前路径放置到 bestPathMap 中
|
// 不存在路径 第一次访问 将当前路径放置到 bestPathMap 中
|
||||||
Path<T> oldPath = bestPathMap.get(nextPoint);
|
final Path<T> oldPath = bestPathMap.get(nextPoint);
|
||||||
if(oldPath == null){
|
if (oldPath == null) {
|
||||||
Path<T> nextPath = currentPath.nextPoint(edge);
|
final Path<T> nextPath = currentPath.nextPoint(edge);
|
||||||
bestPathMap.put(nextPoint,nextPath);
|
bestPathMap.put(nextPoint, nextPath);
|
||||||
|
|
||||||
// 不在队列里就入队
|
// 不在队列里就入队
|
||||||
if(!inQueuePoints.contains(nextPoint)){
|
if (!inQueuePoints.contains(nextPoint)) {
|
||||||
inQueuePoints.add(nextPoint);
|
inQueuePoints.add(nextPoint);
|
||||||
|
|
||||||
// SLF优化 入队优化
|
// SLF优化 入队优化
|
||||||
// 每次出队进行判断扩展出的点与队头元素进行判断,若小于进队头,否则入队尾
|
// 每次出队进行判断扩展出的点与队头元素进行判断,若小于进队头,否则入队尾
|
||||||
// 尽可能的让 负环路 上的节点 先进入队列头
|
// 尽可能的让 负环路 上的节点 先进入队列头
|
||||||
if(pointQueue.isEmpty()){
|
if (pointQueue.isEmpty()) {
|
||||||
pointQueue.addLast(nextPoint);
|
pointQueue.addLast(nextPoint);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
T first = pointQueue.getFirst();
|
final T first = pointQueue.getFirst();
|
||||||
Path<T> fristPath = bestPathMap.get(first);
|
final Path<T> fristPath = bestPathMap.get(first);
|
||||||
if(nextPath.weight < fristPath.weight){
|
if (nextPath.weight < fristPath.weight) {
|
||||||
pointQueue.addFirst(nextPoint);
|
pointQueue.addFirst(nextPoint);
|
||||||
}else {
|
} else {
|
||||||
pointQueue.add(nextPoint);
|
pointQueue.add(nextPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
long newWeight = currentPath.weight + edge.weight;
|
final long newWeight = currentPath.weight + edge.weight;
|
||||||
// 新路径更糟糕 没有优化的必要
|
// 新路径更糟糕 没有优化的必要
|
||||||
if(newWeight >= oldPath.weight){
|
if (newWeight >= oldPath.weight) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新最佳路径 如果下一跳没有在队列中 将下一跳放到队列里
|
// 更新最佳路径 如果下一跳没有在队列中 将下一跳放到队列里
|
||||||
Path<T> nextPath = currentPath.nextPoint(edge);
|
final Path<T> nextPath = currentPath.nextPoint(edge);
|
||||||
bestPathMap.put(nextPoint,nextPath);
|
bestPathMap.put(nextPoint, nextPath);
|
||||||
// 不在队列里就入队
|
// 不在队列里就入队
|
||||||
if(!inQueuePoints.contains(nextPoint)){
|
if (!inQueuePoints.contains(nextPoint)) {
|
||||||
inQueuePoints.add(nextPoint);
|
inQueuePoints.add(nextPoint);
|
||||||
|
|
||||||
// SLF优化 入队优化
|
// SLF优化 入队优化
|
||||||
// 每次出队进行判断扩展出的点与队头元素进行判断,若小于进队头,否则入队尾
|
// 每次出队进行判断扩展出的点与队头元素进行判断,若小于进队头,否则入队尾
|
||||||
// 尽可能的让 负环路 上的节点 先进入队列头
|
// 尽可能的让 负环路 上的节点 先进入队列头
|
||||||
if(pointQueue.isEmpty()){
|
if (pointQueue.isEmpty()) {
|
||||||
pointQueue.addLast(nextPoint);
|
pointQueue.addLast(nextPoint);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
T first = pointQueue.getFirst();
|
final T first = pointQueue.getFirst();
|
||||||
Path<T> fristPath = bestPathMap.get(first);
|
final Path<T> fristPath = bestPathMap.get(first);
|
||||||
if(nextPath.weight < fristPath.weight){
|
if (nextPath.weight < fristPath.weight) {
|
||||||
pointQueue.addFirst(nextPoint);
|
pointQueue.addFirst(nextPoint);
|
||||||
}else {
|
} else {
|
||||||
pointQueue.addLast(nextPoint);
|
pointQueue.addLast(nextPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,89 +204,112 @@ public class DirectedWeightGraph<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 边
|
* 边
|
||||||
* @param <T>
|
*
|
||||||
|
* @param <T> 点类型
|
||||||
*/
|
*/
|
||||||
public static class Edge<T> {
|
public static class Edge<T> {
|
||||||
// 起始点
|
// 起始点
|
||||||
public T fromPoint;
|
protected T fromPoint;
|
||||||
// 目标点
|
// 目标点
|
||||||
public T nextPoint;
|
protected T toPoint;
|
||||||
// 权重
|
// 权重
|
||||||
public long weight;
|
protected long weight;
|
||||||
|
|
||||||
public Edge(T fromPoint, T nextPoint, long weight) {
|
/**
|
||||||
|
* 构造
|
||||||
|
*/
|
||||||
|
public Edge() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param fromPoint 起始点
|
||||||
|
* @param toPoint 目标点
|
||||||
|
* @param weight 权重
|
||||||
|
*/
|
||||||
|
public Edge(final T fromPoint, final T toPoint, final long weight) {
|
||||||
this.fromPoint = fromPoint;
|
this.fromPoint = fromPoint;
|
||||||
this.nextPoint = nextPoint;
|
this.toPoint = toPoint;
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return fromPoint + "->" + nextPoint + "(" + weight + ")";
|
return fromPoint + "->" + toPoint + "(" + weight + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Path<T> {
|
/**
|
||||||
// 开始节点
|
* 路径
|
||||||
public T startPoint;
|
*
|
||||||
// 结束节点
|
* @param <T> 点类型
|
||||||
public T endPoint;
|
*/
|
||||||
|
public static class Path<T> extends Edge<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 道路 即依次按照顺序经过的边
|
* 道路 即依次按照顺序经过的边
|
||||||
*/
|
*/
|
||||||
public LinkedList<Edge<T>> way = new LinkedList<>();
|
private final LinkedList<Edge<T>> way = new LinkedList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已经经过的点 如果 有一个点已经多次经过了 可以判定已经成环
|
* 已经经过的点 如果 有一个点已经多次经过了 可以判定已经成环
|
||||||
* 当源图是一个非联通图时 或者 开始节点处于图路径中下游时 或者 成环路经过的节点数量较少时
|
* 当源图是一个非联通图时 或者 开始节点处于图路径中下游时 或者 成环路经过的节点数量较少时
|
||||||
* 使用判断节点经过次数与全部节点数量进行比较会有冗余判断
|
* 使用判断节点经过次数与全部节点数量进行比较会有冗余判断
|
||||||
* 用成环判断 可以加速这种情况 是针对一些特殊的图结构优化了最差情况
|
* 用成环判断 可以加速这种情况 是针对一些特殊的图结构优化了最差情况
|
||||||
*/
|
*/
|
||||||
public Set<T> passedPoints = new HashSet<>();
|
private final Set<T> passedPoints = new HashSet<>();
|
||||||
|
|
||||||
// 总权重
|
/**
|
||||||
public long weight;
|
* 构造
|
||||||
|
*/
|
||||||
|
public Path() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public Path(Edge<T> edge){
|
/**
|
||||||
startPoint = edge.fromPoint;
|
* 构造
|
||||||
endPoint = edge.nextPoint;
|
*
|
||||||
|
* @param edge 边
|
||||||
|
*/
|
||||||
|
public Path(final Edge<T> edge) {
|
||||||
|
this.fromPoint = edge.fromPoint;
|
||||||
|
this.toPoint = edge.toPoint;
|
||||||
way.add(edge);
|
way.add(edge);
|
||||||
weight = edge.weight;
|
weight = edge.weight;
|
||||||
passedPoints.add(edge.fromPoint);
|
passedPoints.add(edge.fromPoint);
|
||||||
passedPoints.add(edge.nextPoint);
|
passedPoints.add(edge.toPoint);
|
||||||
}
|
}
|
||||||
public Path(){}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成下一跳
|
* 生成下一跳
|
||||||
* @param edge
|
*
|
||||||
|
* @param edge 边
|
||||||
|
* @return 下一跳
|
||||||
* @throws NegativeRingException 负环路
|
* @throws NegativeRingException 负环路
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public Path<T> nextPoint(Edge<T> edge) throws NegativeRingException {
|
public Path<T> nextPoint(final Edge<T> edge) throws NegativeRingException {
|
||||||
Path<T> nextPath = new Path<>();
|
final Path<T> nextPath = new Path<>();
|
||||||
nextPath.startPoint = startPoint;
|
nextPath.fromPoint = fromPoint;
|
||||||
nextPath.endPoint = edge.nextPoint;
|
nextPath.toPoint = edge.toPoint;
|
||||||
nextPath.way.addAll(way);
|
nextPath.way.addAll(way);
|
||||||
nextPath.way.add(edge);
|
nextPath.way.add(edge);
|
||||||
nextPath.weight = weight + edge.weight;
|
nextPath.weight = weight + edge.weight;
|
||||||
nextPath.passedPoints.addAll(passedPoints);
|
nextPath.passedPoints.addAll(passedPoints);
|
||||||
|
|
||||||
// 负环检查
|
// 负环检查
|
||||||
if(nextPath.passedPoints.contains(edge.nextPoint)){
|
if (nextPath.passedPoints.contains(edge.toPoint)) {
|
||||||
throw new NegativeRingException("路径:" + nextPath + "存在负环路");
|
throw new NegativeRingException("路径:" + nextPath + "存在负环路");
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPath.passedPoints.add(edge.nextPoint);
|
nextPath.passedPoints.add(edge.toPoint);
|
||||||
return nextPath;
|
return nextPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
builder.append(String.format("[%s->%s(%d)] ", startPoint, endPoint, weight));
|
builder.append(String.format("[%s->%s(%d)] ", fromPoint, toPoint, weight));
|
||||||
for (Edge<T> edge : way) {
|
for (final Edge<T> edge : way) {
|
||||||
builder.append(edge);
|
builder.append(edge);
|
||||||
builder.append(" ");
|
builder.append(" ");
|
||||||
}
|
}
|
||||||
@ -283,8 +320,15 @@ public class DirectedWeightGraph<T> {
|
|||||||
/**
|
/**
|
||||||
* 负环异常
|
* 负环异常
|
||||||
*/
|
*/
|
||||||
public static class NegativeRingException extends Exception {
|
public static class NegativeRingException extends HutoolException {
|
||||||
public NegativeRingException(String msg){
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param msg 消息
|
||||||
|
*/
|
||||||
|
public NegativeRingException(final String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package org.dromara.hutool.core.bean.copier;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.bean.BeanUtil;
|
||||||
|
import org.dromara.hutool.core.util.ObjUtil;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setFieldValueEditor编辑后的值理应继续判断ignoreNullValue
|
||||||
|
*/
|
||||||
|
public class Issue3702Test {
|
||||||
|
@Test
|
||||||
|
void mapToMapTest() {
|
||||||
|
final Map<String,String> map= new HashMap<>();
|
||||||
|
map.put("a","");
|
||||||
|
map.put("b","b");
|
||||||
|
map.put("c","c");
|
||||||
|
map.put("d","d");
|
||||||
|
|
||||||
|
final Map<String,String> map2= new HashMap<>();
|
||||||
|
map2.put("a","a1");
|
||||||
|
map2.put("b","b1");
|
||||||
|
map2.put("c","c1");
|
||||||
|
map2.put("d","d1");
|
||||||
|
|
||||||
|
final CopyOptions option= CopyOptions.of()
|
||||||
|
.setIgnoreNullValue(true)
|
||||||
|
.setIgnoreError(true)
|
||||||
|
.setFieldEditor((entry)->{
|
||||||
|
if(ObjUtil.equals(entry.getValue(), "")){
|
||||||
|
entry.setValue(null);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
});
|
||||||
|
BeanUtil.copyProperties(map,map2,option);
|
||||||
|
Assertions.assertEquals("{a=a1, b=b, c=c, d=d}", map2.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,20 @@
|
|||||||
package org.dromara.hutool.core.map;
|
package org.dromara.hutool.core.map;
|
||||||
|
|
||||||
import org.dromara.hutool.core.map.multi.DirectedWeightGraph;
|
import org.dromara.hutool.core.map.multi.DirectedWeightGraph;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author newshiJ
|
* @author newshiJ
|
||||||
* @date 2024/8/14 17:07
|
|
||||||
*/
|
*/
|
||||||
public class DirectedWeightGraphTest {
|
public class DirectedWeightGraphTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test1(){
|
@Disabled
|
||||||
DirectedWeightGraph<String> graph = new DirectedWeightGraph<>();
|
public void test1() {
|
||||||
|
final DirectedWeightGraph<String> graph = new DirectedWeightGraph<>();
|
||||||
graph.putEdge("A", "B", 14);
|
graph.putEdge("A", "B", 14);
|
||||||
graph.putEdge("A", "C", 8);
|
graph.putEdge("A", "C", 8);
|
||||||
graph.putEdge("A", "D", 12);
|
graph.putEdge("A", "D", 12);
|
||||||
@ -44,10 +44,10 @@ public class DirectedWeightGraphTest {
|
|||||||
Map<String, DirectedWeightGraph.Path<String>> map = null;
|
Map<String, DirectedWeightGraph.Path<String>> map = null;
|
||||||
try {
|
try {
|
||||||
map = graph.bestPathMap("A");
|
map = graph.bestPathMap("A");
|
||||||
map.forEach((k,v) -> {
|
map.forEach((k, v) -> {
|
||||||
System.out.println(v);
|
System.out.println(v);
|
||||||
});
|
});
|
||||||
} catch (DirectedWeightGraph.NegativeRingException e) {
|
} catch (final DirectedWeightGraph.NegativeRingException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user