diff --git a/CHANGELOG.md b/CHANGELOG.md index d74e0b4b4e..db857215e7 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ # 🚀Changelog +------------------------------------------------------------------------------------------------------------- +# 5.8.23(2023-11-12) + +### 🐣新特性 +* 【json 】 改进TemporalAccessorSerializer支持dayOfMonth和month枚举名(issue#I82AM8@Gitee) +* 【core 】 新增ProxySocketFactory +* 【http 】 UserAgent增加百度浏览器识别(issue#I847JY@Gitee) +* 【core 】 ReflectUtil.getFieldsValue增加Filter重载(pr#1090@Gitee) +* 【core 】 Snowflake增加方法:根据传入时间戳,计算ID起终点(pr#1096@Gitee) +* 【core 】 PathUtil增加loopFiles重载,可选是否追踪软链(issue#3353@Github) + +### 🐞Bug修复 +* 【cron 】 修复Cron表达式range解析错误问题(issue#I82CSH@Gitee) +* 【core 】 修复VersionComparator在极端数据排序时候违反了自反性问题(issue#I81N3H@Gitee) +* 【json 】 修复JSONStrFormatter:format函数对于转义符号处理逻辑错误问题(issue#I84V6I@Gitee) +* 【core 】 修复特定情况下BiMap覆盖Value后,仍能通过旧Value查询到Key问题(issue#I88R5M@Gitee) +* 【core 】 修复aop的afterException无法生效问题(issue#3329@Github) +* 【core 】 修复TypeUtil.getClass方法强转报错问题(pr#1092@Github) +* 【core 】 修复DataSize.parse(size)不支持空格问题(issue#I88Z4Z@Gitee) +* 【http 】 修复SimpleServer在添加的HttpFilter中有获取请求参数时报错问题(issue#3343@Github) +* 【http 】 修复options请求无响应体问题 +* 【core 】 ImgUtil的sliceByRowsAndCols背景无法透明问题(issue#3347@Github) +* 【core 】 修复ClassUtil#scanJar未正确关闭文件问题(issue#3361@Github) +* 【db 】 修复Column.getDigit返回值错误问题(issue#3370@Github) +* 【core 】 修复合成注解在并发环境无法保证正确缓存属性值的问题(pr#1097@Gitee) +* 【core 】 修复CollectorUtil.reduceListMap与collectors.groupby一起使用时出现与预期不符问题(pr#1102@Gitee) + ------------------------------------------------------------------------------------------------------------- # 5.8.22(2023-09-13) diff --git a/README-EN.md b/README-EN.md index 1c583342b3..12c571594d 100755 --- a/README-EN.md +++ b/README-EN.md @@ -46,6 +46,13 @@ ------------------------------------------------------------------------------- +

+ + +

