mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
Merged with v5-dev
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.8.22</version>
|
||||
<version>5.8.23-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@@ -251,7 +251,7 @@ public class Base64 {
|
||||
* base64解码
|
||||
*
|
||||
* @param source 被解码的base64字符串
|
||||
* @return 被加密后的字符串
|
||||
* @return 密文解密的结果
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public static String decodeStrGbk(CharSequence source) {
|
||||
@@ -262,7 +262,7 @@ public class Base64 {
|
||||
* base64解码
|
||||
*
|
||||
* @param source 被解码的base64字符串
|
||||
* @return 被加密后的字符串
|
||||
* @return 密文解密的结果
|
||||
*/
|
||||
public static String decodeStr(CharSequence source) {
|
||||
return Base64Decoder.decodeStr(source);
|
||||
@@ -273,7 +273,7 @@ public class Base64 {
|
||||
*
|
||||
* @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 class Base64 {
|
||||
*
|
||||
* @param source 被解码的base64字符串
|
||||
* @param charset 字符集
|
||||
* @return 被加密后的字符串
|
||||
* @return 密文解密的结果
|
||||
*/
|
||||
public static String decodeStr(CharSequence source, Charset charset) {
|
||||
return Base64Decoder.decodeStr(source, charset);
|
||||
|
@@ -7,7 +7,6 @@ import cn.hutool.core.stream.CollectorUtil;
|
||||
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;
|
||||
|
@@ -2,7 +2,6 @@ package cn.hutool.core.collection;
|
||||
|
||||
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;
|
||||
|
@@ -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;
|
||||
|
||||
/**
|
||||
* 版本比较器<br>
|
||||
@@ -24,6 +21,8 @@ import java.util.List;
|
||||
public class VersionComparator implements Comparator<String>, 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 class VersionComparator implements Comparator<String>, Serializable {
|
||||
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) {
|
||||
|
@@ -3,7 +3,6 @@ package cn.hutool.core.convert;
|
||||
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;
|
||||
|
@@ -6,7 +6,6 @@ import cn.hutool.core.bean.copier.CopyOptions;
|
||||
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;
|
||||
|
@@ -133,7 +133,7 @@ public class Img implements Serializable {
|
||||
* @return Img
|
||||
*/
|
||||
public static Img from(Image image) {
|
||||
return new Img(ImgUtil.toBufferedImage(image));
|
||||
return new Img(ImgUtil.castToBufferedImage(image, ImgUtil.IMAGE_TYPE_JPG));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -455,11 +455,7 @@ public class ImgUtil {
|
||||
* @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 class ImgUtil {
|
||||
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(); // 源图高度
|
||||
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); // 每张切片的高度
|
||||
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));
|
||||
}
|
||||
// 循环建立切片
|
||||
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 class ImgUtil {
|
||||
* @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,13 +1149,11 @@ public class ImgUtil {
|
||||
* @param img {@link Image}
|
||||
* @return {@link BufferedImage}
|
||||
* @since 4.3.2
|
||||
* @deprecated 改用 {@link #castToRenderedImage(Image, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static RenderedImage toRenderedImage(Image img) {
|
||||
if (img instanceof RenderedImage) {
|
||||
return (RenderedImage) img;
|
||||
}
|
||||
|
||||
return copyImage(img, BufferedImage.TYPE_INT_RGB);
|
||||
return castToRenderedImage(img, IMAGE_TYPE_JPG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1172,13 +1162,44 @@ public class ImgUtil {
|
||||
*
|
||||
* @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}<br>
|
||||
* 首先尝试强转,否则新建一个{@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 toBufferedImage(img, imageType);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Image} 转 {@link BufferedImage}<br>
|
||||
* 首先尝试强转,否则新建一个{@link BufferedImage}后重新绘制,使用 imageType 模式
|
||||
*
|
||||
* @param img {@link Image}
|
||||
* @param imageType 目标图片类型,例如jpg或png等
|
||||
* @return {@link BufferedImage}
|
||||
*/
|
||||
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 class ImgUtil {
|
||||
}
|
||||
|
||||
writer.setOutput(output);
|
||||
final RenderedImage renderedImage = toRenderedImage(image);
|
||||
final RenderedImage renderedImage = castToRenderedImage(image, IMAGE_TYPE_JPG);
|
||||
// 设置质量
|
||||
ImageWriteParam imgWriteParams = null;
|
||||
if (quality > 0 && quality < 1) {
|
||||
|
@@ -606,7 +606,7 @@ public class GifDecoder {
|
||||
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
|
||||
|
@@ -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.charset.Charset;
|
||||
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.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* NIO中Path对象操作封装
|
||||
@@ -80,11 +80,26 @@ public class PathUtil {
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static List<File> loopFiles(Path path, int maxDepth, FileFilter fileFilter) {
|
||||
return loopFiles(path, maxDepth, false, fileFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归遍历目录以及子目录中的所有文件<br>
|
||||
* 如果提供path为文件,直接返回过滤结果
|
||||
*
|
||||
* @param path 当前遍历文件或目录
|
||||
* @param maxDepth 遍历最大深度,-1表示遍历到没有目录为止
|
||||
* @param isFollowLinks 是否跟踪软链(快捷方式)
|
||||
* @param fileFilter 文件过滤规则对象,选择要保留的文件,只对文件有效,不过滤目录,null表示接收全部文件
|
||||
* @return 文件列表
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static List<File> loopFiles(final Path path, final int maxDepth, final boolean isFollowLinks, final FileFilter fileFilter) {
|
||||
final List<File> 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 class PathUtil {
|
||||
return fileList;
|
||||
}
|
||||
|
||||
walkFiles(path, maxDepth, new SimpleFileVisitor<Path>() {
|
||||
walkFiles(path, maxDepth, isFollowLinks, new SimpleFileVisitor<Path>() {
|
||||
|
||||
@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 class PathUtil {
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public static void walkFiles(Path start, int maxDepth, FileVisitor<? super Path> 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<? super Path> 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 class PathUtil {
|
||||
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 class PathUtil {
|
||||
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 class PathUtil {
|
||||
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 class PathUtil {
|
||||
* @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 @@ public class PathUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建是否追踪软链的选项
|
||||
*
|
||||
* @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<FileVisitOption> getFileVisitOption(final boolean isFollowLinks) {
|
||||
return isFollowLinks ? EnumSet.of(FileVisitOption.FOLLOW_LINKS) :
|
||||
EnumSet.noneOf(FileVisitOption.class);
|
||||
}
|
||||
}
|
||||
|
@@ -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资源访问类
|
||||
|
@@ -185,7 +185,7 @@ public final class DataSize implements Comparable<DataSize> {
|
||||
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);
|
||||
|
@@ -5,6 +5,7 @@ import cn.hutool.core.collection.EnumerationIter;
|
||||
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 @@ public class ClassScanner implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -198,6 +198,40 @@ public class Snowflake implements Serializable {
|
||||
return (id >> TIMESTAMP_LEFT_SHIFT & ~(-1L << 41L)) + twepoch;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入时间戳-计算ID起终点
|
||||
*
|
||||
* @param timestampStart 开始时间戳
|
||||
* @param timestampEnd 结束时间戳
|
||||
* @return key-ID起点,Value-ID终点
|
||||
* @since 5.8.23
|
||||
*/
|
||||
public Pair<Long, Long> 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<Long, Long> 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
|
||||
*
|
||||
|
@@ -30,7 +30,13 @@ public class BiMap<K, V> extends MapWrapper<K, V> {
|
||||
|
||||
@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);
|
||||
|
@@ -5,7 +5,6 @@ import cn.hutool.core.map.MapWrapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@@ -24,12 +24,18 @@ import java.util.*;
|
||||
/**
|
||||
* 网络相关工具
|
||||
*
|
||||
* @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 class NetUtil {
|
||||
final LinkedHashSet<InetAddress> localAddressList = localAddressList(address -> {
|
||||
// 非loopback地址,指127.*.*.*的地址
|
||||
return false == address.isLoopbackAddress()
|
||||
// 需为IPV4地址
|
||||
&& address instanceof Inet4Address;
|
||||
// 需为IPV4地址
|
||||
&& address instanceof Inet4Address;
|
||||
});
|
||||
|
||||
if (CollUtil.isNotEmpty(localAddressList)) {
|
||||
|
@@ -0,0 +1,85 @@
|
||||
package cn.hutool.core.net;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* 代理Socket工厂,用于创建代理Socket<br>
|
||||
* 来自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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -187,7 +187,7 @@ public class ReflectUtil {
|
||||
* 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。
|
||||
*
|
||||
* @param beanClass 类
|
||||
* @param fieldFilter field过滤器,过滤掉不需要的field
|
||||
* @param fieldFilter field过滤器,过滤掉不需要的field,{@code null}返回原集合
|
||||
* @return 字段列表
|
||||
* @throws SecurityException 安全检查异常
|
||||
* @since 5.7.14
|
||||
@@ -286,14 +286,22 @@ public class ReflectUtil {
|
||||
* @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<Field> 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;
|
||||
|
@@ -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 class TypeUtil {
|
||||
} 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) {
|
||||
|
@@ -29,20 +29,20 @@ public class AnnotationUtilTest {
|
||||
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 class AnnotationUtilTest {
|
||||
|
||||
// 加别名适配
|
||||
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 class AnnotationUtilTest {
|
||||
// -> RootMetaAnnotation3
|
||||
final List<Annotation> 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());
|
||||
}
|
||||
|
||||
|
@@ -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 class VersionComparatorTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
@@ -48,7 +48,9 @@ public class ImgUtilTest {
|
||||
@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 class ImgUtilTest {
|
||||
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() {
|
||||
|
@@ -5,7 +5,6 @@ import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
|
@@ -60,4 +60,11 @@ public class DataSizeUtilTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.ConcurrentHashSet;
|
||||
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 @@ import java.util.Set;
|
||||
*/
|
||||
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<Long, Long> 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<Long> hashSet = new HashSet<>();
|
||||
final HashSet<Long> 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 class 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 class SnowflakeTest {
|
||||
@Ignore
|
||||
public void uniqueTest(){
|
||||
// 测试并发环境下生成ID是否重复
|
||||
Snowflake snowflake = IdUtil.getSnowflake(0, 0);
|
||||
final Snowflake snowflake = IdUtil.getSnowflake(0, 0);
|
||||
|
||||
Set<Long> ids = new ConcurrentHashSet<>();
|
||||
final Set<Long> ids = new ConcurrentHashSet<>();
|
||||
ThreadUtil.concurrencyTest(100, () -> {
|
||||
for (int i = 0; i < 50000; i++) {
|
||||
if(false == ids.add(snowflake.nextId())){
|
||||
@@ -94,7 +118,7 @@ public class SnowflakeTest {
|
||||
final Snowflake snowflake = new Snowflake(null, 0, 0,
|
||||
false, Snowflake.DEFAULT_TIME_OFFSET, 100);
|
||||
|
||||
Set<Long> ids = new ConcurrentHashSet<>();
|
||||
final Set<Long> ids = new ConcurrentHashSet<>();
|
||||
ThreadUtil.concurrencyTest(100, () -> {
|
||||
for (int i = 0; i < 50000; i++) {
|
||||
if(false == ids.add(snowflake.nextId())){
|
||||
|
@@ -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<String, Integer> biMap = new BiMap<>(new LinkedHashMap<>());
|
||||
biMap.put("aaa", 111);
|
||||
biMap.getKey(111);
|
||||
biMap.put("aaa", 222);
|
||||
Assert.assertNull(biMap.getKey(111));
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -148,4 +148,9 @@ public class IdcardUtilTest {
|
||||
flag = IdcardUtil.isValidTWCard(errTwCard2);
|
||||
Assert.assertFalse(flag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issueI88YKMTest() {
|
||||
Assert.assertTrue(IdcardUtil.isValidCard("111111111111111"));
|
||||
}
|
||||
}
|
||||
|
@@ -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<java.lang.String>", 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<String> getList(){
|
||||
public List<String> 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 class TypeUtilTest {
|
||||
}
|
||||
|
||||
@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<Level3>{
|
||||
public static class Level3 extends Level2<Level3> {
|
||||
|
||||
}
|
||||
|
||||
public static class Level2<E> extends Level1<Long>{
|
||||
public static class Level2<E> extends Level1<Long> {
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Level1<T>{
|
||||
public static class Level1<T> {
|
||||
private T id;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Parent<T extends Level1<B>, B extends Long> {
|
||||
private T level;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user