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

This commit is contained in:
Looly 2023-07-24 23:51:49 +08:00
commit a24cf8d3d0
12 changed files with 315 additions and 100 deletions

View File

@ -1554,7 +1554,7 @@ public class CollUtil {
// String按照逗号分隔的列表对待
final String arrayStr = StrUtil.unWrap((CharSequence) value, '[', ']');
iter = SplitUtil.splitTrim(arrayStr, StrUtil.COMMA).iterator();
} else if(value instanceof Map && BeanUtil.isWritableBean(TypeUtil.getClass(elementType))){
} else if (value instanceof Map && BeanUtil.isWritableBean(TypeUtil.getClass(elementType))) {
//https://github.com/dromara/hutool/issues/3139
// 如果值为Map而目标为一个Bean则Map应整体转换为Bean而非拆分成Entry转换
iter = new ArrayIter<>(new Object[]{value});
@ -2354,4 +2354,49 @@ public class CollUtil {
}
return collection.stream().allMatch(predicate);
}
/**
* 解构多层集合
* 例如{@code List<List<List<String>>> 解构成 List<String>}
*
* @param <T> 元素类型
* @param collection 需要解构的集合
* @return 解构后的集合
*/
public static <T> List<T> flat(final Collection<?> collection) {
return flat(collection, true);
}
/**
* 解构多层集合
* 例如{@code List<List<List<String>>> 解构成 List<String>}
* <p>
* skipNull如果为true, 则解构后的集合里不包含null值为false则会包含null值
*
* @param <T> 元素类型
* @param collection 需要结构的集合
* @param skipNull 是否跳过空的值
* @return 解构后的集合
*/
@SuppressWarnings({"unchecked"})
public static <T> List<T> flat(final Collection<?> collection, final boolean skipNull) {
final LinkedList<Object> queue = new LinkedList<>(collection);
final List<Object> result = new ArrayList<>();
while (isNotEmpty(queue)) {
final Object t = queue.removeFirst();
if (skipNull && t == null) {
continue;
}
if (t instanceof Collection) {
queue.addAll((Collection<?>) t);
} else {
result.add(t);
}
}
return (List<T>) result;
}
}

View File

@ -12,6 +12,9 @@
package org.dromara.hutool.core.comparator;
import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.regex.PatternPool;
import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ObjUtil;
@ -87,6 +90,15 @@ public class VersionComparator implements Comparator<String>, Serializable {
diff = v1.length() - v2.length();
if (0 == diff) {
diff = v1.compareTo(v2);
}else {
// https://gitee.com/dromara/hutool/pulls/1043
//不同长度的先比较前面的数字前面数字不相等时按数字大小比较数字相等的时候继续按长度比较
final int v1Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v1, 0), 0);
final int v2Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v2, 0), 0);
final int diff1 = v1Num - v2Num;
if (diff1 != 0) {
diff = diff1;
}
}
if(diff != 0) {
//已有结果结束

View File

@ -13,6 +13,7 @@
package org.dromara.hutool.core.stream;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.collection.iter.IterUtil;
import org.dromara.hutool.core.lang.Console;
@ -486,6 +487,18 @@ public interface TransformableWrappedStream<T, S extends TransformableWrappedStr
return wrap(flatMap(recursive).peek(e -> childrenSetter.accept(e, null)));
}
/**
* 如果当前元素是集合则会将集合中的元素解构出来
* 例如{@code List<List<List<String>>> 解构成 List<String>}
*
* @param <R> 函数执行后返回的List里面的类型
* @return EasyStream 一个流
* @since 6.0.0
*/
default <R> EasyStream<R> flat() {
return EasyStream.of(CollUtil.flat(nonNull().collect(Collectors.toList())));
}
// endregion
// region ============ map ============

View File

