forked from plusone/plusone-commons
Compare commits
4 Commits
e15f4875af
...
aea876a5f2
| Author | SHA1 | Date | |
|---|---|---|---|
| aea876a5f2 | |||
| ef61ecc2df | |||
| a65af967cb | |||
| 27e5650482 |
@@ -9,6 +9,7 @@
|
|||||||
"aliyun",
|
"aliyun",
|
||||||
"baomidou",
|
"baomidou",
|
||||||
"Batis",
|
"Batis",
|
||||||
|
"buildmetadata",
|
||||||
"Consolas",
|
"Consolas",
|
||||||
"cspell",
|
"cspell",
|
||||||
"databind",
|
"databind",
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.model;
|
||||||
|
|
||||||
|
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
|
||||||
|
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||||
|
|
||||||
|
// TODO [优化] 优化正则表达式
|
||||||
|
// TODO [补充] 完善单元测试
|
||||||
|
// TODO [doc] javadoc、README.md
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SemVer 语义版本号
|
||||||
|
*
|
||||||
|
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||||
|
* @since 1.1.0
|
||||||
|
*
|
||||||
|
* @see <a href="https://semver.org/">Semantic Versioning 2.0.0</a>
|
||||||
|
*/
|
||||||
|
public class SemVer implements Comparable<SemVer>, Serializable {
|
||||||
|
private static final long serialVersionUID = 458265121025514002L;
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private final int[] versionNumbers;
|
||||||
|
private final String[] preReleaseVersion;
|
||||||
|
private final String buildMetadata;
|
||||||
|
|
||||||
|
private static final String VERSION_NUMBERS = "(?<numbers>(?<major>0|[1-9]\\d*)\\.(?<minor>0|[1-9]\\d*)\\.(?<patch>0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){0,2})";
|
||||||
|
private static final String PRE_RELEASE_VERSION = "(?:-(?<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?";
|
||||||
|
private static final String BUILD_METADATA = "(?:\\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?";
|
||||||
|
|
||||||
|
private static final Pattern PATTERN = Pattern.compile(
|
||||||
|
"^" + VERSION_NUMBERS + PRE_RELEASE_VERSION + BUILD_METADATA + "$");
|
||||||
|
|
||||||
|
private SemVer(String value, int[] versionNumbers, @Nullable String[] preReleaseVersion, @Nullable String buildMetadata) {
|
||||||
|
this.value = value;
|
||||||
|
this.versionNumbers = versionNumbers;
|
||||||
|
this.preReleaseVersion = preReleaseVersion;
|
||||||
|
this.buildMetadata = buildMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SemVer of(final String value) {
|
||||||
|
checkArgument(StringTools.isNotBlank(value), "版本号不能为空");
|
||||||
|
final Matcher matcher = PATTERN.matcher(value);
|
||||||
|
checkArgument(matcher.matches(), "版本号格式错误");
|
||||||
|
// 数字版本部分
|
||||||
|
final String versionNumbersPart = matcher.group("numbers");
|
||||||
|
// 先行版本号部分
|
||||||
|
final String preReleaseVersionPart = matcher.group("prerelease");
|
||||||
|
// 版本编译信息部分
|
||||||
|
final String buildMetadataPart = matcher.group("buildmetadata");
|
||||||
|
|
||||||
|
final int[] versionNumbers = Splitter.on('.')
|
||||||
|
.splitToStream(versionNumbersPart)
|
||||||
|
// 必须都是数字
|
||||||
|
.mapToInt(Integer::parseInt)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
final String[] preReleaseVersion = preReleaseVersionPart != null
|
||||||
|
? Splitter.on('.').splitToStream(preReleaseVersionPart).toArray(String[]::new)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return new SemVer(value, versionNumbers, preReleaseVersion, buildMetadataPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMajor() {
|
||||||
|
return this.versionNumbers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinor() {
|
||||||
|
return this.versionNumbers[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPatch() {
|
||||||
|
return this.versionNumbers[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBuildMetadata() {
|
||||||
|
return buildMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@Nullable SemVer that) {
|
||||||
|
if (that == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int result = compareVersionNumbers(that);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return comparePreReleaseVersion(that);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + Arrays.hashCode(versionNumbers);
|
||||||
|
result = prime * result + Arrays.hashCode(preReleaseVersion);
|
||||||
|
result = prime * result + Objects.hash(value, buildMetadata);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (!(obj instanceof SemVer))
|
||||||
|
return false;
|
||||||
|
SemVer other = (SemVer) obj;
|
||||||
|
return Objects.equals(value, other.value) && Arrays.equals(versionNumbers, other.versionNumbers)
|
||||||
|
&& Arrays.equals(preReleaseVersion, other.preReleaseVersion)
|
||||||
|
&& Objects.equals(buildMetadata, other.buildMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return 'v' + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int compareVersionNumbers(SemVer that) {
|
||||||
|
final int minLength = Integer.min(this.versionNumbers.length, that.versionNumbers.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < minLength; i++) {
|
||||||
|
final int currentVersionNumberOfThis = this.versionNumbers[i];
|
||||||
|
final int currentVersionNumberOfThat = that.versionNumbers[i];
|
||||||
|
if (currentVersionNumberOfThis != currentVersionNumberOfThat) {
|
||||||
|
return currentVersionNumberOfThis - currentVersionNumberOfThat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.versionNumbers.length - that.versionNumbers.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int comparePreReleaseVersion(SemVer that) {
|
||||||
|
final String[] preReleaseVersionOfThis = this.preReleaseVersion;
|
||||||
|
final String[] preReleaseVersionOfThat = that.preReleaseVersion;
|
||||||
|
byte thisWithoutPreReleaseVersionFlag = preReleaseVersionOfThis == null ? (byte) 1 : (byte) 0;
|
||||||
|
byte thatWithoutPreReleaseVersionFlag = preReleaseVersionOfThat == null ? (byte) 1 : (byte) 0;
|
||||||
|
if ((thisWithoutPreReleaseVersionFlag | thatWithoutPreReleaseVersionFlag) == 1) {
|
||||||
|
return thisWithoutPreReleaseVersionFlag - thatWithoutPreReleaseVersionFlag;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
final int minLength = Integer.min(preReleaseVersionOfThis.length, preReleaseVersionOfThat.length);
|
||||||
|
for (int i = 0; i < minLength; i++) {
|
||||||
|
int r = comparePartOfPreReleaseVersion(preReleaseVersionOfThis[i], preReleaseVersionOfThat[i]);
|
||||||
|
if (r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preReleaseVersionOfThis.length - preReleaseVersionOfThat.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int comparePartOfPreReleaseVersion(String p1, String p2) {
|
||||||
|
boolean p1IsNumber = isAllDigits(p1);
|
||||||
|
boolean p2IsNumber = isAllDigits(p2);
|
||||||
|
|
||||||
|
if (p1IsNumber) {
|
||||||
|
return p2IsNumber
|
||||||
|
? Integer.parseInt(p1) - Integer.parseInt(p2) // 都是数字
|
||||||
|
: -1; // p1 是数字,p2 是字符串
|
||||||
|
}
|
||||||
|
// 如果 p1 是字符串,p2 是数字,则返回 1(字符串优先于纯数字)
|
||||||
|
return p2IsNumber ? 1 : p1.compareTo(p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAllDigits(@Nullable String str) {
|
||||||
|
if (str == null || str.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if (c < '0' || c > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
package xyz.zhouxy.plusone.commons.model;
|
package xyz.zhouxy.plusone.commons.model;
|
||||||
|
|
||||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@@ -75,8 +76,8 @@ public abstract class ValidatableStringRecord<T extends ValidatableStringRecord<
|
|||||||
* @param errorMessage 正则不匹配时的错误信息
|
* @param errorMessage 正则不匹配时的错误信息
|
||||||
*/
|
*/
|
||||||
protected ValidatableStringRecord(String value, Pattern pattern, String errorMessage) {
|
protected ValidatableStringRecord(String value, Pattern pattern, String errorMessage) {
|
||||||
checkArgument(Objects.nonNull(value), "The value cannot be null.");
|
checkArgumentNotNull(value, "The value cannot be null.");
|
||||||
checkArgument(Objects.nonNull(pattern), "The pattern cannot be null.");
|
checkArgumentNotNull(pattern, "The pattern cannot be null.");
|
||||||
this.matcher = pattern.matcher(value);
|
this.matcher = pattern.matcher(value);
|
||||||
checkArgument(this.matcher.matches(), errorMessage);
|
checkArgument(this.matcher.matches(), errorMessage);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package xyz.zhouxy.plusone.commons.util;
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -491,7 +492,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static char[] repeat(char[] arr, int times, int maxLength) {
|
public static char[] repeat(char[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -526,7 +527,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static byte[] repeat(byte[] arr, int times, int maxLength) {
|
public static byte[] repeat(byte[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -561,7 +562,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static short[] repeat(short[] arr, int times, int maxLength) {
|
public static short[] repeat(short[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -596,7 +597,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static int[] repeat(int[] arr, int times, int maxLength) {
|
public static int[] repeat(int[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -631,7 +632,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static long[] repeat(long[] arr, int times, int maxLength) {
|
public static long[] repeat(long[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -666,7 +667,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static float[] repeat(float[] arr, int times, int maxLength) {
|
public static float[] repeat(float[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -701,7 +702,7 @@ public class ArrayTools {
|
|||||||
* @return 重复后的数组
|
* @return 重复后的数组
|
||||||
*/
|
*/
|
||||||
public static double[] repeat(double[] arr, int times, int maxLength) {
|
public static double[] repeat(double[] arr, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(arr));
|
checkArgumentNotNull(arr);
|
||||||
checkArgument(times >= 0,
|
checkArgument(times >= 0,
|
||||||
"The number of times must be greater than or equal to zero");
|
"The number of times must be greater than or equal to zero");
|
||||||
checkArgument(maxLength >= 0,
|
checkArgument(maxLength >= 0,
|
||||||
@@ -750,7 +751,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(char[] a, int fromIndex, int toIndex, @Nullable char[] values) {
|
public static void fill(char[] a, int fromIndex, int toIndex, @Nullable char[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -793,7 +794,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(byte[] a, int fromIndex, int toIndex, @Nullable byte[] values) {
|
public static void fill(byte[] a, int fromIndex, int toIndex, @Nullable byte[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -836,7 +837,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(short[] a, int fromIndex, int toIndex, @Nullable short[] values) {
|
public static void fill(short[] a, int fromIndex, int toIndex, @Nullable short[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -879,7 +880,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(int[] a, int fromIndex, int toIndex, @Nullable int[] values) {
|
public static void fill(int[] a, int fromIndex, int toIndex, @Nullable int[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -922,7 +923,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(long[] a, int fromIndex, int toIndex, @Nullable long[] values) {
|
public static void fill(long[] a, int fromIndex, int toIndex, @Nullable long[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -965,7 +966,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(float[] a, int fromIndex, int toIndex, @Nullable float[] values) {
|
public static void fill(float[] a, int fromIndex, int toIndex, @Nullable float[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1008,7 +1009,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
public static void fill(double[] a, int fromIndex, int toIndex, @Nullable double[] values) {
|
public static void fill(double[] a, int fromIndex, int toIndex, @Nullable double[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1063,7 +1064,7 @@ public class ArrayTools {
|
|||||||
* @param values 填充内容
|
* @param values 填充内容
|
||||||
*/
|
*/
|
||||||
private static <T> void fillInternal(T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
private static <T> void fillInternal(T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
||||||
checkArgument(Objects.nonNull(a));
|
checkArgumentNotNull(a);
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkArgument(boolean condition) {
|
public static void checkArgument(boolean condition) {
|
||||||
checkCondition(condition, IllegalArgumentException::new);
|
if (!condition) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +67,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkArgument(boolean condition, @Nullable String errorMessage) {
|
public static void checkArgument(boolean condition, @Nullable String errorMessage) {
|
||||||
checkCondition(condition, () -> new IllegalArgumentException(errorMessage));
|
if (!condition) {
|
||||||
|
throw new IllegalArgumentException(errorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +80,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkArgument(boolean condition, Supplier<String> errorMessageSupplier) {
|
public static void checkArgument(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||||
checkCondition(condition, () -> new IllegalArgumentException(errorMessageSupplier.get()));
|
if (!condition) {
|
||||||
|
throw new IllegalArgumentException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,8 +95,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static void checkArgument(boolean condition,
|
public static void checkArgument(boolean condition,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||||
checkCondition(condition,
|
if (!condition) {
|
||||||
() -> new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
@@ -109,7 +116,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> T checkArgumentNotNull(@Nullable T obj) {
|
public static <T> T checkArgumentNotNull(@Nullable T obj) {
|
||||||
checkCondition(obj != null, IllegalArgumentException::new);
|
if (obj == null) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +131,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> T checkArgumentNotNull(@Nullable T obj, String errorMessage) {
|
public static <T> T checkArgumentNotNull(@Nullable T obj, String errorMessage) {
|
||||||
checkCondition(obj != null, () -> new IllegalArgumentException(errorMessage));
|
if (obj == null) {
|
||||||
|
throw new IllegalArgumentException(errorMessage);
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +146,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> T checkArgumentNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
public static <T> T checkArgumentNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
||||||
checkCondition(obj != null, () -> new IllegalArgumentException(errorMessageSupplier.get()));
|
if (obj == null) {
|
||||||
|
throw new IllegalArgumentException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +163,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkArgumentNotNull(@Nullable T obj,
|
public static <T> T checkArgumentNotNull(@Nullable T obj,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||||
checkCondition(obj != null,
|
if (obj == null) {
|
||||||
() -> new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +184,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalStateException 当条件不满足时抛出
|
* @throws IllegalStateException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkState(boolean condition) {
|
public static void checkState(boolean condition) {
|
||||||
checkCondition(condition, IllegalStateException::new);
|
if (!condition) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,7 +197,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalStateException 当条件不满足时抛出
|
* @throws IllegalStateException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkState(boolean condition, @Nullable String errorMessage) {
|
public static void checkState(boolean condition, @Nullable String errorMessage) {
|
||||||
checkCondition(condition, () -> new IllegalStateException(errorMessage));
|
if (!condition) {
|
||||||
|
throw new IllegalStateException(errorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,7 +210,9 @@ public class AssertTools {
|
|||||||
* @throws IllegalStateException 当条件不满足时抛出
|
* @throws IllegalStateException 当条件不满足时抛出
|
||||||
*/
|
*/
|
||||||
public static void checkState(boolean condition, Supplier<String> errorMessageSupplier) {
|
public static void checkState(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||||
checkCondition(condition, () -> new IllegalStateException(errorMessageSupplier.get()));
|
if (!condition) {
|
||||||
|
throw new IllegalStateException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,8 +225,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static void checkState(boolean condition,
|
public static void checkState(boolean condition,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||||
checkCondition(condition,
|
if (!condition) {
|
||||||
() -> new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
@@ -225,7 +246,9 @@ public class AssertTools {
|
|||||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> void checkNotNull(@Nullable T obj) {
|
public static <T> void checkNotNull(@Nullable T obj) {
|
||||||
checkCondition(obj != null, NullPointerException::new);
|
if (obj == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,7 +260,9 @@ public class AssertTools {
|
|||||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> void checkNotNull(@Nullable T obj, String errorMessage) {
|
public static <T> void checkNotNull(@Nullable T obj, String errorMessage) {
|
||||||
checkCondition(obj != null, () -> new NullPointerException(errorMessage));
|
if (obj == null) {
|
||||||
|
throw new NullPointerException(errorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,7 +274,9 @@ public class AssertTools {
|
|||||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> void checkNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
public static <T> void checkNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
||||||
checkCondition(obj != null, () -> new NullPointerException(errorMessageSupplier.get()));
|
if (obj == null) {
|
||||||
|
throw new NullPointerException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,8 +290,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> void checkNotNull(@Nullable T obj,
|
public static <T> void checkNotNull(@Nullable T obj,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||||
checkCondition(obj != null,
|
if (obj == null) {
|
||||||
() -> new NullPointerException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new NullPointerException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
@@ -285,7 +313,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(@Nullable T obj)
|
public static <T> T checkExists(@Nullable T obj)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(obj != null, DataNotExistsException::new);
|
if (obj == null) {
|
||||||
|
throw new DataNotExistsException();
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +330,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(@Nullable T obj, String errorMessage)
|
public static <T> T checkExists(@Nullable T obj, String errorMessage)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(obj != null, () -> new DataNotExistsException(errorMessage));
|
if (obj == null) {
|
||||||
|
throw new DataNotExistsException(errorMessage);
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +347,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(@Nullable T obj, Supplier<String> errorMessageSupplier)
|
public static <T> T checkExists(@Nullable T obj, Supplier<String> errorMessageSupplier)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(obj != null, () -> new DataNotExistsException(errorMessageSupplier.get()));
|
if (obj == null) {
|
||||||
|
throw new DataNotExistsException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +366,9 @@ public class AssertTools {
|
|||||||
public static <T> T checkExists(@Nullable T obj,
|
public static <T> T checkExists(@Nullable T obj,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs)
|
String errorMessageTemplate, Object... errorMessageArgs)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(obj != null,
|
if (obj == null) {
|
||||||
() -> new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +382,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(Optional<T> optional)
|
public static <T> T checkExists(Optional<T> optional)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), DataNotExistsException::new);
|
if (!optional.isPresent()) {
|
||||||
|
throw new DataNotExistsException();
|
||||||
|
}
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +399,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(Optional<T> optional, String errorMessage)
|
public static <T> T checkExists(Optional<T> optional, String errorMessage)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(errorMessage));
|
if (!optional.isPresent()) {
|
||||||
|
throw new DataNotExistsException(errorMessage);
|
||||||
|
}
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +416,9 @@ public class AssertTools {
|
|||||||
*/
|
*/
|
||||||
public static <T> T checkExists(Optional<T> optional, Supplier<String> errorMessageSupplier)
|
public static <T> T checkExists(Optional<T> optional, Supplier<String> errorMessageSupplier)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(errorMessageSupplier.get()));
|
if (!optional.isPresent()) {
|
||||||
|
throw new DataNotExistsException(errorMessageSupplier.get());
|
||||||
|
}
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,8 +435,9 @@ public class AssertTools {
|
|||||||
public static <T> T checkExists(Optional<T> optional,
|
public static <T> T checkExists(Optional<T> optional,
|
||||||
String errorMessageTemplate, Object... errorMessageArgs)
|
String errorMessageTemplate, Object... errorMessageArgs)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(),
|
if (!optional.isPresent()) {
|
||||||
() -> new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs)));
|
throw new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs));
|
||||||
|
}
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
package xyz.zhouxy.plusone.commons.util;
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
@@ -69,20 +69,20 @@ public final class RandomTools {
|
|||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
public static String randomStr(Random random, char[] sourceCharacters, int length) {
|
public static String randomStr(Random random, char[] sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
checkArgumentNotNull(random, "Random cannot be null.");
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(random, sourceCharacters, length);
|
return randomStrInternal(random, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomStr(char[] sourceCharacters, int length) {
|
public static String randomStr(char[] sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String secureRandomStr(char[] sourceCharacters, int length) {
|
public static String secureRandomStr(char[] sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
@@ -98,20 +98,20 @@ public final class RandomTools {
|
|||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
public static String randomStr(Random random, String sourceCharacters, int length) {
|
public static String randomStr(Random random, String sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
checkArgumentNotNull(random, "Random cannot be null.");
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(random, sourceCharacters, length);
|
return randomStrInternal(random, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomStr(String sourceCharacters, int length) {
|
public static String randomStr(String sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String secureRandomStr(String sourceCharacters, int length) {
|
public static String secureRandomStr(String sourceCharacters, int length) {
|
||||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
package xyz.zhouxy.plusone.commons.util;
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ public class StringTools {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public static String repeat(final String str, int times, int maxLength) {
|
public static String repeat(final String str, int times, int maxLength) {
|
||||||
checkArgument(Objects.nonNull(str));
|
checkArgumentNotNull(str);
|
||||||
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
|
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
|
import javax.annotation.CheckForNull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zip 工具类
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 提供最基础的数据压缩/解压方法
|
||||||
|
*
|
||||||
|
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||||
|
*
|
||||||
|
* @see Deflater
|
||||||
|
* @see Inflater
|
||||||
|
*/
|
||||||
|
public class ZipTools {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用默认压缩级别压缩数据
|
||||||
|
*
|
||||||
|
* @param input 输入
|
||||||
|
* @param level 压缩级别
|
||||||
|
* @return 压缩后的数据
|
||||||
|
*
|
||||||
|
* @throws IOException 发生 I/O 错误时抛出
|
||||||
|
*/
|
||||||
|
public static byte[] zip(@Nullable byte[] input) throws IOException {
|
||||||
|
return zipInternal(input, Deflater.DEFAULT_COMPRESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定压缩级别压缩数据
|
||||||
|
*
|
||||||
|
* @param input 输入
|
||||||
|
* @param level 压缩级别
|
||||||
|
* @return 压缩后的数据
|
||||||
|
*
|
||||||
|
* @throws IOException 发生 I/O 错误时抛出
|
||||||
|
*/
|
||||||
|
public static byte[] zip(@Nullable byte[] input, int level) throws IOException {
|
||||||
|
checkArgument((level >= 0 && level <= 9) || level == Deflater.DEFAULT_COMPRESSION,
|
||||||
|
"invalid compression level");
|
||||||
|
return zipInternal(input, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckForNull
|
||||||
|
private static byte[] zipInternal(@Nullable byte[] input, int level) throws IOException {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try (DeflaterOutputStream dos = new DeflaterOutputStream(baos, new Deflater(level))) {
|
||||||
|
dos.write(input);
|
||||||
|
dos.finish();
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解压数据
|
||||||
|
*
|
||||||
|
* @param input 输入
|
||||||
|
* @return 解压后的数据
|
||||||
|
*
|
||||||
|
* @throws IOException 发生 I/O 错误时抛出
|
||||||
|
*/
|
||||||
|
@CheckForNull
|
||||||
|
public static byte[] unzip(@Nullable byte[] input) throws IOException {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try (InflaterOutputStream dos = new InflaterOutputStream(baos, new Inflater())) {
|
||||||
|
dos.write(input);
|
||||||
|
dos.finish();
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZipTools() {
|
||||||
|
throw new IllegalStateException("Utility class");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package xyz.zhouxy.plusone.commons.model;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class SemVerTests {
|
||||||
|
@Test
|
||||||
|
void testCompareTo() {
|
||||||
|
|
||||||
|
SemVer[] versions = {
|
||||||
|
SemVer.of("1.0.0-alpha.beta"),
|
||||||
|
SemVer.of("1.0.1"),
|
||||||
|
SemVer.of("1.0.0-beta.11"),
|
||||||
|
SemVer.of("1.0.0-beta"),
|
||||||
|
SemVer.of("1.0.0-alpha"),
|
||||||
|
SemVer.of("1.0.0-beta.2"),
|
||||||
|
SemVer.of("1.0.0-rc.1"),
|
||||||
|
SemVer.of("1.0.0"),
|
||||||
|
SemVer.of("1.0.0-alpha.1"),
|
||||||
|
|
||||||
|
// SemVer.of("10.20.30.40.50-RC2.20250904"),
|
||||||
|
// SemVer.of("10.20.30.40.50-RC1.20250801"),
|
||||||
|
// SemVer.of("10.20.30.40.50-M1.2"),
|
||||||
|
// SemVer.of("10.20.30.40.50-M1"),
|
||||||
|
// SemVer.of("10.3.30-50"),
|
||||||
|
// SemVer.of("10.20.30-50"),
|
||||||
|
// SemVer.of("10.20.30-beta"),
|
||||||
|
// SemVer.of("10.20.30-alpha"),
|
||||||
|
// SemVer.of("10.20.30-2a"),
|
||||||
|
// SemVer.of("10.20.30-RC1"),
|
||||||
|
// SemVer.of("10.20.30-RC2"),
|
||||||
|
// SemVer.of("10.20.30-M2"),
|
||||||
|
// SemVer.of("10.20.30-M1"),
|
||||||
|
// SemVer.of("10.20.30-20"),
|
||||||
|
// SemVer.of("10.20.30.40-10"),
|
||||||
|
};
|
||||||
|
|
||||||
|
String compareResult = Arrays.stream(versions)
|
||||||
|
.sorted()
|
||||||
|
.map(SemVer::getValue)
|
||||||
|
.collect(Collectors.joining(" < "));
|
||||||
|
log.info(compareResult);
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0 < 1.0.1",
|
||||||
|
compareResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.zip.DataFormatException;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
|
import com.google.common.base.Stopwatch;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ZipToolsTests {
|
||||||
|
|
||||||
|
static byte[] bytes;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() throws IOException {
|
||||||
|
URL resource = Resources.getResource("xyz/zhouxy/plusone/commons/util/LoremIpsum.txt");
|
||||||
|
bytes = Resources.toByteArray(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zip_WithDefaultLevel() throws IOException, DataFormatException {
|
||||||
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||||
|
byte[] zip = ZipTools.zip(bytes);
|
||||||
|
stopwatch.stop();
|
||||||
|
log.info("default level, size: {} ({})", zip.length, stopwatch);
|
||||||
|
assertArrayEquals(bytes, ZipTools.unzip(zip));
|
||||||
|
|
||||||
|
assertNull(ZipTools.zip(null));
|
||||||
|
assertNull(ZipTools.unzip(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(ints = { -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })
|
||||||
|
void zip_WithLevel(int level) throws IOException, DataFormatException {
|
||||||
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||||
|
byte[] zip = ZipTools.zip(bytes, level);
|
||||||
|
stopwatch.stop();
|
||||||
|
log.info("level: {}, size: {} ({})", level, zip.length, stopwatch);
|
||||||
|
assertArrayEquals(bytes, ZipTools.unzip(zip));
|
||||||
|
|
||||||
|
assertNull(ZipTools.zip(null, level));
|
||||||
|
assertNull(ZipTools.unzip(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void zip_WithWrongLevel() throws IOException, DataFormatException {
|
||||||
|
Random random = new Random();
|
||||||
|
final int levelGtMax = random.nextInt() + 9;
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ZipTools.zip(bytes, levelGtMax));
|
||||||
|
|
||||||
|
final int levelLtMin = -1 - random.nextInt();
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ZipTools.zip(bytes, levelLtMin));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
|
||||||
|
Constructor<?>[] constructors = ZipTools.class.getDeclaredConstructors();
|
||||||
|
Arrays.stream(constructors)
|
||||||
|
.forEach(constructor -> {
|
||||||
|
assertFalse(constructor.isAccessible());
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
Throwable cause = assertThrows(Exception.class, constructor::newInstance)
|
||||||
|
.getCause();
|
||||||
|
assertInstanceOf(IllegalStateException.class, cause);
|
||||||
|
assertEquals("Utility class", cause.getMessage());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user