+ +------------------------------------------------------------------------------- + [**🌎中文说明**](README.md) ------------------------------------------------------------------------------- @@ -144,18 +151,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop: cn.hutool hutool-all - 5.8.22 + 5.8.23 ``` ### 🍐Gradle ``` -implementation 'cn.hutool:hutool-all:5.8.22' +implementation 'cn.hutool:hutool-all:5.8.23' ``` ## 📥Download -- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.22/) +- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.23/) > 🔔️note: > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available. @@ -208,10 +215,3 @@ Hutool welcomes anyone to contribute code to Hutool, but the author suffers from ## ⭐Star Hutool [![Stargazers over time](https://starchart.cc/dromara/hutool.svg)](https://starchart.cc/dromara/hutool) - -## 📌WeChat Official Account - -
- - -
diff --git a/README.md b/README.md index 621c1cf89d..c3df8cd0b1 100755 --- a/README.md +++ b/README.md @@ -46,6 +46,13 @@ ------------------------------------------------------------------------------- +

+ + +

+ +------------------------------------------------------------------------------- + [**🌎English Documentation**](README-EN.md) ------------------------------------------------------------------------------- @@ -137,20 +144,20 @@ Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu cn.hutool hutool-all - 5.8.22 + 5.8.23 ``` ### 🍐Gradle ``` -implementation 'cn.hutool:hutool-all:5.8.22' +implementation 'cn.hutool:hutool-all:5.8.23' ``` ### 📥下载jar 点击以下链接,下载`hutool-all-X.X.X.jar`即可: -- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.22/) +- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.8.23/) > 🔔️注意 > Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 @@ -211,9 +218,3 @@ Hutool欢迎任何人为Hutool添砖加瓦,贡献代码,不过维护者是 ## ⭐Star Hutool [![Stargazers over time](https://starchart.cc/dromara/hutool.svg)](https://starchart.cc/dromara/hutool) - -## 📌 知识星球 - -
- -
diff --git a/bin/javadoc.sh b/bin/javadoc.sh index b9aaa39147..38eb2b683c 100755 --- a/bin/javadoc.sh +++ b/bin/javadoc.sh @@ -1,3 +1,6 @@ #!/bin/bash -exec mvn javadoc:javadoc +#exec mvn javadoc:javadoc + +# 多模块聚合文档,生成在target/site/apidocs +exec mvn javadoc:aggregate diff --git a/bin/version.txt b/bin/version.txt index 8050bf9ff8..e1ff3f5bae 100755 --- a/bin/version.txt +++ b/bin/version.txt @@ -1 +1 @@ -5.8.22 +5.8.23 diff --git a/docs/apidocs/index.html b/docs/apidocs/index.html index a283ef6661..a5ddd56400 100644 --- a/docs/apidocs/index.html +++ b/docs/apidocs/index.html @@ -2,32 +2,77 @@ - - - - Hutool API Docs - + + + Document + + + -
-
- -
- - -
- - -
-
-
- +
+
+ + hutool + +
+
+ + +
+
+
+ +
+ + +
+
+
- \ No newline at end of file + diff --git a/docs/js/version.js b/docs/js/version.js index ac35b07daa..9096578c01 100755 --- a/docs/js/version.js +++ b/docs/js/version.js @@ -1 +1 @@ -var version = '5.8.22' \ No newline at end of file +var version = '5.8.23' \ No newline at end of file diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml index 7e6d76bbb2..9ebe69fa5e 100755 --- a/hutool-all/pom.xml +++ b/hutool-all/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-all diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index 1e879544dd..116a07ea7b 100755 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-aop diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java index f0f7f9e900..39381f7253 100755 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java @@ -43,10 +43,14 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr try { // result = proxy.invokeSuper(obj, args); result = proxy.invoke(target, args); - } catch (InvocationTargetException e) { + } catch (final Throwable e) { + Throwable throwable = e; + if(throwable instanceof InvocationTargetException){ + throwable = ((InvocationTargetException) throwable).getTargetException(); + } // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) - if (aspect.afterException(target, method, args, e.getTargetException())) { - throw e; + if (aspect.afterException(target, method, args, throwable)) { + throw throwable; } } } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java index 8db4834690..7a3697e771 100755 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java @@ -48,9 +48,14 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr try { // result = proxy.invokeSuper(obj, args); result = proxy.invoke(target, args); - } catch (InvocationTargetException e) { + } catch (Throwable e) { + Throwable throwable = e; + if(throwable instanceof InvocationTargetException){ + throwable = ((InvocationTargetException) throwable).getTargetException(); + } + // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) - if (aspect.afterException(target, method, args, e.getTargetException())) { + if (aspect.afterException(target, method, args, throwable)) { throw e; } } diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml index 2802c292d2..972014aa9e 100755 --- a/hutool-bloomFilter/pom.xml +++ b/hutool-bloomFilter/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-bloomFilter diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml index b40c3c21d5..89acf6ca82 100755 --- a/hutool-bom/pom.xml +++ b/hutool-bom/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-bom diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml index 9a23018841..2f4d809cd2 100755 --- a/hutool-cache/pom.xml +++ b/hutool-cache/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-cache diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml index 6ea3742f56..0f358a72bb 100755 --- a/hutool-captcha/pom.xml +++ b/hutool-captcha/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-captcha diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index 22b41cbe65..6403f7c594 100755 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-core diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractAnnotationSynthesizer.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractAnnotationSynthesizer.java index 1b04ebdcf7..7ffdb0fb01 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractAnnotationSynthesizer.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AbstractAnnotationSynthesizer.java @@ -4,13 +4,13 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ObjectUtil; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; /** * {@link AnnotationSynthesizer}的基本实现 @@ -158,11 +158,19 @@ public Map, SynthesizedAnnotation> getAllSynthesized @SuppressWarnings("unchecked") @Override public A synthesize(Class annotationType) { - return (A)synthesizedProxyAnnotations.computeIfAbsent(annotationType, type -> { - final SynthesizedAnnotation synthesizedAnnotation = synthesizedAnnotationMap.get(annotationType); - return ObjectUtil.isNull(synthesizedAnnotation) ? - null : synthesize(annotationType, synthesizedAnnotation); - }); + A annotation = (A)synthesizedProxyAnnotations.get(annotationType); + if (Objects.nonNull(annotation)) { + return annotation; + } + synchronized (synthesizedProxyAnnotations) { + annotation = (A)synthesizedProxyAnnotations.get(annotationType); + if (Objects.isNull(annotation)) { + final SynthesizedAnnotation synthesizedAnnotation = synthesizedAnnotationMap.get(annotationType); + annotation = synthesize(annotationType, synthesizedAnnotation); + synthesizedProxyAnnotations.put(annotationType, annotation); + } + } + return annotation; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableAnnotationAttribute.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableAnnotationAttribute.java index e4c8bc94c5..5ef49f1ec8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableAnnotationAttribute.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableAnnotationAttribute.java @@ -14,7 +14,7 @@ */ public class CacheableAnnotationAttribute implements AnnotationAttribute { - private boolean valueInvoked; + private volatile boolean valueInvoked; private Object value; private boolean defaultValueInvoked; @@ -45,8 +45,12 @@ public Method getAttribute() { @Override public Object getValue() { if (!valueInvoked) { - valueInvoked = true; - value = ReflectUtil.invoke(annotation, attribute); + synchronized (this) { + if (!valueInvoked) { + valueInvoked = true; + value = ReflectUtil.invoke(annotation, attribute); + } + } } return value; } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java index ab7ae9ad69..c104856d75 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/CacheableSynthesizedAnnotationAttributeProcessor.java @@ -3,10 +3,10 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.map.multi.RowKeyTable; import cn.hutool.core.map.multi.Table; -import cn.hutool.core.util.ObjectUtil; import java.util.Collection; import java.util.Comparator; +import java.util.Objects; /** *

带缓存功能的{@link SynthesizedAnnotationAttributeProcessor}实现, @@ -47,16 +47,19 @@ public CacheableSynthesizedAnnotationAttributeProcessor() { @Override public T getAttributeValue(String attributeName, Class attributeType, Collection synthesizedAnnotations) { Object value = valueCaches.get(attributeName, attributeType); - // 此处理论上不可能出现缓存值为nul的情况 - if (ObjectUtil.isNotNull(value)) { - return (T)value; + if (Objects.isNull(value)) { + synchronized (valueCaches) { + value = valueCaches.get(attributeName, attributeType); + if (Objects.isNull(value)) { + value = synthesizedAnnotations.stream() + .filter(ma -> ma.hasAttribute(attributeName, attributeType)) + .min(annotationComparator) + .map(ma -> ma.getAttributeValue(attributeName)) + .orElse(null); + valueCaches.put(attributeName, attributeType, value); + } + } } - value = synthesizedAnnotations.stream() - .filter(ma -> ma.hasAttribute(attributeName, attributeType)) - .min(annotationComparator) - .map(ma -> ma.getAttributeValue(attributeName)) - .orElse(null); - valueCaches.put(attributeName, attributeType, value); return (T)value; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotationProxy.java b/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotationProxy.java index 233d849405..00b86c95de 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotationProxy.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/SynthesizedAnnotationProxy.java @@ -95,12 +95,13 @@ public static boolean isProxyAnnotation(Class annotationType) { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return Opt.ofNullable(methods.get(method.getName())) .map(m -> m.apply(method, args)) - .orElseGet(() -> ReflectUtil.invoke(this, method, args)); + .orElseGet(() -> ReflectUtil.invoke(annotation.getAnnotation(), method, args)); } // ========================= 代理方法 ========================= void loadMethods() { + // 非用户属性 methods.put("toString", (method, args) -> proxyToString()); methods.put("hashCode", (method, args) -> proxyHashCode()); methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation()); @@ -114,9 +115,11 @@ void loadMethods() { }); methods.put("getAttributeValue", (method, args) -> annotation.getAttributeValue((String) args[0])); methods.put("annotationType", (method, args) -> annotation.annotationType()); - for (final Method declaredMethod : ClassUtil.getDeclaredMethods(annotation.getAnnotation().annotationType())) { - methods.put(declaredMethod.getName(), (method, args) -> proxyAttributeValue(method)); - } + + // 可以被合成的用户属性 + Stream.of(ClassUtil.getDeclaredMethods(annotation.getAnnotation().annotationType())) + .filter(m -> !methods.containsKey(m.getName())) + .forEach(m -> methods.put(m.getName(), (method, args) -> proxyAttributeValue(method))); } private String proxyToString() { diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java index def62a6e69..680aa65298 100755 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base64.java @@ -251,7 +251,7 @@ public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) * base64解码 * * @param source 被解码的base64字符串 - * @return 被加密后的字符串 + * @return 密文解密的结果 * @since 4.3.2 */ public static String decodeStrGbk(CharSequence source) { @@ -262,7 +262,7 @@ public static String decodeStrGbk(CharSequence source) { * base64解码 * * @param source 被解码的base64字符串 - * @return 被加密后的字符串 + * @return 密文解密的结果 */ public static String decodeStr(CharSequence source) { return Base64Decoder.decodeStr(source); @@ -273,7 +273,7 @@ public static String decodeStr(CharSequence source) { * * @param source 被解码的base64字符串 * @param charset 字符集 - * @return 被加密后的字符串 + * @return 密文解密的结果 */ public static String decodeStr(CharSequence source, String charset) { return decodeStr(source, CharsetUtil.charset(charset)); @@ -284,7 +284,7 @@ public static String decodeStr(CharSequence source, String charset) { * * @param source 被解码的base64字符串 * @param charset 字符集 - * @return 被加密后的字符串 + * @return 密文解密的结果 */ public static String decodeStr(CharSequence source, Charset charset) { return Base64Decoder.decodeStr(source, charset); diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java index 989ae6c6ba..e99f343338 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java @@ -7,7 +7,6 @@ import cn.hutool.core.stream.StreamUtil; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java index 829a5b147a..eb21e7fd25 100755 --- a/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ListUtil.java @@ -2,7 +2,6 @@ import cn.hutool.core.comparator.PinyinComparator; import cn.hutool.core.comparator.PropertyComparator; -import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Matcher; import cn.hutool.core.lang.Validator; diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/VersionComparator.java b/hutool-core/src/main/java/cn/hutool/core/comparator/VersionComparator.java index 7538f86775..0e12a8389d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/VersionComparator.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/VersionComparator.java @@ -1,15 +1,12 @@ package cn.hutool.core.comparator; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.PatternPool; -import cn.hutool.core.util.CharUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.ReUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.*; import java.io.Serializable; import java.util.Comparator; import java.util.List; +import java.util.regex.Pattern; /** * 版本比较器
@@ -24,6 +21,8 @@ public class VersionComparator implements Comparator, Serializable { private static final long serialVersionUID = 8083701245147495562L; + private static final Pattern PATTERN_PRE_NUMBERS= Pattern.compile("^\\d+"); + /** 单例 */ public static final VersionComparator INSTANCE = new VersionComparator(); @@ -80,12 +79,15 @@ public int compare(String version1, String version2) { if (0 == diff) { diff = v1.compareTo(v2); }else { - //不同长度的先比较前面的数字;前面数字不相等时,按数字大小比较;数字相等的时候,继续按长度比较, - int v1Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v1, 0), 0); - int v2Num = Convert.toInt(ReUtil.get(PatternPool.NUMBERS, v2, 0), 0); - int diff1 = v1Num - v2Num; - if (diff1 != 0) { - diff = diff1; + // 不同长度,且含有字母 + if(!NumberUtil.isNumber(v1) || !NumberUtil.isNumber(v2)){ + //不同长度的先比较前面的数字;前面数字不相等时,按数字大小比较;数字相等的时候,继续按长度比较,类似于 103 > 102a + final int v1Num = Convert.toInt(ReUtil.get(PATTERN_PRE_NUMBERS, v1, 0), 0); + final int v2Num = Convert.toInt(ReUtil.get(PATTERN_PRE_NUMBERS, v2, 0), 0); + final int diff1 = v1Num - v2Num; + if (diff1 != 0) { + diff = diff1; + } } } if(diff != 0) { diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 16cb2e9c94..d9cda806fe 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -3,7 +3,6 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.convert.impl.*; import cn.hutool.core.date.DateTime; -import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.TypeReference; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java index 4dc10e5686..42abb70f6c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java @@ -6,7 +6,6 @@ import cn.hutool.core.bean.copier.ValueProvider; import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.ConvertException; -import cn.hutool.core.lang.Console; import cn.hutool.core.map.MapProxy; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/img/Img.java b/hutool-core/src/main/java/cn/hutool/core/img/Img.java index bfa3ca04fe..375241b148 100755 --- a/hutool-core/src/main/java/cn/hutool/core/img/Img.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/Img.java @@ -133,7 +133,7 @@ public static Img from(URL imageUrl) { * @return Img */ public static Img from(Image image) { - return new Img(ImgUtil.toBufferedImage(image)); + return new Img(ImgUtil.castToBufferedImage(image, ImgUtil.IMAGE_TYPE_JPG)); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java index 536897c00b..a27238a391 100755 --- a/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/ImgUtil.java @@ -455,11 +455,7 @@ public static void sliceByRowsAndCols(File srcImageFile, File destDir, int rows, * @param cols 目标切片列数。默认2,必须是范围 [1, 20] 之内 */ public static void sliceByRowsAndCols(File srcImageFile, File destDir, String format, int rows, int cols) { - try { - sliceByRowsAndCols(ImageIO.read(srcImageFile), destDir, format, rows, cols); - } catch (IOException e) { - throw new IORuntimeException(e); - } + sliceByRowsAndCols(read(srcImageFile), destDir, format, rows, cols); } /** @@ -491,32 +487,27 @@ public static void sliceByRowsAndCols(Image srcImage, File destDir, String forma throw new IllegalArgumentException("Destination Dir must be a Directory !"); } - try { - if (rows <= 0 || rows > 20) { - rows = 2; // 切片行数 - } - if (cols <= 0 || cols > 20) { - cols = 2; // 切片列数 - } - // 读取源图像 - final BufferedImage bi = toBufferedImage(srcImage); - int srcWidth = bi.getWidth(); // 源图宽度 - int srcHeight = bi.getHeight(); // 源图高度 - - int destWidth = NumberUtil.partValue(srcWidth, cols); // 每张切片的宽度 - int destHeight = NumberUtil.partValue(srcHeight, rows); // 每张切片的高度 - - // 循环建立切片 - Image tag; - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - tag = cut(bi, new Rectangle(j * destWidth, i * destHeight, destWidth, destHeight)); - // 输出为文件 - ImageIO.write(toRenderedImage(tag), format, new File(destDir, "_r" + i + "_c" + j + "." + format)); - } + if (rows <= 0 || rows > 20) { + rows = 2; // 切片行数 + } + if (cols <= 0 || cols > 20) { + cols = 2; // 切片列数 + } + // 读取源图像 + int srcWidth = srcImage.getWidth(null); // 源图宽度 + int srcHeight = srcImage.getHeight(null); // 源图高度 + + int destWidth = NumberUtil.partValue(srcWidth, cols); // 每张切片的宽度 + int destHeight = NumberUtil.partValue(srcHeight, rows); // 每张切片的高度 + + // 循环建立切片 + Image tag; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + tag = cut(srcImage, new Rectangle(j * destWidth, i * destHeight, destWidth, destHeight)); + // 输出为文件 + write(tag, new File(destDir, "_r" + i + "_c" + j + "." + format)); } - } catch (IOException e) { - throw new IORuntimeException(e); } } @@ -573,8 +564,9 @@ public static void convert(InputStream srcStream, String formatName, OutputStrea * @since 4.1.14 */ public static void convert(Image srcImage, String formatName, ImageOutputStream destImageStream, boolean isSrcPng) { + final BufferedImage src = toBufferedImage(srcImage, isSrcPng ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); try { - ImageIO.write(isSrcPng ? copyImage(srcImage, BufferedImage.TYPE_INT_RGB) : toBufferedImage(srcImage), formatName, destImageStream); + ImageIO.write(src, formatName, destImageStream); } catch (IOException e) { throw new IORuntimeException(e); } @@ -1157,28 +1149,57 @@ public static void compress(File imageFile, File outFile, float quality) throws * @param img {@link Image} * @return {@link BufferedImage} * @since 4.3.2 + * @deprecated 改用 {@link #castToRenderedImage(Image, String)} */ + @Deprecated public static RenderedImage toRenderedImage(Image img) { + return castToRenderedImage(img, IMAGE_TYPE_JPG); + } + + /** + * {@link Image} 转 {@link BufferedImage}
+ * 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 {@link BufferedImage#TYPE_INT_RGB} 模式 + * + * @param img {@link Image} + * @return {@link BufferedImage} + * @deprecated 改用 {@link #castToBufferedImage(Image, String)} + */ + @Deprecated + public static BufferedImage toBufferedImage(Image img) { + return castToBufferedImage(img, IMAGE_TYPE_JPG); + } + + /** + * {@link Image} 转 {@link RenderedImage}
+ * 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 {@link BufferedImage#TYPE_INT_RGB} 模式。 + * + * @param img {@link Image} + * @param imageType 目标图片类型,例如jpg或png等 + * @return {@link BufferedImage} + * @since 4.3.2 + */ + public static RenderedImage castToRenderedImage(final Image img, final String imageType) { if (img instanceof RenderedImage) { return (RenderedImage) img; } - return copyImage(img, BufferedImage.TYPE_INT_RGB); + return toBufferedImage(img, imageType); } /** * {@link Image} 转 {@link BufferedImage}
- * 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 {@link BufferedImage#TYPE_INT_RGB} 模式 + * 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 imageType 模式 * * @param img {@link Image} + * @param imageType 目标图片类型,例如jpg或png等 * @return {@link BufferedImage} */ - public static BufferedImage toBufferedImage(Image img) { + public static BufferedImage castToBufferedImage(final Image img, final String imageType) { if (img instanceof BufferedImage) { return (BufferedImage) img; } - return copyImage(img, BufferedImage.TYPE_INT_RGB); + return toBufferedImage(img, imageType); } /** @@ -1687,7 +1708,7 @@ public static boolean write(Image image, ImageWriter writer, ImageOutputStream o } writer.setOutput(output); - final RenderedImage renderedImage = toRenderedImage(image); + final RenderedImage renderedImage = castToRenderedImage(image, IMAGE_TYPE_JPG); // 设置质量 ImageWriteParam imgWriteParams = null; if (quality > 0 && quality < 1) { diff --git a/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java b/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java index 23da5136d0..0c5c8c505d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java @@ -606,7 +606,7 @@ protected void readContents() { for (int i = 0; i < 11; i++) { app.append((char) block[i]); } - if ("NETSCAPE2.0".equals(app.toString())) { + if ("NETSCAPE2.0".contentEquals(app)) { readNetscapeExt(); } else { skip(); // don't care diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java index 78a58c6758..cf3b6568eb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java @@ -1,10 +1,10 @@ package cn.hutool.core.io.file; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.file.visitor.CopyVisitor; import cn.hutool.core.io.file.visitor.DelVisitor; -import cn.hutool.core.io.file.visitor.MoveVisitor; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.CharsetUtil; @@ -20,7 +20,6 @@ import java.nio.file.AccessDeniedException; import java.nio.file.CopyOption; import java.nio.file.DirectoryStream; -import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -33,6 +32,7 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; +import java.util.Set; /** * NIO中Path对象操作封装 @@ -80,11 +80,26 @@ public static List loopFiles(Path path, FileFilter fileFilter) { * @since 5.4.1 */ public static List loopFiles(Path path, int maxDepth, FileFilter fileFilter) { + return loopFiles(path, maxDepth, false, fileFilter); + } + + /** + * 递归遍历目录以及子目录中的所有文件
+ * 如果提供path为文件,直接返回过滤结果 + * + * @param path 当前遍历文件或目录 + * @param maxDepth 遍历最大深度,-1表示遍历到没有目录为止 + * @param isFollowLinks 是否跟踪软链(快捷方式) + * @param fileFilter 文件过滤规则对象,选择要保留的文件,只对文件有效,不过滤目录,null表示接收全部文件 + * @return 文件列表 + * @since 5.4.1 + */ + public static List loopFiles(final Path path, final int maxDepth, final boolean isFollowLinks, final FileFilter fileFilter) { final List fileList = new ArrayList<>(); - if (null == path || false == Files.exists(path)) { + if (!exists(path, isFollowLinks)) { return fileList; - } else if (false == isDirectory(path)) { + } else if (!isDirectory(path, isFollowLinks)) { final File file = path.toFile(); if (null == fileFilter || fileFilter.accept(file)) { fileList.add(file); @@ -92,10 +107,10 @@ public static List loopFiles(Path path, int maxDepth, FileFilter fileFilte return fileList; } - walkFiles(path, maxDepth, new SimpleFileVisitor() { + walkFiles(path, maxDepth, isFollowLinks, new SimpleFileVisitor() { @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { + public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) { final File file = path.toFile(); if (null == fileFilter || fileFilter.accept(file)) { fileList.add(file); @@ -129,14 +144,28 @@ public static void walkFiles(Path start, FileVisitor visitor) { * @since 4.6.3 */ public static void walkFiles(Path start, int maxDepth, FileVisitor visitor) { + walkFiles(start, maxDepth, false, visitor); + } + + /** + * 遍历指定path下的文件并做处理 + * + * @param start 起始路径,必须为目录 + * @param maxDepth 最大遍历深度,-1表示不限制深度 + * @param visitor {@link FileVisitor} 接口,用于自定义在访问文件时,访问目录前后等节点做的操作 + * @param isFollowLinks 是否追踪到软链对应的真实地址 + * @see Files#walkFileTree(Path, java.util.Set, int, FileVisitor) + * @since 5.8.23 + */ + public static void walkFiles(final Path start, int maxDepth, final boolean isFollowLinks, final FileVisitor visitor) { if (maxDepth < 0) { // < 0 表示遍历到最底层 maxDepth = Integer.MAX_VALUE; } try { - Files.walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), maxDepth, visitor); - } catch (IOException e) { + Files.walkFileTree(start, getFileVisitOption(isFollowLinks), maxDepth, visitor); + } catch (final IOException e) { throw new IORuntimeException(e); } } @@ -283,8 +312,7 @@ public static boolean isDirectory(Path path, boolean isFollowLinks) { if (null == path) { return false; } - final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; - return Files.isDirectory(path, options); + return Files.isDirectory(path, getLinkOptions(isFollowLinks)); } /** @@ -368,9 +396,8 @@ public static BasicFileAttributes getAttributes(Path path, boolean isFollowLinks return null; } - final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; try { - return Files.readAttributes(path, BasicFileAttributes.class, options); + return Files.readAttributes(path, BasicFileAttributes.class, getLinkOptions(isFollowLinks)); } catch (IOException e) { throw new IORuntimeException(e); } @@ -541,8 +568,7 @@ public static boolean isFile(Path path, boolean isFollowLinks) { if (null == path) { return false; } - final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; - return Files.isRegularFile(path, options); + return Files.isRegularFile(path, getLinkOptions(isFollowLinks)); } /** @@ -565,8 +591,7 @@ public static boolean isSymlink(Path path) { * @since 5.5.3 */ public static boolean exists(Path path, boolean isFollowLinks) { - final LinkOption[] options = isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; - return Files.exists(path, options); + return Files.exists(path, getLinkOptions(isFollowLinks)); } /** @@ -714,4 +739,27 @@ protected static void delFile(Path path) throws IOException { } } } + + /** + * 构建是否追踪软链的选项 + * + * @param isFollowLinks 是否追踪软链 + * @return 选项 + * @since 5.8.23 + */ + public static LinkOption[] getLinkOptions(final boolean isFollowLinks) { + return isFollowLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; + } + + /** + * 构建是否追踪软链的选项 + * + * @param isFollowLinks 是否追踪软链 + * @return 选项 + * @since 5.8.23 + */ + public static Set getFileVisitOption(final boolean isFollowLinks) { + return isFollowLinks ? EnumSet.of(FileVisitOption.FOLLOW_LINKS) : + EnumSet.noneOf(FileVisitOption.class); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java index ab65a90700..4e07b091d0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java @@ -1,14 +1,12 @@ package cn.hutool.core.io.resource; import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.URLUtil; import java.io.*; import java.net.URI; import java.net.URL; -import java.net.URLConnection; /** * URL资源访问类 diff --git a/hutool-core/src/main/java/cn/hutool/core/io/unit/DataSize.java b/hutool-core/src/main/java/cn/hutool/core/io/unit/DataSize.java index 00a8e6bc51..8fa074a31a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/unit/DataSize.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/unit/DataSize.java @@ -185,7 +185,7 @@ public static DataSize parse(CharSequence text) { public static DataSize parse(CharSequence text, DataUnit defaultUnit) { Assert.notNull(text, "Text must not be null"); try { - final Matcher matcher = PATTERN.matcher(text); + final Matcher matcher = PATTERN.matcher(StrUtil.cleanBlank(text)); Assert.state(matcher.matches(), "Does not match data size pattern"); final DataUnit unit = determineDataUnit(matcher.group(3), defaultUnit); diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java b/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java index 1a118de2f6..bb78bf8ae3 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ClassScanner.java @@ -5,6 +5,7 @@ import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.*; @@ -356,22 +357,26 @@ private void scanFile(File file, String rootDir) { } /** - * 扫描jar包 + * 扫描jar包,扫描结束后关闭jar文件 * * @param jar jar包 */ private void scanJar(JarFile jar) { - String name; - for (JarEntry entry : new EnumerationIter<>(jar.entries())) { - name = StrUtil.removePrefix(entry.getName(), StrUtil.SLASH); - if (StrUtil.isEmpty(packagePath) || name.startsWith(this.packagePath)) { - if (name.endsWith(FileUtil.CLASS_EXT) && false == entry.isDirectory()) { - final String className = name// + try{ + String name; + for (JarEntry entry : new EnumerationIter<>(jar.entries())) { + name = StrUtil.removePrefix(entry.getName(), StrUtil.SLASH); + if (StrUtil.isEmpty(packagePath) || name.startsWith(this.packagePath)) { + if (name.endsWith(FileUtil.CLASS_EXT) && false == entry.isDirectory()) { + final String className = name// .substring(0, name.length() - 6)// .replace(CharUtil.SLASH, CharUtil.DOT);// - addIfAccept(loadClass(className)); + addIfAccept(loadClass(className)); + } } } + } finally { + IoUtil.close(jar); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java b/hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java index c9eeac826c..84ae4e7c33 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java @@ -198,6 +198,40 @@ public long getGenerateDateTime(long id) { return (id >> TIMESTAMP_LEFT_SHIFT & ~(-1L << 41L)) + twepoch; } + /** + * 根据传入时间戳-计算ID起终点 + * + * @param timestampStart 开始时间戳 + * @param timestampEnd 结束时间戳 + * @return key-ID起点,Value-ID终点 + * @since 5.8.23 + */ + public Pair getIdScopeByTimestamp(long timestampStart, long timestampEnd) { + return getIdScopeByTimestamp(timestampStart, timestampEnd, true); + } + + /** + * 根据传入时间戳-计算ID起终点 Gitee/issues/I60M14 + * + * @param timestampStart 开始时间戳 + * @param timestampEnd 结束时间戳 + * @param ignoreCenterAndWorker 是否忽略数据中心和机器节点的占位,忽略后可获得分布式环境全局可信赖的起终点。 + * @return key-ID起点,Value-ID终点 + * @since 5.8.23 + */ + public Pair getIdScopeByTimestamp(long timestampStart, long timestampEnd, boolean ignoreCenterAndWorker) { + long startTimeMinId = (timestampStart - twepoch) << TIMESTAMP_LEFT_SHIFT; + long endTimeMinId = (timestampEnd - twepoch) << TIMESTAMP_LEFT_SHIFT; + if (ignoreCenterAndWorker) { + long endId = endTimeMinId | ~(-1 << TIMESTAMP_LEFT_SHIFT); + return Pair.of(startTimeMinId, endId); + } else { + long startId = startTimeMinId | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT); + long endId = endTimeMinId | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | SEQUENCE_MASK; + return Pair.of(startId, endId); + } + } + /** * 下一个ID * diff --git a/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java b/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java index 3ce87cc9f5..a376d71f17 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/BiMap.java @@ -30,7 +30,13 @@ public BiMap(Map raw) { @Override public V put(K key, V value) { + final V oldValue = super.put(key, value); if (null != this.inverse) { + if(null != oldValue){ + // issue#I88R5M + // 如果put的key相同,value不同,需要在inverse中移除旧的关联 + this.inverse.remove(oldValue); + } this.inverse.put(value, key); } return super.put(key, value); diff --git a/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsCollValueMap.java b/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsCollValueMap.java index 921e858886..3ab7e27db9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsCollValueMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/multi/AbsCollValueMap.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; /** diff --git a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java index 660066485d..720e6bc3ab 100755 --- a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java @@ -24,12 +24,18 @@ /** * 网络相关工具 * - * @author xiaoleilu + * @author looly */ public class NetUtil { + /** + * 本地IPv4地址 + */ public final static String LOCAL_IP = Ipv4Util.LOCAL_IP; + /** + * 本地主机名称 + */ public static String localhostName; /** @@ -500,8 +506,8 @@ public static InetAddress getLocalhost() { final LinkedHashSet localAddressList = localAddressList(address -> { // 非loopback地址,指127.*.*.*的地址 return false == address.isLoopbackAddress() - // 需为IPV4地址 - && address instanceof Inet4Address; + // 需为IPV4地址 + && address instanceof Inet4Address; }); if (CollUtil.isNotEmpty(localAddressList)) { diff --git a/hutool-core/src/main/java/cn/hutool/core/net/ProxySocketFactory.java b/hutool-core/src/main/java/cn/hutool/core/net/ProxySocketFactory.java new file mode 100644 index 0000000000..ca17e68200 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/net/ProxySocketFactory.java @@ -0,0 +1,85 @@ +package cn.hutool.core.net; + +import javax.net.SocketFactory; +import java.io.IOException; +import java.net.*; + +/** + * 代理Socket工厂,用于创建代理Socket
+ * 来自commons-net的DefaultSocketFactory + * + * @author commons-net, looly + * @since 5.8.23 + */ +public class ProxySocketFactory extends SocketFactory { + + /** + * 创建代理SocketFactory + * @param proxy 代理对象 + * @return {@code ProxySocketFactory} + */ + public static ProxySocketFactory of(final Proxy proxy) { + return new ProxySocketFactory(proxy); + } + + private final Proxy proxy; + + /** + * 构造 + * + * @param proxy Socket代理 + */ + public ProxySocketFactory(final Proxy proxy) { + this.proxy = proxy; + } + + @Override + public Socket createSocket() { + if (proxy != null) { + return new Socket(proxy); + } + return new Socket(); + } + + @Override + public Socket createSocket(final InetAddress address, final int port) throws IOException { + if (proxy != null) { + final Socket s = new Socket(proxy); + s.connect(new InetSocketAddress(address, port)); + return s; + } + return new Socket(address, port); + } + + @Override + public Socket createSocket(final InetAddress address, final int port, final InetAddress localAddr, final int localPort) throws IOException { + if (proxy != null) { + final Socket s = new Socket(proxy); + s.bind(new InetSocketAddress(localAddr, localPort)); + s.connect(new InetSocketAddress(address, port)); + return s; + } + return new Socket(address, port, localAddr, localPort); + } + + @Override + public Socket createSocket(final String host, final int port) throws IOException { + if (proxy != null) { + final Socket s = new Socket(proxy); + s.connect(new InetSocketAddress(host, port)); + return s; + } + return new Socket(host, port); + } + + @Override + public Socket createSocket(final String host, final int port, final InetAddress localAddr, final int localPort) throws IOException { + if (proxy != null) { + final Socket s = new Socket(proxy); + s.bind(new InetSocketAddress(localAddr, localPort)); + s.connect(new InetSocketAddress(host, port)); + return s; + } + return new Socket(host, port, localAddr, localPort); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java index 4e399e369f..7cce5c039b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/URLDecoder.java @@ -1,6 +1,5 @@ package cn.hutool.core.net; -import cn.hutool.core.lang.Console; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index f474c53eae..85969e0bc5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -31,7 +31,7 @@ public class CollectorUtil { * 说明已包含IDENTITY_FINISH特征 为 Characteristics.IDENTITY_FINISH 的缩写 */ public static final Set CH_ID - = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); + = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); /** * 说明不包含IDENTITY_FINISH特征 */ @@ -76,11 +76,11 @@ public class CollectorUtil { CharSequence suffix, Function toStringFunc) { return new SimpleCollector<>( - () -> new StringJoiner(delimiter, prefix, suffix), - (joiner, ele) -> joiner.add(toStringFunc.apply(ele)), - StringJoiner::merge, - StringJoiner::toString, - Collections.emptySet() + () -> new StringJoiner(delimiter, prefix, suffix), + (joiner, ele) -> joiner.add(toStringFunc.apply(ele)), + StringJoiner::merge, + StringJoiner::toString, + Collections.emptySet() ); } @@ -191,7 +191,7 @@ public class CollectorUtil { BinaryOperator mergeFunction, Supplier mapSupplier) { BiConsumer accumulator - = (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get()); + = (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get()); return new SimpleCollector<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); } @@ -239,13 +239,15 @@ public static > BinaryOperator mapMerger(BinaryOper */ public static >> Collector, ?, R> reduceListMap(final Supplier mapSupplier) { return Collectors.reducing(mapSupplier.get(), value -> { - final R result = mapSupplier.get(); - value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); - return result; - }, (l, r) -> { - r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v)); - return l; - } + final R result = mapSupplier.get(); + value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); + return result; + }, (l, r) -> { + final R resultMap = mapSupplier.get(); + resultMap.putAll(l); + r.forEach((k, v) -> resultMap.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v)); + return resultMap; + } ); } @@ -265,12 +267,12 @@ public static > BinaryOperator mapMerger(BinaryOper * @return {@link Collector} */ public static , M extends Map> Collector groupingBy( - final Function classifier, - final Function valueMapper, - final Supplier valueCollFactory, - final Supplier mapFactory) { + final Function classifier, + final Function valueMapper, + final Supplier valueCollFactory, + final Supplier mapFactory) { return groupingBy(classifier, mapFactory, Collectors.mapping( - valueMapper, Collectors.toCollection(valueCollFactory) + valueMapper, Collectors.toCollection(valueCollFactory) )); } @@ -288,9 +290,9 @@ public static > BinaryOperator mapMerger(BinaryOper * @return {@link Collector} */ public static > Collector> groupingBy( - final Function classifier, - final Function valueMapper, - final Supplier valueCollFactory) { + final Function classifier, + final Function valueMapper, + final Supplier valueCollFactory) { return groupingBy(classifier, valueMapper, valueCollFactory, HashMap::new); } @@ -298,16 +300,16 @@ public static > BinaryOperator mapMerger(BinaryOper * 提供对null值友好的groupingBy操作的{@link Collector}实现, * 对集合分组,然后对分组后的值集合进行映射 * - * @param classifier 分组依据 - * @param valueMapper 值映射方法 - * @param 元素类型 - * @param 键类型 - * @param 值类型 + * @param classifier 分组依据 + * @param valueMapper 值映射方法 + * @param 元素类型 + * @param 键类型 + * @param 值类型 * @return {@link Collector} */ public static Collector>> groupingBy( - final Function classifier, - final Function valueMapper) { + final Function classifier, + final Function valueMapper) { return groupingBy(classifier, valueMapper, ArrayList::new, HashMap::new); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java index e626df6800..3cd6898e3e 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java @@ -187,7 +187,7 @@ public static Field[] getFields(Class beanClass) throws SecurityException { * 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。 * * @param beanClass 类 - * @param fieldFilter field过滤器,过滤掉不需要的field + * @param fieldFilter field过滤器,过滤掉不需要的field,{@code null}返回原集合 * @return 字段列表 * @throws SecurityException 安全检查异常 * @since 5.7.14 @@ -286,14 +286,22 @@ public static Object getFieldValue(Object obj, Field field) throws UtilException * @since 4.1.17 */ public static Object[] getFieldsValue(Object obj) { + return getFieldsValue(obj, null); + } + + /** + * 获取所有字段的值 + * + * @param obj bean对象,如果是static字段,此处为类class + * @param filter 字段过滤器,,{@code null}返回原集合 + * @return 字段值数组 + * @since 5.8.23 + */ + public static Object[] getFieldsValue(Object obj, Filter filter) { if (null != obj) { - final Field[] fields = getFields(obj instanceof Class ? (Class) obj : obj.getClass()); + final Field[] fields = getFields(obj instanceof Class ? (Class) obj : obj.getClass(), filter); if (null != fields) { - final Object[] values = new Object[fields.length]; - for (int i = 0; i < fields.length; i++) { - values[i] = getFieldValue(obj, fields[i]); - } - return values; + return ArrayUtil.map(fields, Object.class, field -> getFieldValue(obj, field)); } } return null; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java index 8188694e4a..70d92ca41d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/TypeUtil.java @@ -1,6 +1,5 @@ package cn.hutool.core.util; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.ParameterizedTypeImpl; import cn.hutool.core.lang.reflect.ActualTypeMapperPool; @@ -41,7 +40,10 @@ public static Class getClass(Type type) { } else if (type instanceof ParameterizedType) { return (Class) ((ParameterizedType) type).getRawType(); } else if (type instanceof TypeVariable) { - return (Class) ((TypeVariable) type).getBounds()[0]; + Type[] bounds = ((TypeVariable) type).getBounds(); + if (bounds.length == 1) { + return getClass(bounds[0]); + } } else if (type instanceof WildcardType) { final Type[] upperBounds = ((WildcardType) type).getUpperBounds(); if (upperBounds.length == 1) { diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index 1c724e477a..8765d96e38 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -29,20 +29,20 @@ public void getCombinationAnnotationsWithClassTest(){ final AnnotationForTest[] annotations = AnnotationUtil.getCombinationAnnotations(ClassWithAnnotation.class, AnnotationForTest.class); Assert.assertNotNull(annotations); Assert.assertEquals(1, annotations.length); - Assert.assertEquals("测试", annotations[0].value()); + Assert.assertTrue(annotations[0].value().equals("测试") || annotations[0].value().equals("repeat-annotation")); } @Test public void getAnnotationValueTest() { final Object value = AnnotationUtil.getAnnotationValue(ClassWithAnnotation.class, AnnotationForTest.class); - Assert.assertEquals("测试", value); + Assert.assertTrue(value.equals("测试") || value.equals("repeat-annotation")); } @Test public void getAnnotationValueTest2() { final String[] names = AnnotationUtil.getAnnotationValue(ClassWithAnnotation.class, AnnotationForTest::names); - Assert.assertTrue(ArrayUtil.equals(names, new String[]{"测试1", "测试2"})); + Assert.assertTrue(names.length == 1 && names[0].isEmpty() || ArrayUtil.equals(names, new String[]{"测试1", "测试2"})); } @Test @@ -52,7 +52,8 @@ public void getAnnotationSyncAlias() { // 加别名适配 final AnnotationForTest annotation = AnnotationUtil.getAnnotationAlias(ClassWithAnnotation.class, AnnotationForTest.class); - Assert.assertEquals("测试", annotation.retry()); + String retryValue = annotation.retry(); + Assert.assertTrue(retryValue.equals("测试") || retryValue.equals("repeat-annotation")); Assert.assertTrue(AnnotationUtil.isSynthesizedAnnotation(annotation)); } @@ -78,9 +79,12 @@ public void scanMetaAnnotationTest() { // -> RootMetaAnnotation3 final List annotations = AnnotationUtil.scanMetaAnnotation(RootAnnotation.class); Assert.assertEquals(4, annotations.size()); - Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(0).annotationType()); - Assert.assertEquals(RootMetaAnnotation1.class, annotations.get(1).annotationType()); - Assert.assertEquals(RootMetaAnnotation2.class, annotations.get(2).annotationType()); + Assert.assertTrue(annotations.get(0).annotationType() == RootMetaAnnotation3.class || + annotations.get(0).annotationType() == RootMetaAnnotation1.class); + Assert.assertTrue(annotations.get(1).annotationType() == RootMetaAnnotation1.class || + annotations.get(1).annotationType() == RootMetaAnnotation2.class); + Assert.assertTrue(annotations.get(2).annotationType() == RootMetaAnnotation2.class || + annotations.get(2).annotationType() == RootMetaAnnotation3.class); Assert.assertEquals(RootMetaAnnotation3.class, annotations.get(3).annotationType()); } diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/GenericSynthesizedAggregateAnnotationTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/GenericSynthesizedAggregateAnnotationTest.java index c59b9d6bdb..5432ebb9fc 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/GenericSynthesizedAggregateAnnotationTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/GenericSynthesizedAggregateAnnotationTest.java @@ -4,6 +4,7 @@ import org.junit.Assert; import org.junit.Test; +import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -11,6 +12,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; /** * 合成注解{@link GenericSynthesizedAggregateAnnotation}的测试用例 @@ -36,9 +38,11 @@ public void baseSynthesisAnnotationWorkTest() { Assert.assertEquals(grandParentAnnotation, syntheticMetaAnnotation.getAnnotation(GrandParentAnnotation.class)); Assert.assertEquals(parentAnnotation, syntheticMetaAnnotation.getAnnotation(ParentAnnotation.class)); Assert.assertEquals(childAnnotation, syntheticMetaAnnotation.getAnnotation(ChildAnnotation.class)); + Annotation[] synthesizedAnnotations = syntheticMetaAnnotation.getAnnotations(); + Arrays.sort(synthesizedAnnotations, Comparator.comparing(Annotation::toString)); Assert.assertEquals( Arrays.asList(childAnnotation, grandParentAnnotation, parentAnnotation), - Arrays.asList(syntheticMetaAnnotation.getAnnotations()) + Arrays.asList(synthesizedAnnotations) ); // 扩展方法 diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/TestIssueI8CLBJ.java b/hutool-core/src/test/java/cn/hutool/core/annotation/TestIssueI8CLBJ.java new file mode 100644 index 0000000000..04c2a92677 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/TestIssueI8CLBJ.java @@ -0,0 +1,64 @@ +package cn.hutool.core.annotation; + +import org.junit.Assert; +import org.junit.Test; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * @author huangchengxing + */ +public class TestIssueI8CLBJ { + + @Test + public void test() throws NoSuchFieldException { + Field field = Foo.class.getDeclaredField("name"); + Assert.assertNotNull(field); + Annotation[] annotations = field.getDeclaredAnnotations(); + Assert.assertTrue(annotations.length > 0); + + TestAnnotation annotation = AnnotationUtil.getSynthesizedAnnotation(TestAnnotation.class, annotations); + List threadList = new ArrayList<>(); + for (int i = 0; i < 30; i++) { + Thread thread = new Thread(() -> { + try { + String valueFieldName = annotation.valueFieldName(); + System.out.println("valueFieldName:" + valueFieldName); + } catch (Exception e) { + e.printStackTrace(); + } + }); + threadList.add(thread); + thread.start(); + } + + try { + for (Thread thread : threadList) { + thread.join(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static class Foo { + private Integer id; + @TestAnnotation("name") + private String name; + } + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + private @interface TestAnnotation { + String value() default ""; + @Alias("value") + String valueFieldName() default ""; + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/comparator/VersionComparatorTest.java b/hutool-core/src/test/java/cn/hutool/core/comparator/VersionComparatorTest.java index f00f93b33a..f68958d845 100644 --- a/hutool-core/src/test/java/cn/hutool/core/comparator/VersionComparatorTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/comparator/VersionComparatorTest.java @@ -15,36 +15,59 @@ public class VersionComparatorTest { public void versionComparatorTest1() { int compare = VersionComparator.INSTANCE.compare("1.2.1", "1.12.1"); Assert.assertTrue(compare < 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("1.12.1", "1.2.1"); + Assert.assertTrue(compare > 0); } @Test public void versionComparatorTest2() { int compare = VersionComparator.INSTANCE.compare("1.12.1", "1.12.1c"); Assert.assertTrue(compare < 0); + + compare = VersionComparator.INSTANCE.compare("1.12.1c", "1.12.1"); + Assert.assertTrue(compare > 0); } @Test public void versionComparatorTest3() { int compare = VersionComparator.INSTANCE.compare(null, "1.12.1c"); Assert.assertTrue(compare < 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("1.12.1c", null); + Assert.assertTrue(compare > 0); } @Test public void versionComparatorTest4() { int compare = VersionComparator.INSTANCE.compare("1.13.0", "1.12.1c"); Assert.assertTrue(compare > 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("1.12.1c", "1.13.0"); + Assert.assertTrue(compare < 0); } @Test public void versionComparatorTest5() { int compare = VersionComparator.INSTANCE.compare("V1.2", "V1.1"); Assert.assertTrue(compare > 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("V1.1", "V1.2"); + Assert.assertTrue(compare < 0); } @Test public void versionComparatorTes6() { int compare = VersionComparator.INSTANCE.compare("V0.0.20170102", "V0.0.20170101"); Assert.assertTrue(compare > 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("V0.0.20170101", "V0.0.20170102"); + Assert.assertTrue(compare < 0); } @Test @@ -58,5 +81,9 @@ public void equalsTest(){ public void versionComparatorTest7() { int compare = VersionComparator.INSTANCE.compare("1.12.2", "1.12.1c"); Assert.assertTrue(compare > 0); + + // 自反测试 + compare = VersionComparator.INSTANCE.compare("1.12.1c", "1.12.2"); + Assert.assertTrue(compare < 0); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/Issue3348Test.java b/hutool-core/src/test/java/cn/hutool/core/date/Issue3348Test.java new file mode 100644 index 0000000000..67f2cdc8c4 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/Issue3348Test.java @@ -0,0 +1,16 @@ +package cn.hutool.core.date; + +import cn.hutool.core.lang.Console; +import org.junit.Assert; +import org.junit.Test; + +public class Issue3348Test { + + @Test + public void formatChineseDateTest() { + final String formatChineseDate = DateUtil.formatChineseDate( + DateUtil.parse("2023-10-23"), true, false); + Console.log(formatChineseDate); + Assert.assertEquals("二〇二三年十月二十三日", formatChineseDate); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/date/IssueI82Y1LTest.java b/hutool-core/src/test/java/cn/hutool/core/date/IssueI82Y1LTest.java new file mode 100644 index 0000000000..0e847f4f31 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/IssueI82Y1LTest.java @@ -0,0 +1,12 @@ +package cn.hutool.core.date; + +import org.junit.Assert; +import org.junit.Test; + +public class IssueI82Y1LTest { + @Test + public void parseTest() { + final String dt1 = "2023-09-14T05:00:03.648519Z"; + Assert.assertEquals("2023-09-14 05:10:51", DateUtil.parse(dt1).toString()); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java index d53e28b0a5..c65d6cc939 100755 --- a/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java @@ -48,7 +48,9 @@ public void scaleByWidthAndHeightTest() { @Test @Ignore public void cutTest() { - ImgUtil.cut(FileUtil.file("d:/face.jpg"), FileUtil.file("d:/face_result.jpg"), new Rectangle(200, 200, 100, 100)); + ImgUtil.cut(FileUtil.file("d:/test/hutool.png"), + FileUtil.file("d:/test/result.png"), + new Rectangle(0, 0, 400, 240)); } @Test @@ -92,6 +94,14 @@ public void sliceByRowsAndColsTest() { ImgUtil.sliceByRowsAndCols(FileUtil.file("d:/temp/2.png"), FileUtil.file("d:/temp/slice/png"),ImgUtil.IMAGE_TYPE_PNG, 1, 5); } + @Test + @Ignore + public void sliceByRowsAndColsTest2() { + ImgUtil.sliceByRowsAndCols( + FileUtil.file("d:/test/hutool.png"), + FileUtil.file("d:/test/dest"), ImgUtil.IMAGE_TYPE_PNG, 1, 5); + } + @Test @Ignore public void convertTest() { diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java index c37021532f..52e48109c0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java @@ -5,7 +5,6 @@ import org.junit.Ignore; import org.junit.Test; -import java.io.File; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; diff --git a/hutool-core/src/test/java/cn/hutool/core/io/unit/DataSizeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/unit/DataSizeUtilTest.java index dcdc600578..feafb9a3a7 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/unit/DataSizeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/unit/DataSizeUtilTest.java @@ -60,4 +60,11 @@ public void formatTest(){ format = DataSizeUtil.format(1024L * 1024 * 1024 * 1024); Assert.assertEquals("1 TB", format); } + + @Test + public void issueI88Z4ZTest() { + final String size = DataSizeUtil.format(10240000); + final long bytes = DataSize.parse(size).toBytes(); + Assert.assertEquals(10244587, bytes); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/SnowflakeTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/SnowflakeTest.java index ca02e5e67b..30af070721 100755 --- a/hutool-core/src/test/java/cn/hutool/core/lang/SnowflakeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/SnowflakeTest.java @@ -4,6 +4,7 @@ import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import org.junit.Assert; import org.junit.Ignore; @@ -19,22 +20,45 @@ */ public class SnowflakeTest { + /** + * 测试-根据传入时间戳-计算ID起终点 + */ + @Test + public void snowflakeTestGetIdScope() { + final long workerId = RandomUtil.randomLong(31); + final long dataCenterId = RandomUtil.randomLong(31); + final Snowflake idWorker = new Snowflake(workerId, dataCenterId); + final long generatedId = idWorker.nextId(); + // 随机忽略数据中心和工作机器的占位 + final boolean ignore = RandomUtil.randomBoolean(); + final long createTimestamp = idWorker.getGenerateDateTime(generatedId); + final Pair idScope = idWorker.getIdScopeByTimestamp(createTimestamp, createTimestamp, ignore); + final long startId = idScope.getKey(); + final long endId = idScope.getValue(); + + // 起点终点相差比较 + final long trueOffSet = endId - startId; + // 忽略数据中心和工作机器时差值为22个1,否则为12个1 + final long expectedOffSet = ignore ? ~(-1 << 22) : ~(-1 << 12); + Assert.assertEquals(trueOffSet, expectedOffSet); + } + @Test public void snowflakeTest1(){ //构建Snowflake,提供终端ID和数据中心ID - Snowflake idWorker = new Snowflake(0, 0); - long nextId = idWorker.nextId(); + final Snowflake idWorker = new Snowflake(0, 0); + final long nextId = idWorker.nextId(); Assert.assertTrue(nextId > 0); } @Test public void snowflakeTest(){ - HashSet hashSet = new HashSet<>(); + final HashSet hashSet = new HashSet<>(); //构建Snowflake,提供终端ID和数据中心ID - Snowflake idWorker = new Snowflake(0, 0); + final Snowflake idWorker = new Snowflake(0, 0); for (int i = 0; i < 1000; i++) { - long id = idWorker.nextId(); + final long id = idWorker.nextId(); hashSet.add(id); } Assert.assertEquals(1000L, hashSet.size()); @@ -43,8 +67,8 @@ public void snowflakeTest(){ @Test public void snowflakeGetTest(){ //构建Snowflake,提供终端ID和数据中心ID - Snowflake idWorker = new Snowflake(1, 2); - long nextId = idWorker.nextId(); + final Snowflake idWorker = new Snowflake(1, 2); + final long nextId = idWorker.nextId(); Assert.assertEquals(1, idWorker.getWorkerId(nextId)); Assert.assertEquals(2, idWorker.getDataCenterId(nextId)); @@ -55,9 +79,9 @@ public void snowflakeGetTest(){ @Ignore public void uniqueTest(){ // 测试并发环境下生成ID是否重复 - Snowflake snowflake = IdUtil.getSnowflake(0, 0); + final Snowflake snowflake = IdUtil.getSnowflake(0, 0); - Set ids = new ConcurrentHashSet<>(); + final Set ids = new ConcurrentHashSet<>(); ThreadUtil.concurrencyTest(100, () -> { for (int i = 0; i < 50000; i++) { if(false == ids.add(snowflake.nextId())){ @@ -94,7 +118,7 @@ public void uniqueOfRandomSequenceTest(){ final Snowflake snowflake = new Snowflake(null, 0, 0, false, Snowflake.DEFAULT_TIME_OFFSET, 100); - Set ids = new ConcurrentHashSet<>(); + final Set ids = new ConcurrentHashSet<>(); ThreadUtil.concurrencyTest(100, () -> { for (int i = 0; i < 50000; i++) { if(false == ids.add(snowflake.nextId())){ diff --git a/hutool-core/src/test/java/cn/hutool/core/map/IssueI88R5MTest.java b/hutool-core/src/test/java/cn/hutool/core/map/IssueI88R5MTest.java new file mode 100644 index 0000000000..aefb9f0fc0 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/map/IssueI88R5MTest.java @@ -0,0 +1,17 @@ +package cn.hutool.core.map; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.LinkedHashMap; + +public class IssueI88R5MTest { + @Test + public void biMapTest() { + final BiMap biMap = new BiMap<>(new LinkedHashMap<>()); + biMap.put("aaa", 111); + biMap.getKey(111); + biMap.put("aaa", 222); + Assert.assertNull(biMap.getKey(111)); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java index 1791b690b5..1bea35c063 100644 --- a/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java @@ -1,7 +1,6 @@ package cn.hutool.core.map; import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Opt; import cn.hutool.core.util.StrUtil; diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java index bd8a415bae..c79d7f4948 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.stream; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.map.MapUtil; import org.junit.Assert; import org.junit.Test; @@ -29,6 +30,22 @@ public void reduceListMapTest() { Assert.assertEquals(MapUtil.builder("苏格拉底", Arrays.asList(1, 2)) .put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(), nameScoresMap); + + List> data = ListUtil.toList( + MapUtil.builder("name", "sam").put("count", "80").map(), + MapUtil.builder("name", "sam").put("count", "81").map(), + MapUtil.builder("name", "sam").put("count", "82").map(), + MapUtil.builder("name", "jack").put("count", "80").map(), + MapUtil.builder("name", "jack").put("count", "90").map() + ); + + Map>> nameMap = data.stream() + .collect(Collectors.groupingBy(e -> e.get("name"), CollectorUtil.reduceListMap())); + Assert.assertEquals(MapUtil.builder("jack", MapUtil.builder("name", Arrays.asList("jack", "jack")) + .put("count", Arrays.asList("80", "90")).build()) + .put("sam", MapUtil.builder("name", Arrays.asList("sam", "sam", "sam")) + .put("count", Arrays.asList("80", "81", "82")).build()) + .build(), nameMap); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/core/text/NamingCaseTest.java b/hutool-core/src/test/java/cn/hutool/core/text/NamingCaseTest.java index 1582982d0c..7ab8640eaa 100755 --- a/hutool-core/src/test/java/cn/hutool/core/text/NamingCaseTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/NamingCaseTest.java @@ -1,6 +1,5 @@ package cn.hutool.core.text; -import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Dict; import cn.hutool.core.util.CharUtil; import org.junit.Assert; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java index 2e38992f7c..97c7b117a9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java @@ -148,4 +148,9 @@ public void isValidTWCardIdTest() { flag = IdcardUtil.isValidTWCard(errTwCard2); Assert.assertFalse(flag); } + + @Test + public void issueI88YKMTest() { + Assert.assertTrue(IdcardUtil.isValidCard("111111111111111")); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java index 28b0b88f42..e7f2422138 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/ReflectUtilTest.java @@ -15,6 +15,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -225,8 +226,10 @@ public void getMethodsFromInterfaceTest() { final Method[] methods = ReflectUtil.getMethods(TestInterface3.class); Assert.assertEquals(4, methods.length); + Arrays.sort(methods, Comparator.comparing(Method::toString)); // 接口里,调用getMethods和getPublicMethods效果相同 final Method[] publicMethods = ReflectUtil.getPublicMethods(TestInterface3.class); + Arrays.sort(publicMethods, Comparator.comparing(Method::toString)); Assert.assertArrayEquals(methods, publicMethods); } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java index 81c9f030d2..a67ed9cd8a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/TypeUtilTest.java @@ -1,48 +1,61 @@ package cn.hutool.core.util; -import lombok.Data; -import org.junit.Assert; -import org.junit.Test; - import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; public class TypeUtilTest { - + @Test public void getEleTypeTest() { Method method = ReflectUtil.getMethod(TestClass.class, "getList"); Type type = TypeUtil.getReturnType(method); Assert.assertEquals("java.util.List", type.toString()); - + Type type2 = TypeUtil.getTypeArgument(type); Assert.assertEquals(String.class, type2); } - + @Test public void getParamTypeTest() { Method method = ReflectUtil.getMethod(TestClass.class, "intTest", Integer.class); Type type = TypeUtil.getParamType(method, 0); Assert.assertEquals(Integer.class, type); - + Type returnType = TypeUtil.getReturnType(method); Assert.assertEquals(Integer.class, returnType); } - + + @Test + public void getClasses() { + Method method = ReflectUtil.getMethod(Parent.class, "getLevel"); + Type returnType = TypeUtil.getReturnType(method); + Class clazz = TypeUtil.getClass(returnType); + Assert.assertEquals(Level1.class, clazz); + + method = ReflectUtil.getMethod(Level1.class, "getId"); + returnType = TypeUtil.getReturnType(method); + clazz = TypeUtil.getClass(returnType); + Assert.assertEquals(Object.class, clazz); + } + public static class TestClass { - public List getList(){ + public List getList() { return new ArrayList<>(); } - + public Integer intTest(Integer integer) { return 1; } + } @Test - public void getTypeArgumentTest(){ + public void getTypeArgumentTest() { // 测试不继承父类,而是实现泛型接口时是否可以获取成功。 final Type typeArgument = TypeUtil.getTypeArgument(IPService.class); Assert.assertEquals(String.class, typeArgument); @@ -59,25 +72,29 @@ public void service(String string) { } @Test - public void getActualTypesTest(){ + public void getActualTypesTest() { // 测试多层级泛型参数是否能获取成功 - Type idType = TypeUtil.getActualType(Level3.class, - ReflectUtil.getField(Level3.class, "id")); + Type idType = TypeUtil.getActualType(Level3.class, ReflectUtil.getField(Level3.class, "id")); Assert.assertEquals(Long.class, idType); } - public static class Level3 extends Level2{ + public static class Level3 extends Level2 { } - public static class Level2 extends Level1{ + public static class Level2 extends Level1 { } @Data - public static class Level1{ + public static class Level1 { private T id; } + @Data + public static class Parent, B extends Long> { + private T level; + } + } diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml index 6705a867d3..c632c4b69b 100755 --- a/hutool-cron/pom.xml +++ b/hutool-cron/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-cron diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java index aa7ee5c3dd..7178aab329 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/Part.java @@ -89,7 +89,7 @@ public int getMax() { */ public int checkValue(int value) throws CronException { Assert.checkBetween(value, min, max, - () -> new CronException("Value {} out of range: [{} , {}]", value, min, max)); + () -> new CronException("{} value {} out of range: [{} , {}]", this.name(), value, min, max)); return value; } diff --git a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java index 263b641358..7c33ed05c7 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/pattern/parser/PartParser.java @@ -3,16 +3,11 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.Month; import cn.hutool.core.date.Week; -import cn.hutool.core.lang.Console; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.cron.CronException; import cn.hutool.cron.pattern.Part; -import cn.hutool.cron.pattern.matcher.AlwaysTrueMatcher; -import cn.hutool.cron.pattern.matcher.BoolArrayMatcher; -import cn.hutool.cron.pattern.matcher.DayOfMonthMatcher; -import cn.hutool.cron.pattern.matcher.PartMatcher; -import cn.hutool.cron.pattern.matcher.YearValueMatcher; +import cn.hutool.cron.pattern.matcher.*; import java.util.ArrayList; import java.util.List; @@ -204,13 +199,11 @@ private List parseRange(String value, int step) { //在range模式下,如果步进不存在,表示步进为1 step = 1; } - if (v1 < v2) {// 正常范围,例如:2-5 + if (v1 <= v2) {// 正常范围,例如:2-5,3-3 NumberUtil.appendRange(v1, v2, step, results); - } else if (v1 > v2) {// 逆向范围,反选模式,例如:5-2 + } else {// 逆向范围,反选模式,例如:5-2 NumberUtil.appendRange(v1, part.getMax(), step, results); NumberUtil.appendRange(part.getMin(), v2, step, results); - } else {// v1 == v2,此时与单值模式一致 - NumberUtil.appendRange(v1, part.getMax(), step, results); } } else { throw new CronException("Invalid syntax of field: [{}]", value); diff --git a/hutool-cron/src/test/java/cn/hutool/cron/pattern/IssueI82CSHTest.java b/hutool-cron/src/test/java/cn/hutool/cron/pattern/IssueI82CSHTest.java new file mode 100644 index 0000000000..4dfc28c0db --- /dev/null +++ b/hutool-cron/src/test/java/cn/hutool/cron/pattern/IssueI82CSHTest.java @@ -0,0 +1,21 @@ +package cn.hutool.cron.pattern; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Date; +import java.util.List; + +public class IssueI82CSHTest { + + @Test + public void test() { + final DateTime begin = DateUtil.parse("2023-09-20"); + final DateTime end = DateUtil.parse("2025-09-20"); + final List dates = CronPatternUtil.matchedDates("0 0 1 3-3,9 *", begin, end, 20, false); + //dates.forEach(Console::log); + Assert.assertEquals(4, dates.size()); + } +} diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml index 57e8c72c13..d48d44ec24 100755 --- a/hutool-crypto/pom.xml +++ b/hutool-crypto/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-crypto @@ -19,7 +19,7 @@ cn.hutool.crypto - 1.75 + 1.76 diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java index 68971d361c..daf27255f5 100644 --- a/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java @@ -1,6 +1,5 @@ package cn.hutool.crypto; -import cn.hutool.crypto.BCUtil; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.junit.Assert; diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java index 2ef57eea22..b981799f6b 100644 --- a/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java @@ -1,8 +1,5 @@ package cn.hutool.crypto; -import cn.hutool.crypto.CryptoException; -import cn.hutool.crypto.GlobalBouncyCastleProvider; -import cn.hutool.crypto.KeyUtil; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index fe47273321..f4d7b10b81 100755 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-db @@ -21,16 +21,16 @@ 0.9.5.5 - 2.9.0 + 2.11.0 10.0.23 - 1.2.16 + 1.2.20 4.0.3 4.9.1 - 3.42.0.0 + 3.43.2.2 2.5.2 - 4.3.1 + 5.0.2 @@ -84,7 +84,7 @@ com.github.chris2018998 beecp - 3.4.1 + 3.4.2 slf4j-api @@ -97,12 +97,6 @@ org.apache.commons commons-dbcp2 ${dbcp2.version} - - - commons-pool2 - org.apache.commons - - true @@ -121,6 +115,10 @@ slf4j-api org.slf4j + + commons-pool2 + org.apache.commons + true @@ -147,7 +145,7 @@ mysql mysql-connector-java - 8.0.32 + 8.0.33 test @@ -177,7 +175,7 @@ com.clickhouse clickhouse-jdbc - 0.4.6 + 0.5.0 test diff --git a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java index 6a13bec352..ed9cacc4d2 100755 --- a/hutool-db/src/main/java/cn/hutool/db/meta/Column.java +++ b/hutool-db/src/main/java/cn/hutool/db/meta/Column.java @@ -258,7 +258,7 @@ public Column setSize(int size) { * * @return 大小或数据长度 */ - public int getDigit() { + public Integer getDigit() { return digit; } diff --git a/hutool-db/src/test/java/cn/hutool/db/MySQLTest.java b/hutool-db/src/test/java/cn/hutool/db/MySQLTest.java index 8ecebb74e0..c7aa2e4bf9 100755 --- a/hutool-db/src/test/java/cn/hutool/db/MySQLTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/MySQLTest.java @@ -1,7 +1,6 @@ package cn.hutool.db; import cn.hutool.core.lang.Console; -import cn.hutool.core.util.ArrayUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; diff --git a/hutool-db/src/test/java/cn/hutool/db/dialect/DialectFactoryTest.java b/hutool-db/src/test/java/cn/hutool/db/dialect/DialectFactoryTest.java index 519e671a4c..8222dcdac2 100644 --- a/hutool-db/src/test/java/cn/hutool/db/dialect/DialectFactoryTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/dialect/DialectFactoryTest.java @@ -4,9 +4,7 @@ import org.junit.Assert; import org.junit.Test; - import java.util.HashMap; - import java.util.Map; import static cn.hutool.db.dialect.DriverNamePool.*; diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml index 1a6a327161..a467e88c06 100755 --- a/hutool-dfa/pom.xml +++ b/hutool-dfa/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-dfa diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index 68e59f0244..086d124684 100755 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-extra @@ -20,15 +20,15 @@ cn.hutool.extra 2.3 - 3.15.3.RELEASE + 3.15.10.RELEASE 1.4.2 2.3.32 - 5.0.3 - 3.1.1.RELEASE + 5.1.3 + 3.1.2.RELEASE 1.6.2 0.1.55 - 0.35.0 - 3.5.1 + 0.37.0 + 3.5.2 3.9.0 5.1.1 4.0.1 @@ -348,7 +348,7 @@ com.github.houbb pinyin - 0.3.1 + 0.4.0 true @@ -407,7 +407,7 @@ com.googlecode.aviator aviator - 5.3.3 + 5.4.1 compile true @@ -421,14 +421,14 @@ org.apache.commons commons-jexl3 - 3.2.1 + 3.3 compile true org.mvel mvel2 - 2.4.14.Final + 2.5.0.Final compile true @@ -442,7 +442,7 @@ org.springframework spring-expression - 5.3.26 + 5.3.30 compile true @@ -456,7 +456,7 @@ com.alibaba QLExpress - 3.3.1 + 3.3.2 compile true @@ -464,7 +464,7 @@ org.apache.commons commons-compress - 1.22 + 1.24.0 compile true diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 61a9f1b7d4..94271dac08 100755 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-http diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 9c9f8ed2b7..657acd8e88 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -8,7 +8,6 @@ import cn.hutool.core.io.resource.MultiFileResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.Console; import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.TableMap; import cn.hutool.core.net.SSLUtil; @@ -1405,7 +1404,7 @@ private void sendMultipart() throws IOException { /** * 是否忽略读取响应body部分
- * HEAD、CONNECT、OPTIONS、TRACE方法将不读取响应体 + * HEAD、CONNECT、TRACE方法将不读取响应体 * * @return 是否需要忽略响应body部分 * @since 3.1.2 @@ -1413,7 +1412,6 @@ private void sendMultipart() throws IOException { private boolean isIgnoreResponseBody() { return Method.HEAD == this.method // || Method.CONNECT == this.method // - || Method.OPTIONS == this.method // || Method.TRACE == this.method; } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/HttpExchangeWrapper.java b/hutool-http/src/main/java/cn/hutool/http/server/HttpExchangeWrapper.java new file mode 100644 index 0000000000..16f651fa0b --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/server/HttpExchangeWrapper.java @@ -0,0 +1,148 @@ +package cn.hutool.http.server; + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpPrincipal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; + +/** + * {@link HttpExchange}包装类,提供增强方法和缓存 + * + * @author looly + */ +public class HttpExchangeWrapper extends HttpExchange { + + private final HttpExchange raw; + private final HttpServerRequest request; + private final HttpServerResponse response; + + /** + * 构造 + * + * @param raw {@link HttpExchange} + */ + public HttpExchangeWrapper(final HttpExchange raw) { + this.raw = raw; + this.request = new HttpServerRequest(this); + this.response = new HttpServerResponse(this); + } + + /** + * 获取原始对象 + * @return 对象 + */ + public HttpExchange getRaw() { + return this.raw; + } + + /** + * 获取请求 + * + * @return 请求 + */ + public HttpServerRequest getRequest() { + return request; + } + + /** + * 获取响应 + * + * @return 响应 + */ + public HttpServerResponse getResponse() { + return response; + } + + // region ----- HttpExchange methods + @Override + public Headers getRequestHeaders() { + return this.raw.getRequestHeaders(); + } + + @Override + public Headers getResponseHeaders() { + return this.raw.getResponseHeaders(); + } + + @Override + public URI getRequestURI() { + return this.raw.getRequestURI(); + } + + @Override + public String getRequestMethod() { + return this.raw.getRequestMethod(); + } + + @Override + public HttpContext getHttpContext() { + return this.raw.getHttpContext(); + } + + @Override + public void close() { + this.raw.close(); + } + + @Override + public InputStream getRequestBody() { + return this.raw.getRequestBody(); + } + + @Override + public OutputStream getResponseBody() { + return this.raw.getResponseBody(); + } + + @Override + public void sendResponseHeaders(final int rCode, final long responseLength) throws IOException { + this.raw.sendResponseHeaders(rCode, responseLength); + } + + @Override + public InetSocketAddress getRemoteAddress() { + return this.raw.getRemoteAddress(); + } + + @Override + public int getResponseCode() { + return this.raw.getResponseCode(); + } + + @Override + public InetSocketAddress getLocalAddress() { + return this.raw.getLocalAddress(); + } + + @Override + public String getProtocol() { + return this.raw.getProtocol(); + } + + @Override + public Object getAttribute(final String name) { + return this.raw.getAttribute(name); + } + + @Override + public void setAttribute(final String name, final Object value) { + this.raw.setAttribute(name, value); + } + + @Override + public void setStreams(final InputStream i, final OutputStream o) { + this.raw.setStreams(i, o); + } + + @Override + public HttpPrincipal getPrincipal() { + return this.raw.getPrincipal(); + } + // endregion +} diff --git a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java index 05dc1ed62a..e62e5e49e2 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java @@ -126,7 +126,8 @@ public SimpleServer addFilter(HttpFilter filter) { return addFilter(new SimpleFilter() { @Override public void doFilter(HttpExchange httpExchange, Chain chain) throws IOException { - filter.doFilter(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange), chain); + final HttpExchangeWrapper httpExchangeWrapper = new HttpExchangeWrapper(httpExchange); + filter.doFilter(httpExchangeWrapper.getRequest(), httpExchangeWrapper.getResponse(), chain); } }); } diff --git a/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java b/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java index 42f88c5485..1e1077162f 100644 --- a/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java +++ b/hutool-http/src/main/java/cn/hutool/http/server/handler/ActionHandler.java @@ -1,5 +1,6 @@ package cn.hutool.http.server.handler; +import cn.hutool.http.server.HttpExchangeWrapper; import cn.hutool.http.server.HttpServerRequest; import cn.hutool.http.server.HttpServerResponse; import cn.hutool.http.server.action.Action; @@ -29,10 +30,18 @@ public ActionHandler(Action action) { @Override public void handle(HttpExchange httpExchange) throws IOException { - action.doAction( - new HttpServerRequest(httpExchange), - new HttpServerResponse(httpExchange) - ); + final HttpServerRequest request; + final HttpServerResponse response; + if (httpExchange instanceof HttpExchangeWrapper) { + // issue#3343 当使用Filter时,可能读取了请求参数,此时使用共享的req和res,可复用缓存 + final HttpExchangeWrapper wrapper = (HttpExchangeWrapper) httpExchange; + request = wrapper.getRequest(); + response = wrapper.getResponse(); + } else { + request = new HttpServerRequest(httpExchange); + response = new HttpServerResponse(httpExchange); + } + action.doAction(request, response); httpExchange.close(); } } diff --git a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java index 8c1a060a75..0b0abf9565 100755 --- a/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java +++ b/hutool-http/src/main/java/cn/hutool/http/useragent/Browser.java @@ -28,54 +28,56 @@ public class Browser extends UserAgentInfo { * 支持的浏览器类型 */ public static final List browers = CollUtil.newArrayList( - // 部分特殊浏览器是基于安卓、Iphone等的,需要优先判断 - // 企业微信 企业微信使用微信浏览器内核,会包含 MicroMessenger 所以要放在前面 - new Browser("wxwork", "wxwork", "wxwork\\/([\\d\\w\\.\\-]+)"), - // 微信 - new Browser("MicroMessenger", "MicroMessenger", Other_Version), - // 微信小程序 - new Browser("miniProgram", "miniProgram", Other_Version), - // QQ浏览器 - new Browser("QQBrowser", "MQQBrowser", "MQQBrowser\\/([\\d\\w\\.\\-]+)"), - // 钉钉PC端浏览器 - new Browser("DingTalk-win", "dingtalk-win", "DingTalk\\(([\\d\\w\\.\\-]+)\\)"), - // 钉钉内置浏览器 - new Browser("DingTalk", "DingTalk", "AliApp\\(DingTalk\\/([\\d\\w\\.\\-]+)\\)"), - // 支付宝内置浏览器 - new Browser("Alipay", "AlipayClient", "AliApp\\(AP\\/([\\d\\w\\.\\-]+)\\)"), - // 淘宝内置浏览器 - new Browser("Taobao", "taobao", "AliApp\\(TB\\/([\\d\\w\\.\\-]+)\\)"), - // UC浏览器 - new Browser("UCBrowser", "UC?Browser", "UC?Browser\\/([\\d\\w\\.\\-]+)"), - // XiaoMi 浏览器 - new Browser("MiuiBrowser", "MiuiBrowser|mibrowser", "MiuiBrowser\\/([\\d\\w\\.\\-]+)"), - // 夸克浏览器 - new Browser("Quark", "Quark", Other_Version), - // 联想浏览器 - new Browser("Lenovo", "SLBrowser", "SLBrowser/([\\d\\w\\.\\-]+)"), - new Browser("MSEdge", "Edge|Edg", "(?:edge|Edg|EdgA)\\/([\\d\\w\\.\\-]+)"), - new Browser("Chrome", "chrome|(iphone.*crios.*safari)", "(?:Chrome|CriOS)\\/([\\d\\w\\.\\-]+)"), - new Browser("Firefox", "firefox", Other_Version), - new Browser("IEMobile", "iemobile", Other_Version), - new Browser("Android Browser", "android", "version\\/([\\d\\w\\.\\-]+)"), - new Browser("Safari", "safari", "version\\/([\\d\\w\\.\\-]+)"), - new Browser("Opera", "opera", Other_Version), - new Browser("Konqueror", "konqueror", Other_Version), - new Browser("PS3", "playstation 3", "([\\d\\w\\.\\-]+)\\)\\s*$"), - new Browser("PSP", "playstation portable", "([\\d\\w\\.\\-]+)\\)?\\s*$"), - new Browser("Lotus", "lotus.notes", "Lotus-Notes\\/([\\w.]+)"), - new Browser("Thunderbird", "thunderbird", Other_Version), - new Browser("Netscape", "netscape", Other_Version), - new Browser("Seamonkey", "seamonkey", Other_Version), - new Browser("Outlook", "microsoft.outlook", Other_Version), - new Browser("Evolution", "evolution", Other_Version), - new Browser("MSIE", "msie", "msie ([\\d\\w\\.\\-]+)"), - new Browser("MSIE11", "rv:11", "rv:([\\d\\w\\.\\-]+)"), - new Browser("Gabble", "Gabble", Other_Version), - new Browser("Yammer Desktop", "AdobeAir", "([\\d\\w\\.\\-]+)\\/Yammer"), - new Browser("Yammer Mobile", "Yammer[\\s]+([\\d\\w\\.\\-]+)", "Yammer[\\s]+([\\d\\w\\.\\-]+)"), - new Browser("Apache HTTP Client", "Apache\\\\-HttpClient", "Apache\\-HttpClient\\/([\\d\\w\\.\\-]+)"), - new Browser("BlackBerry", "BlackBerry", "BlackBerry[\\d]+\\/([\\d\\w\\.\\-]+)") + // 部分特殊浏览器是基于安卓、Iphone等的,需要优先判断 + // 企业微信 企业微信使用微信浏览器内核,会包含 MicroMessenger 所以要放在前面 + new Browser("wxwork", "wxwork", "wxwork\\/([\\d\\w\\.\\-]+)"), + // 微信 + new Browser("MicroMessenger", "MicroMessenger", Other_Version), + // 微信小程序 + new Browser("miniProgram", "miniProgram", Other_Version), + // QQ浏览器 + new Browser("QQBrowser", "MQQBrowser", "MQQBrowser\\/([\\d\\w\\.\\-]+)"), + // 钉钉PC端浏览器 + new Browser("DingTalk-win", "dingtalk-win", "DingTalk\\(([\\d\\w\\.\\-]+)\\)"), + // 钉钉内置浏览器 + new Browser("DingTalk", "DingTalk", "AliApp\\(DingTalk\\/([\\d\\w\\.\\-]+)\\)"), + // 支付宝内置浏览器 + new Browser("Alipay", "AlipayClient", "AliApp\\(AP\\/([\\d\\w\\.\\-]+)\\)"), + // 淘宝内置浏览器 + new Browser("Taobao", "taobao", "AliApp\\(TB\\/([\\d\\w\\.\\-]+)\\)"), + // UC浏览器 + new Browser("UCBrowser", "UC?Browser", "UC?Browser\\/([\\d\\w\\.\\-]+)"), + // XiaoMi 浏览器 + new Browser("MiuiBrowser", "MiuiBrowser|mibrowser", "MiuiBrowser\\/([\\d\\w\\.\\-]+)"), + // 夸克浏览器 + new Browser("Quark", "Quark", Other_Version), + // 联想浏览器 + new Browser("Lenovo", "SLBrowser", "SLBrowser/([\\d\\w\\.\\-]+)"), + new Browser("MSEdge", "Edge|Edg", "(?:edge|Edg|EdgA)\\/([\\d\\w\\.\\-]+)"), + new Browser("Chrome", "chrome|(iphone.*crios.*safari)", "(?:Chrome|CriOS)\\/([\\d\\w\\.\\-]+)"), + new Browser("Firefox", "firefox", Other_Version), + new Browser("IEMobile", "iemobile", Other_Version), + new Browser("Android Browser", "android", "version\\/([\\d\\w\\.\\-]+)"), + new Browser("Safari", "safari", "version\\/([\\d\\w\\.\\-]+)"), + new Browser("Opera", "opera", Other_Version), + new Browser("Konqueror", "konqueror", Other_Version), + new Browser("PS3", "playstation 3", "([\\d\\w\\.\\-]+)\\)\\s*$"), + new Browser("PSP", "playstation portable", "([\\d\\w\\.\\-]+)\\)?\\s*$"), + new Browser("Lotus", "lotus.notes", "Lotus-Notes\\/([\\w.]+)"), + new Browser("Thunderbird", "thunderbird", Other_Version), + new Browser("Netscape", "netscape", Other_Version), + new Browser("Seamonkey", "seamonkey", Other_Version), + new Browser("Outlook", "microsoft.outlook", Other_Version), + new Browser("Evolution", "evolution", Other_Version), + new Browser("MSIE", "msie", "msie ([\\d\\w\\.\\-]+)"), + new Browser("MSIE11", "rv:11", "rv:([\\d\\w\\.\\-]+)"), + new Browser("Gabble", "Gabble", Other_Version), + new Browser("Yammer Desktop", "AdobeAir", "([\\d\\w\\.\\-]+)\\/Yammer"), + new Browser("Yammer Mobile", "Yammer[\\s]+([\\d\\w\\.\\-]+)", "Yammer[\\s]+([\\d\\w\\.\\-]+)"), + new Browser("Apache HTTP Client", "Apache\\\\-HttpClient", "Apache\\-HttpClient\\/([\\d\\w\\.\\-]+)"), + new Browser("BlackBerry", "BlackBerry", "BlackBerry[\\d]+\\/([\\d\\w\\.\\-]+)"), + // issue#I847JY 百度浏览器 + new Browser("Baidu", "Baidu", "baiduboxapp\\/([\\d\\w\\.\\-]+)") ); /** @@ -116,7 +118,7 @@ public Browser(String name, String regex, String versionRegex) { * @return 版本 */ public String getVersion(String userAgentString) { - if(isUnknown()){ + if (isUnknown()) { return null; } return ReUtil.getGroup1(this.versionPattern, userAgentString); @@ -130,11 +132,11 @@ public String getVersion(String userAgentString) { public boolean isMobile() { final String name = this.getName(); return "PSP".equals(name) || - "Yammer Mobile".equals(name) || - "Android Browser".equals(name) || - "IEMobile".equals(name) || - "MicroMessenger".equals(name) || - "miniProgram".equals(name) || - "DingTalk".equals(name); + "Yammer Mobile".equals(name) || + "Android Browser".equals(name) || + "IEMobile".equals(name) || + "MicroMessenger".equals(name) || + "miniProgram".equals(name) || + "DingTalk".equals(name); } } diff --git a/hutool-http/src/test/java/cn/hutool/http/Issue3314Test.java b/hutool-http/src/test/java/cn/hutool/http/Issue3314Test.java new file mode 100644 index 0000000000..3107c9d429 --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/Issue3314Test.java @@ -0,0 +1,21 @@ +package cn.hutool.http; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Console; +import org.junit.Ignore; +import org.junit.Test; + +public class Issue3314Test { + @Test + @Ignore + public void postTest() { + String url = "https://hutool.cn/test/getList"; + final String body = HttpRequest.get(url) + .setRest(true) + .body(FileUtil.readBytes("d:/test/3314.xlsx")) + .execute() + .body(); + + Console.log(body); + } +} diff --git a/hutool-http/src/test/java/cn/hutool/http/server/Issue3343Test.java b/hutool-http/src/test/java/cn/hutool/http/server/Issue3343Test.java new file mode 100644 index 0000000000..b5f43ba21e --- /dev/null +++ b/hutool-http/src/test/java/cn/hutool/http/server/Issue3343Test.java @@ -0,0 +1,33 @@ +package cn.hutool.http.server; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Console; +import cn.hutool.core.map.multi.ListValueMap; +import cn.hutool.http.HttpUtil; + +/** + * http://localhost:8888/?name=hutool + */ +public class Issue3343Test { + public static void main(final String[] args) { + final SimpleServer server = HttpUtil.createServer(8888) + .addFilter((req, res, chain) -> { + Console.log(DateUtil.now() + " got request: " + req.getPath()); + Console.log(" > from : " + req.getClientIP()); + // 过滤器中获取请求参数 + Console.log(" > params : " + req.getParams()); + chain.doFilter(req.getHttpExchange()); + }); + + server.addAction("/", Issue3343Test::index); + + server.start(); + } + + private static void index(HttpServerRequest request, HttpServerResponse response) { + // 具体逻辑中再次获取请求参数 + ListValueMap params = request.getParams(); + Console.log("index params: " + params); + response.getWriter().write("GOT: " + params); + } +} diff --git a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java index 0263137816..b17481d99f 100644 --- a/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/useragent/UserAgentUtilTest.java @@ -456,4 +456,20 @@ public void issuseI7OTCUTest() { Assert.assertEquals("iPhone", ua2.getPlatform().toString()); Assert.assertTrue(ua2.isMobile()); } + + @Test + public void issueI847JYTest() { + final String s = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + + "Mobile/15E148 SP-engine/2.80.0 main%2F1.0 baiduboxapp/13.42.0.11 (Baidu; P2 17.0) NABar/1.0 themeUA=Them"; + final UserAgent ua2 = UserAgentUtil.parse(s); + + Assert.assertEquals("Baidu", ua2.getBrowser().toString()); + Assert.assertEquals("13.42.0.11", ua2.getVersion()); + Assert.assertEquals("Webkit", ua2.getEngine().toString()); + Assert.assertEquals("605.1.15", ua2.getEngineVersion()); + Assert.assertEquals("iPhone", ua2.getOs().toString()); + Assert.assertEquals("17_0", ua2.getOsVersion()); + Assert.assertEquals("iPhone", ua2.getPlatform().toString()); + Assert.assertTrue(ua2.isMobile()); + } } diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index 159a1cf38f..9135f1845d 100755 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-json diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java index 3b1becd3af..7492c0acfe 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java @@ -1,6 +1,5 @@ package cn.hutool.json; -import cn.hutool.core.lang.Console; import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.mutable.Mutable; import cn.hutool.core.lang.mutable.MutablePair; diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java b/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java index 5181401bef..8b033c17dd 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONStrFormatter.java @@ -42,10 +42,12 @@ public static String format(String json) { if (null == wrapChar) { //字符串模式开始 wrapChar = key; - } else if (isEscapeMode) { - //在字符串模式下的转义 - isEscapeMode = false; } else if (wrapChar.equals(key)) { + if (isEscapeMode) { + //字符串模式下,遇到结束符号,也同时结束转义 + isEscapeMode = false; + } + //字符串包装结束 wrapChar = null; } diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java b/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java index 7ca54d49b0..0577551d3e 100755 --- a/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java @@ -1,5 +1,6 @@ package cn.hutool.json.serialize; +import cn.hutool.core.lang.Assert; import cn.hutool.json.JSON; import cn.hutool.json.JSONException; import cn.hutool.json.JSONObject; @@ -7,6 +8,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.Month; import java.time.temporal.TemporalAccessor; /** @@ -61,11 +63,33 @@ public void serialize(JSONObject json, TemporalAccessor bean) { @Override public TemporalAccessor deserialize(JSON json) { final JSONObject jsonObject = (JSONObject) json; - if (LocalDate.class.equals(this.temporalAccessorClass)) { - return LocalDate.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY)); - } else if (LocalDateTime.class.equals(this.temporalAccessorClass)) { - return LocalDateTime.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY), - jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY)); + if (LocalDate.class.equals(this.temporalAccessorClass) || LocalDateTime.class.equals(this.temporalAccessorClass)) { + final Integer year = jsonObject.getInt(YEAR_KEY); + Assert.notNull(year, "Field 'year' must be not null"); + Integer month = jsonObject.getInt(MONTH_KEY); + if (null == month) { + final Month monthEnum = Month.valueOf(jsonObject.getStr(MONTH_KEY)); + Assert.notNull(monthEnum, "Field 'month' must be not null"); + month = monthEnum.getValue(); + } + Integer day = jsonObject.getInt(DAY_KEY); + if (null == day) { + day = jsonObject.getInt("dayOfMonth"); + Assert.notNull(day, "Field 'day' or 'dayOfMonth' must be not null"); + } + + final LocalDate localDate = LocalDate.of(year, month, day); + if (LocalDate.class.equals(this.temporalAccessorClass)) { + return localDate; + } + + final LocalTime localTime = LocalTime.of( + jsonObject.getInt(HOUR_KEY, 0), + jsonObject.getInt(MINUTE_KEY, 0), + jsonObject.getInt(SECOND_KEY, 0), + jsonObject.getInt(NANO_KEY, 0)); + + return LocalDateTime.of(localDate, localTime); } else if (LocalTime.class.equals(this.temporalAccessorClass)) { return LocalTime.of(jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY)); } diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java index b4a55dee1c..1e3509e7cb 100644 --- a/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2365Test.java @@ -1,6 +1,5 @@ package cn.hutool.json; -import cn.hutool.json.JSONUtil; import lombok.Data; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue2555Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2555Test.java index 88419acccf..bc0fd48540 100755 --- a/hutool-json/src/test/java/cn/hutool/json/Issue2555Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2555Test.java @@ -1,9 +1,5 @@ package cn.hutool.json; -import cn.hutool.json.JSON; -import cn.hutool.json.JSONConfig; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import cn.hutool.json.serialize.JSONDeserializer; import cn.hutool.json.serialize.JSONObjectSerializer; import lombok.Data; diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue3051Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue3051Test.java index aa06ee69fd..df89a9a881 100644 --- a/hutool-json/src/test/java/cn/hutool/json/Issue3051Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue3051Test.java @@ -10,9 +10,8 @@ * See the Mulan PSL v2 for more details. */ -package cn.hutool.json;import cn.hutool.json.JSONConfig; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; +package cn.hutool.json; + import lombok.Data; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue3139Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue3139Test.java index b5fd4a9324..16649c62b8 100755 --- a/hutool-json/src/test/java/cn/hutool/json/Issue3139Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue3139Test.java @@ -12,7 +12,6 @@ package cn.hutool.json; -import cn.hutool.core.lang.Console; import cn.hutool.core.util.XmlUtil; import lombok.Data; import org.junit.Assert; diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI6YN2ATest.java b/hutool-json/src/test/java/cn/hutool/json/IssueI6YN2ATest.java index 633408e8c9..60172e8907 100755 --- a/hutool-json/src/test/java/cn/hutool/json/IssueI6YN2ATest.java +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI6YN2ATest.java @@ -12,8 +12,6 @@ package cn.hutool.json; -import cn.hutool.core.lang.Console; -import cn.hutool.core.lang.TypeReference; import lombok.Data; import org.junit.Assert; import org.junit.Test; diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI82AM8Test.java b/hutool-json/src/test/java/cn/hutool/json/IssueI82AM8Test.java new file mode 100644 index 0000000000..b20d558747 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI82AM8Test.java @@ -0,0 +1,43 @@ +package cn.hutool.json; + +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.lang.TypeReference; +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +public class IssueI82AM8Test { + + @Test + public void toBeanTest() { + final String json = ResourceUtil.readUtf8Str("issueI82AM8.json"); + + Map bean1 = + JSONUtil.toBean(json, new TypeReference>() { + }, false); + + bean1.forEach((k, v) -> Assert.assertNotNull(v.getTestimonials())); + } + + // 对象 + @Data + public static class MedicalCenter { + + private Map medicalCenterLocalized; + + @Data + public static class MedicalCenterLocalized { + + private List testimonials; + + @Data + public static class Testimonial { + private LocalDateTime createTime; + } + } + } +} diff --git a/hutool-json/src/test/java/cn/hutool/json/IssueI84V6ITest.java b/hutool-json/src/test/java/cn/hutool/json/IssueI84V6ITest.java new file mode 100644 index 0000000000..963d105396 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/IssueI84V6ITest.java @@ -0,0 +1,18 @@ +package cn.hutool.json; + +import org.junit.Assert; +import org.junit.Test; + +public class IssueI84V6ITest { + @Test + public void formatTest() { + final String a1 = "{'x':'\\n','y':','}"; + final String formatJsonStr = JSONUtil.formatJsonStr(a1); +// Console.log(formatJsonStr); + Assert.assertEquals( + "{\n" + + " 'x': '\\n',\n" + + " 'y': ','\n" + + "}", formatJsonStr); + } +} diff --git a/hutool-json/src/test/resources/issueI82AM8.json b/hutool-json/src/test/resources/issueI82AM8.json new file mode 100644 index 0000000000..a12f9bde93 --- /dev/null +++ b/hutool-json/src/test/resources/issueI82AM8.json @@ -0,0 +1,46 @@ +{ + "en": { + "testimonials": [ + { + "createTime": { + "dayOfYear": 261, + "dayOfWeek": "MONDAY", + "year": 2023, + "month": "SEPTEMBER", + "nano": 0, + "monthValue": 9, + "dayOfMonth": 18, + "hour": 15, + "minute": 18, + "second": 0, + "chronology": { + "id": "ISO", + "calendarType": "iso8601" + } + } + } + ] + }, + "zh": { + "testimonials": [ + { + "createTime": { + "dayOfYear": 261, + "dayOfWeek": "MONDAY", + "year": 2023, + "month": "SEPTEMBER", + "nano": 0, + "monthValue": 9, + "dayOfMonth": 18, + "hour": 15, + "minute": 18, + "second": 0, + "chronology": { + "id": "ISO", + "calendarType": "iso8601" + } + } + } + ] + } +} diff --git a/hutool-jwt/pom.xml b/hutool-jwt/pom.xml index 873ca6beec..8a86ab83e0 100755 --- a/hutool-jwt/pom.xml +++ b/hutool-jwt/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-jwt @@ -20,7 +20,8 @@ cn.hutool.jwt - 1.75 + 1.76 + 0.12.3 @@ -44,13 +45,13 @@ io.jsonwebtoken jjwt-impl - 0.11.5 + ${jjwt.version} test io.jsonwebtoken jjwt-gson - 0.11.5 + ${jjwt.version} test diff --git a/hutool-jwt/src/test/java/cn/hutool/jwt/Issue3205Test.java b/hutool-jwt/src/test/java/cn/hutool/jwt/Issue3205Test.java index b24957d34f..297db5c3eb 100644 --- a/hutool-jwt/src/test/java/cn/hutool/jwt/Issue3205Test.java +++ b/hutool-jwt/src/test/java/cn/hutool/jwt/Issue3205Test.java @@ -30,7 +30,7 @@ public void es256Test() { final String token = jwt.sign(); - final boolean signed = Jwts.parserBuilder().setSigningKey(keyPair.getPublic()).build().isSigned(token); + final boolean signed = Jwts.parser().verifyWith(keyPair.getPublic()).build().isSigned(token); Assert.assertTrue(signed); } diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index 4ee6b53c63..62a5d636ef 100755 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-log @@ -26,7 +26,7 @@ 2.20.0 1.2 1.3.6 - 2.6.1 + 2.6.2 3.4.3.Final 0.45.0 diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index 4a12fdc220..c439d0e545 100755 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-poi @@ -47,7 +47,7 @@ org.ofdrw ofdrw-full - 2.0.5 + 2.1.0 compile true diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java index a63bcd29d7..d040d1ba68 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.IntStream; diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java index 84fc2a51f5..a24882c9df 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java @@ -1,12 +1,9 @@ package cn.hutool.poi.excel.sax; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.log.StaticLog; import cn.hutool.poi.excel.sax.handler.RowHandler; import cn.hutool.poi.exceptions.POIException; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml index 97ecf49c72..a19f01d668 100755 --- a/hutool-script/pom.xml +++ b/hutool-script/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-script @@ -21,7 +21,7 @@ 2.7.3 3.0.1 - 3.0.17 + 3.0.19 diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml index 217400e939..0d97a98a69 100755 --- a/hutool-setting/pom.xml +++ b/hutool-setting/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-setting @@ -34,7 +34,7 @@ org.yaml snakeyaml - 2.0 + 2.2 true diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml index 35ea9ddf05..ea8e7c2bc6 100755 --- a/hutool-socket/pom.xml +++ b/hutool-socket/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-socket diff --git a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java index d3eaee9c77..0e56c368eb 100644 --- a/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java +++ b/hutool-socket/src/main/java/cn/hutool/socket/nio/NioServer.java @@ -3,7 +3,6 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.log.Log; -import cn.hutool.log.StaticLog; import java.io.Closeable; import java.io.IOException; @@ -16,7 +15,7 @@ /** * 基于NIO的Socket服务端实现 - * + * * @author looly * */ @@ -31,7 +30,7 @@ public class NioServer implements Closeable { /** * 构造 - * + * * @param port 端口 */ public NioServer(int port) { @@ -40,7 +39,7 @@ public NioServer(int port) { /** * 初始化 - * + * * @param address 地址和端口 * @return this */ @@ -109,7 +108,7 @@ public void listen() { /** * 开始监听 - * + * * @throws IOException IO异常 */ private void doListen() throws IOException { @@ -125,7 +124,7 @@ private void doListen() throws IOException { /** * 处理SelectionKey - * + * * @param key SelectionKey */ private void handle(SelectionKey key) { diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml index f00d794843..f17be3d038 100755 --- a/hutool-system/pom.xml +++ b/hutool-system/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool-system @@ -32,7 +32,7 @@ com.github.oshi oshi-core - 6.4.1 + 6.4.7 provided diff --git a/pom.xml b/pom.xml index 5dd131e3a6..b2dc0732a7 100755 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.8.22 + 5.8.23 hutool Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 https://github.com/dromara/hutool @@ -45,8 +45,8 @@ 8 - 5.9.2 - 1.18.26 + 5.10.1 + 1.18.30