@ -1,5 +1,6 @@
package org.dromara.hutool.core.collection;
import lombok.*;
import org.dromara.hutool.core.collection.iter.IterUtil;
import org.dromara.hutool.core.collection.set.SetUtil;
import org.dromara.hutool.core.comparator.CompareUtil;
@ -8,32 +9,10 @@ import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.map.Dict;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.*;
import java.util.function.Function;
/**
@ -669,7 +648,7 @@ public class CollUtilTest {
@Test
public void subInput1PositiveNegativePositiveOutputArrayIndexOutOfBoundsException() {
Assertions.assertThrows(IndexOutOfBoundsException.class, ()->{
Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {
// Arrange
final List<Integer> list = new ArrayList<>();
list.add(null);
@ -1224,4 +1203,55 @@ public class CollUtilTest {
final List<Pig> pig = Arrays.asList(new Pig("pig1", 12), new Pig("pig2", 12));
Assertions.assertEquals(CollUtil.unionDistinct(dog, cat, pig).size(), 5);
}
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
@Test
public void flatListTest1() {
final List<List<List<String>>> list = Arrays.asList(Arrays.asList(Arrays.asList("1", "2", "3"), Arrays.asList("5", "6", "7")));
final List<Object> objects = CollUtil.flat(list);
Assertions.assertArrayEquals(new String[]{"1", "2", "3", "5", "6", "7"}, objects.toArray());
}
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
@Test
public void flatListTest2() {
final List<List<List<String>>> list = Arrays.asList(
Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b", "c"),
Arrays.asList("d", "e", "f")
),
Arrays.asList(
Arrays.asList("g", "h", "i"),
Arrays.asList("j", "k", "l")
)
);
final List<Object> flat = CollUtil.flat(list);
Assertions.assertArrayEquals(new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}, flat.toArray());
}
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
@Test
void flatListTest3() {
final List<List<List<String>>> list = Arrays.asList(
Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b", "c", null),
Arrays.asList("d", "e", "f")
),
Arrays.asList(
Arrays.asList("g", "h", "i"),
Arrays.asList("j", "k", "l")
)
);
final List<Object> flat = CollUtil.flat(list, false);
Assertions.assertArrayEquals(new String[]{"a", "b", "c", null, "d", "e", "f", "g", "h", "i", "j", "k", "l"}, flat.toArray());
}
}

View File

@ -53,4 +53,10 @@ public class VersionComparatorTest {
final VersionComparator other = new VersionComparator();
Assertions.assertNotEquals(first, other);
}
@Test
public void versionComparatorTest7() {
final int compare = VersionComparator.INSTANCE.compare("1.12.2", "1.12.1c");
Assertions.assertTrue(compare > 0);
}
}

View File

@ -708,4 +708,23 @@ public class AbstractEnhancedWrappedStreamTest {
private List<Tree> children;
}
@Test
void test() {
List<List<List<String>>> list = Arrays.asList(
Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b", "c"),
Arrays.asList("d", "e", "f")
),
Arrays.asList(
Arrays.asList("g", "h", "i"),
Arrays.asList("j", "k", "l")
)
);
List<String> r = EasyStream.of(list).<String>flat().toList();
Assertions.assertArrayEquals(new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}, r.toArray());
}
}

View File

@ -24,7 +24,6 @@ import org.dromara.hutool.setting.Setting;
* @author Luxiaolei
*/
public final class DbUtil {
private final static Log log = Log.get();
/**
* 从配置文件中读取SQL打印选项读取后会去除相应属性
@ -34,25 +33,24 @@ public final class DbUtil {
*/
public static void setShowSqlGlobal(final Setting setting) {
// 初始化SQL显示
final boolean isShowSql = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_SQL), false);
final boolean isFormatSql = Convert.toBoolean(setting.remove(DSKeys.KEY_FORMAT_SQL), false);
final boolean isShowParams = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_PARAMS), false);
final boolean isShowSql = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_SQL));
final boolean isFormatSql = Convert.toBoolean(setting.remove(DSKeys.KEY_FORMAT_SQL));
final boolean isShowParams = Convert.toBoolean(setting.remove(DSKeys.KEY_SHOW_PARAMS));
String sqlLevelStr = setting.remove(DSKeys.KEY_SQL_LEVEL);
if (null != sqlLevelStr) {
sqlLevelStr = sqlLevelStr.toUpperCase();
}
final Level level = Convert.toEnum(Level.class, sqlLevelStr, Level.DEBUG);
log.debug("Show sql: [{}], format sql: [{}], show params: [{}], level: [{}]", isShowSql, isFormatSql, isShowParams, level);
final Level level = Convert.toEnum(Level.class, sqlLevelStr);
setShowSqlGlobal(isShowSql, isFormatSql, isShowParams, level);
}
/**
* 设置全局配置是否通过debug日志显示SQL
*
* @param isShowSql 是否显示SQL
* @param isFormatSql 是否格式化显示的SQL
* @param isShowParams 是否打印参数
* @param level SQL打印到的日志
* @param isShowSql 是否显示SQL{@code null}表示保持默认
* @param isFormatSql 是否格式化显示的SQL{@code null}表示保持默认
* @param isShowParams 是否打印参数{@code null}表示保持默认
* @param level 日志级{@code null}表示保持默认
* @see GlobalDbConfig#setShowSql(boolean, boolean, boolean, Level)
* @since 4.1.7
*/

View File

