Merge branch 'v6-dev' of gitee.com:dromara/hutool into v6-dev

This commit is contained in:
Looly 2023-05-10 13:12:19 +08:00
commit 296f3c794d
8 changed files with 69 additions and 75 deletions

View File

@ -3,7 +3,7 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 6.0.0.M1 (2023-04-23) # 6.0.0.M4 (2023-05-09)
### 计划实现 ### 计划实现
* 【poi 】 Markdown相关如HTML转换等基于commonmark-java * 【poi 】 Markdown相关如HTML转换等基于commonmark-java
@ -14,5 +14,6 @@
### ❌不兼容特性 ### ❌不兼容特性
### 🐣新特性 ### 🐣新特性
* 【db 】 优化count查询兼容informixissue#I713XQ@Gitee
### 🐞Bug修复 ### 🐞Bug修复

View File

@ -144,8 +144,8 @@ public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
* @param withMissCount 是否计数丢失数 * @param withMissCount 是否计数丢失数
*/ */
private void remove(final K key, final boolean withMissCount) { private void remove(final K key, final boolean withMissCount) {
lock.lock();
CacheObj<K, V> co; CacheObj<K, V> co;
lock.lock();
try { try {
co = removeWithoutLock(key, withMissCount); co = removeWithoutLock(key, withMissCount);
} finally { } finally {

View File

@ -43,7 +43,7 @@ public interface HierarchyIterator<H, R> {
* *
* @param result 结果 * @param result 结果
* @param hierarchy 当前层级 * @param hierarchy 当前层级
* @return 向容器中添加元素的方法 * @return 下一需要遍历的层级
*/ */
Collection<H> nextHierarchies(R result, H hierarchy); Collection<H> nextHierarchies(R result, H hierarchy);

View File

@ -50,7 +50,7 @@ public class HierarchyIteratorImpl<H, R> implements HierarchyIterator<H, R> {
* *
* @param result 结果 * @param result 结果
* @param hierarchy 当前层级 * @param hierarchy 当前层级
* @return 向容器中添加元素的方法 * @return 下一需要遍历的层级
*/ */
@Override @Override
public Collection<H> nextHierarchies(final R result, final H hierarchy) { public Collection<H> nextHierarchies(final R result, final H hierarchy) {

View File

@ -35,11 +35,11 @@ import java.util.function.Predicate;
* Node root = Tree.build(); * Node root = Tree.build();
* // 从树结构中通过深度优先查找某个节点 * // 从树结构中通过深度优先查找某个节点
* Node target = HierarchyUtil.traverseByDepthFirst( * Node target = HierarchyUtil.traverseByDepthFirst(
* root, HierarchyUtil.finder(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null) * root, HierarchyIteratorUtil.find(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null)
* ); * );
* // 从树结构中通过广度优先获取其所有的子节点 * // 从树结构中通过广度优先获取其所有的子节点
* List<Node> nodes = HierarchyUtil.traverseByBreadthFirst( * List<Node> nodes = HierarchyUtil.traverseByBreadthFirst(
* root, HierarchyUtil.collector(Node::getChildren) * root, HierarchyIteratorUtil.collect(Node::getChildren)
* ); * );
* }</pre> * }</pre>
* *
@ -123,17 +123,15 @@ public class HierarchyUtil {
Objects.requireNonNull(hierarchyIterator); Objects.requireNonNull(hierarchyIterator);
// 遍历层级结构 // 遍历层级结构
final Predicate<? super H> hierarchyFilter = filter.negate();
final LinkedList<H> queue = new LinkedList<>(); final LinkedList<H> queue = new LinkedList<>();
final Set<H> accessed = new HashSet<>(); final Set<H> accessed = new HashSet<>();
queue.add(hierarchy); queue.add(hierarchy);
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
// 跳过已经访问过或者被过滤的层级结构 // 跳过已经访问过或者被过滤的层级结构
final H curr = queue.removeFirst(); final H curr = queue.removeFirst();
if (accessed.contains(curr) || hierarchyFilter.test(curr)) { if (!accessed.add(curr) || !filter.test(curr)) {
continue; continue;
} }
accessed.add(curr);
// 若迭代器返回true则结束遍历 // 若迭代器返回true则结束遍历
if (hierarchyIterator.isBreak(curr)) { if (hierarchyIterator.isBreak(curr)) {

View File

@ -12,13 +12,12 @@
package org.dromara.hutool.core.tree.hierarchy; package org.dromara.hutool.core.tree.hierarchy;
import lombok.Data;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* test for {@link HierarchyUtil} * test for {@link HierarchyUtil}
@ -27,63 +26,72 @@ import java.util.stream.Collectors;
*/ */
class HierarchyUtilTest { class HierarchyUtilTest {
private Map<String, String> tree; @Data
static class Node {
private String parent;
private String value;
private List<Node> children;
public Node(final String parent, final String value) {
this.parent = parent;
this.value = value;
}
}
private Node root;
@BeforeEach @BeforeEach
void init() { void init() {
tree = new LinkedHashMap<>();
// 根节点 // 根节点
tree.put("0", null); root = new Node(null, "0");
// 第一层 // 第二层
tree.put("0-1", "0"); final Node first1 = new Node(root.value, "0-1");
tree.put("0-2", "0"); final Node first2 = new Node(root.value, "0-2");
tree.put("0-3", "0"); final Node first3 = new Node(root.value, "0-3");
root.setChildren(Arrays.asList(first1, first2, first3));
// 第三层 // 第三层
tree.put("0-1-1", "0-1"); final Node second11 = new Node(first1.value, "0-1-1");
tree.put("0-1-2", "0-1"); final Node second12 = new Node(first1.value, "0-1-2");
tree.put("0-1-3", "0-1"); final Node second13 = new Node(first1.value, "0-1-3");
first1.setChildren(Arrays.asList(second11, second12, second13));
tree.put("0-2-1", "0-2"); final Node second21 = new Node(first2.value, "0-2-1");
tree.put("0-2-2", "0-2"); final Node second22 = new Node(first2.value, "0-2-2");
tree.put("0-2-3", "0-2"); final Node second23 = new Node(first2.value, "0-2-3");
first2.setChildren(Arrays.asList(second21, second22, second23));
tree.put("0-3-1", "0-3"); final Node second31 = new Node(first3.value, "0-3-1");
tree.put("0-3-2", "0-3"); final Node second32 = new Node(first3.value, "0-3-2");
tree.put("0-3-3", "0-3"); final Node second33 = new Node(first3.value, "0-3-3");
first3.setChildren(Arrays.asList(second31, second32, second33));
} }
@Test @Test
void testTraverseByBreadthFirst() { void testTraverseByBreadthFirst() {
// 按广度优先遍历所有节点 // // 按广度优先遍历所有节点
final Set<String> nodes = new LinkedHashSet<>(); final List<String> nodes = new ArrayList<>();
HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.scan(t -> { HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.scan(t -> {
nodes.add(t); nodes.add(t.getValue());
return tree.entrySet().stream() return t.getChildren();
.filter(e -> Objects.equals(t, e.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
})); }));
Assertions.assertEquals(13, nodes.size()); Assertions.assertEquals(13, nodes.size());
Assertions.assertEquals( Assertions.assertEquals(
new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3")), Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3"),
nodes nodes
); );
// 按广度优先寻找 0-2-3 // 按广度优先寻找 0-2-3
final String target = HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.find(parentFinder(), final String target = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.find(Node::getChildren,
t -> Objects.equals(t, "0-2-3") ? t : null t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null
)); ));
Assertions.assertEquals("0-2-3", target); Assertions.assertEquals("0-2-3", target);
// 按广度优先获取 0-2 的所有子节点 // 按广度优先获取 0-2 的所有子节点
final List<String> children = HierarchyUtil.traverseByBreadthFirst( final List<String> children = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren,
"0", HierarchyIteratorUtil.collect(parentFinder(), t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null
t -> Objects.equals(tree.get(t), "0-2") ? t : null ));
)
);
Assertions.assertEquals(3, children.size()); Assertions.assertEquals(3, children.size());
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children); Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
} }
@ -92,40 +100,28 @@ class HierarchyUtilTest {
void testTraverseByDepthFirst() { void testTraverseByDepthFirst() {
// 按深度优先遍历所有节点 // 按深度优先遍历所有节点
final Set<String> nodes = new LinkedHashSet<>(); final Set<String> nodes = new LinkedHashSet<>();
HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.scan(t -> { HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.scan(t -> {
nodes.add(t); nodes.add(t.getValue());
return tree.entrySet().stream() return t.getChildren();
.filter(e -> Objects.equals(t, e.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
})); }));
Assertions.assertEquals(13, nodes.size()); Assertions.assertEquals(13, nodes.size());
Assertions.assertEquals( Assertions.assertEquals(
new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")), new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")),
nodes nodes
); );
// 按深度优先寻找 0-2-3 // 按深度优先寻找 0-2-3
final String target = HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.find(parentFinder(), final String target = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.find(Node::getChildren,
t -> Objects.equals(t, "0-2-3") ? t : null t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null
)); ));
Assertions.assertEquals("0-2-3", target); Assertions.assertEquals("0-2-3", target);
// 按深度优先获取 0-2 的所有子节点 // 按深度优先获取 0-2 的所有子节点
final List<String> children = HierarchyUtil.traverseByDepthFirst( final List<String> children = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren,
"0", HierarchyIteratorUtil.collect(parentFinder(), t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null
t -> Objects.equals(tree.get(t), "0-2") ? t : null ));
)
);
Assertions.assertEquals(3, children.size()); Assertions.assertEquals(3, children.size());
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children); Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
} }
private Function<String, Collection<String>> parentFinder() {
return t -> tree.entrySet()
.stream()
.filter(e -> Objects.equals(t, e.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
} }

View File

@ -302,9 +302,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @since 6.0.0 * @since 6.0.0
*/ */
public byte[] encrypt(final byte[] data, final byte[] salt) { public byte[] encrypt(final byte[] data, final byte[] salt) {
lock.lock();
byte[] result; byte[] result;
lock.lock();
try { try {
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, salt); final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, salt);
result = cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize())); result = cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize()));
@ -318,9 +317,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
@Override @Override
public void encrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException { public void encrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
lock.lock();
CipherOutputStream cipherOutputStream = null; CipherOutputStream cipherOutputStream = null;
lock.lock();
try { try {
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, null); final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, null);
cipherOutputStream = new CipherOutputStream(out, cipher); cipherOutputStream = new CipherOutputStream(out, cipher);
@ -358,10 +356,9 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
public byte[] decrypt(final byte[] bytes) { public byte[] decrypt(final byte[] bytes) {
final int blockSize; final int blockSize;
final byte[] decryptData; final byte[] decryptData;
lock.lock(); lock.lock();
final byte[] salt = SaltMagic.getSalt(bytes);
try { try {
final byte[] salt = SaltMagic.getSalt(bytes);
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, salt); final Cipher cipher = initMode(Cipher.DECRYPT_MODE, salt);
blockSize = cipher.getBlockSize(); blockSize = cipher.getBlockSize();
decryptData = cipher.doFinal(SaltMagic.getData(bytes)); decryptData = cipher.doFinal(SaltMagic.getData(bytes));
@ -376,8 +373,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
@Override @Override
public void decrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException { public void decrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
lock.lock();
CipherInputStream cipherInputStream = null; CipherInputStream cipherInputStream = null;
lock.lock();
try { try {
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, null); final Cipher cipher = initMode(Cipher.DECRYPT_MODE, null);
cipherInputStream = new CipherInputStream(data, cipher); cipherInputStream = new CipherInputStream(data, cipher);

View File

@ -160,8 +160,10 @@ public interface Dialect extends Serializable {
* @since 5.7.2 * @since 5.7.2
*/ */
default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException { default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException {
// https://gitee.com/dromara/hutool/issues/I713XQ
// 为了兼容informix等数据库此处使用count(*)而非count(1)
sqlBuilder = sqlBuilder sqlBuilder = sqlBuilder
.insertPreFragment("SELECT count(1) from(") .insertPreFragment("SELECT count(*) from(")
// issue#I3IJ8X@Gitee在子查询时需设置单独别名此处为了防止和用户的表名冲突使用自定义的较长别名 // issue#I3IJ8X@Gitee在子查询时需设置单独别名此处为了防止和用户的表名冲突使用自定义的较长别名
.append(") hutool_alias_count_"); .append(") hutool_alias_count_");
return psForPage(conn, sqlBuilder, null); return psForPage(conn, sqlBuilder, null);