@ -112,10 +112,10 @@ public class GlobalDbConfig {
/**
* 设置全局配置是否通过debug日志显示SQL
*
* @param isShowSql 是否显示SQL
* @param isFormatSql 是否格式化显示的SQL
* @param isShowParams 是否打印参数
* @param level SQL打印到的日志
* @param isShowSql 是否显示SQL{@code null}表示保持默认
* @param isFormatSql 是否格式化显示的SQL{@code null}表示保持默认
* @param isShowParams 是否打印参数{@code null}表示保持默认
* @param level 日志级{@code null}表示保持默认
*/
public static void setShowSql(final boolean isShowSql, final boolean isFormatSql, final boolean isShowParams, final Level level) {
SqlLog.INSTANCE.init(isShowSql, isFormatSql, isShowParams, level);

View File

@ -12,6 +12,7 @@
package org.dromara.hutool.db.sql;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.db.DbRuntimeException;
@ -19,6 +20,7 @@ import org.dromara.hutool.db.Entity;
import org.dromara.hutool.db.Page;
import java.util.Collection;
import java.util.Set;
/**
* 查询对象用于传递查询所需的字段值<br>
@ -26,30 +28,45 @@ import java.util.Collection;
* 如果想自定义返回结果则可在查询对象中自定义要查询的字段名分页{@link Page}信息来自定义结果
*
* @author Looly
*
*/
public class Query implements Cloneable {
/** 查询的字段名列表 */
/**
* 查询的字段名列表
*/
Collection<String> fields;
/** 查询的表名 */
/**
* 查询的表名
*/
String[] tableNames;
/** 查询的条件语句 */
/**
* 查询的条件语句
*/
Condition[] where;
/** 分页对象 */
/**
* 分页对象
*/
Page page;
/**
* {@link Entity}构建Query
*
* @param where 条件查询{@link Entity}包含条件Map和表名
* @return Query
* @since 5.5.3
*/
public static Query of(final Entity where){
return new Query(SqlUtil.buildConditions(where), where.getTableName());
public static Query of(final Entity where) {
final Query query = new Query(SqlUtil.buildConditions(where), where.getTableName());
final Set<String> fieldNames = where.getFieldNames();
if (CollUtil.isNotEmpty(fieldNames)) {
query.setFields(fieldNames);
}
return query;
}
// --------------------------------------------------------------- Constructor start
/**
* 构造
*
@ -98,6 +115,7 @@ public class Query implements Cloneable {
// --------------------------------------------------------------- Constructor end
// --------------------------------------------------------------- Getters and Setters start
/**
* 获得查询的字段名列表
*

View File

@ -50,17 +50,27 @@ public class SqlLog {
/**
* 设置全局配置是否通过debug日志显示SQL
*
* @param isShowSql 是否显示SQL
* @param isFormatSql 是否格式化显示的SQL
* @param isShowParams 是否打印参数
* @param level 日志级别
* @param isShowSql 是否显示SQL{@code null}表示保持默认
* @param isFormatSql 是否格式化显示的SQL{@code null}表示保持默认
* @param isShowParams 是否打印参数{@code null}表示保持默认
* @param level 日志级别{@code null}表示保持默认
*/
public void init(final boolean isShowSql, final boolean isFormatSql, final boolean isShowParams, final Level level) {
public void init(final Boolean isShowSql, final Boolean isFormatSql, final Boolean isShowParams, final Level level) {
if (null != isShowSql) {
this.showSql = isShowSql;
}
if (null != isFormatSql) {
this.formatSql = isFormatSql;
}
if (null != isShowParams) {
this.showParams = isShowParams;
}
if (null != level) {
this.level = level;
}
log.debug("Show sql: [{}], format sql: [{}], show params: [{}], level: [{}]",
this.showSql, this.formatSql, this.showParams, this.level);
}
/**
* 打印SQL日志

View File

@ -41,7 +41,7 @@ public class UserInfo implements Serializable{
// JDK1.4 {@code user.country}JDK1.2 {@code user.region}
String userCountry = SystemUtil.get("user.country", false);
if(null == userCountry){
userCountry = SystemUtil.get("user.country", false);
userCountry = SystemUtil.get("user.region", false);
}
USER_COUNTRY = userCountry;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.json;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.dromara.hutool.core.reflect.TypeReference;
import org.dromara.hutool.json.serialize.JSONDeserializer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
/**
* https://gitee.com/dromara/hutool/issues/I7M2GZ
*/
public class IssueI7M2GZTest {
@Data
@AllArgsConstructor
public static class JSONBeanParserImpl implements JSONDeserializer<JSONBeanParserImpl> {
private String name;
private Integer parsed;
@Override
public JSONBeanParserImpl deserialize(final JSON json) {
setName("new Object");
setParsed(12);
return this;
}
}
@Data
public static class MyEntity<T> {
private List<T> list;
}
@Test
public void toListTest() {
final List<JSONBeanParserImpl> list = new ArrayList<>();
list.add(new JSONBeanParserImpl("Object1", 1));
final MyEntity<JSONBeanParserImpl> entity = new MyEntity<>();
entity.setList(list);
final String json = JSONUtil.toJsonStr(entity);
//Console.log(json);
final MyEntity<JSONBeanParserImpl> result = JSONUtil.toBean(json, new TypeReference<MyEntity<JSONBeanParserImpl>>() {});
Assertions.assertEquals("new Object", result.getList().get(0).getName());
Assertions.assertNotNull(result.getList().get(0).getParsed());
Assertions.assertEquals(Integer.valueOf(12), result.getList().get(0).getParsed());
}
}