forked from plusone/plusone-commons
Compare commits
39 Commits
ba12fec71d
...
reactor/mu
Author | SHA1 | Date | |
---|---|---|---|
4638853da6 | |||
ce9f3edfbc | |||
0f90756f44 | |||
34a49d30ca | |||
f4c3793aab | |||
6556a53163 | |||
56079c29d8 | |||
f111b02c21 | |||
56fd5f0a6a | |||
e2e5f50162 | |||
8eac9054cd | |||
a55c712349 | |||
0eda94a658 | |||
c816696c55 | |||
8828b12c78 | |||
89acbecc5a | |||
336d99d4ba | |||
0731bf2c22 | |||
2827f69aef | |||
2e73ca5f6d | |||
1239a11cd7 | |||
f8a2046d2d | |||
fb2036c038 | |||
f9b4c3c58c | |||
3ca2ec3be0 | |||
f83bb55fd6 | |||
e90e3dc1b4 | |||
b774d8c477 | |||
2a18a47ffe | |||
cb903a8cce | |||
030ed9ed3b | |||
5ce738bdfc | |||
97a4ae2279 | |||
af66cd2380 | |||
3b519105bf | |||
b70e526509 | |||
a2781012be | |||
9e410029b1 | |||
ee7213a687 |
13
README.md
13
README.md
@@ -68,16 +68,17 @@ System.out.println(result); // Output: Return string
|
||||
`RegexConsts` 包含常见正则表达式;`PatternConsts` 包含对应的 `Pattern` 对象
|
||||
|
||||
## 五、exception - 异常
|
||||
### 1. MultiTypesException - 多类型异常
|
||||
### 1. IMultiTypesException - 多类型异常
|
||||
异常在不同场景下被抛出,可以用不同的枚举值,表示不同的场景类型。
|
||||
|
||||
异常实现 `MultiTypesException` 的 `MultiTypesException#getType` 方法,返回对应的场景类型。
|
||||
异常实现 `IMultiTypesException` 的 `IMultiTypesException#getType` 方法,返回对应的场景类型。
|
||||
|
||||
表示场景类型的枚举实现 `MultiTypesException.ExceptionType`,其中的工厂方法用于创建类型对象。
|
||||
表示场景类型的枚举实现 `IMultiTypesException.IExceptionType`,其中的工厂方法用于创建对应类型的异常。
|
||||
```java
|
||||
public final class LoginException
|
||||
extends RuntimeException
|
||||
implements MultiTypesException<LoginException, LoginException.Type> {
|
||||
implements IMultiTypesException<LoginException.Type> {
|
||||
private static final long serialVersionUID = 881293090625085616L;
|
||||
private final Type type;
|
||||
private LoginException(@Nonnull Type type, @Nonnull String message) {
|
||||
super(message);
|
||||
@@ -103,7 +104,7 @@ public final class LoginException
|
||||
|
||||
// ...
|
||||
|
||||
public enum Type implements ExceptionType {
|
||||
public enum Type implements IExceptionType<String>, IExceptionFactory<LoginException> {
|
||||
DEFAULT("00", "当前会话未登录"),
|
||||
NOT_TOKEN("10", "未提供token"),
|
||||
INVALID_TOKEN("20", "token无效"),
|
||||
@@ -210,7 +211,7 @@ throw LoginException.Type.TOKEN_TIMEOUT.create();
|
||||
#### 2. UnifiedResponse
|
||||
UnifiedResponse 对返回给前端的数据进行封装,包含 `code`、`message`、`data。`
|
||||
|
||||
可使用 `UnifiedResponses` 快速构建 `UnifiedResponse` 对象。 `UnifiedResponses` 默认的成功代码为 "2000000", 用户按测试类 `CustomUnifiedResponseFactoryTests` 中所示范的,继承 `UnifiedResponses` 实现自己的工厂类, 自定义 `SUCCESS_CODE` 和 `DEFAULT_SUCCESS_MSG` 和工厂方法。 见 [issue#22](http://zhouxy.xyz:3000/plusone/plusone-commons/issues/22)。
|
||||
可使用 `UnifiedResponses` 快速构建 `UnifiedResponse` 对象。 `UnifiedResponses` 默认的成功代码为 "2000000", 用户按测试类 `CustomUnifiedResponseFactoryTests` 中所示范的,继承 `UnifiedResponses` 实现自己的工厂类, 自定义 `SUCCESS_CODE` 和 `DEFAULT_SUCCESS_MSG` 和工厂方法。 见 [issue#22](http://gitea.zhouxy.xyz/plusone/plusone-commons/issues/22)。
|
||||
|
||||
## 八、time - 时间 API
|
||||
### 1. 季度
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"ignorePaths": [
|
||||
"src/test"
|
||||
"*/src/test"
|
||||
],
|
||||
"dictionaryDefinitions": [],
|
||||
"dictionaries": [],
|
||||
@@ -14,25 +14,31 @@
|
||||
"cspell",
|
||||
"databind",
|
||||
"datasource",
|
||||
"dbutils",
|
||||
"fasterxml",
|
||||
"findbugs",
|
||||
"gson",
|
||||
"Hikari",
|
||||
"hutool",
|
||||
"jasypt",
|
||||
"jbcrypt",
|
||||
"Jdbc",
|
||||
"joda",
|
||||
"logback",
|
||||
"mapstruct",
|
||||
"mindrot",
|
||||
"Multimap",
|
||||
"Multiset",
|
||||
"mybatis",
|
||||
"Nonnull",
|
||||
"NOSONAR",
|
||||
"okhttp",
|
||||
"ooxml",
|
||||
"overriden",
|
||||
"plusone",
|
||||
"println",
|
||||
"projectlombok",
|
||||
"querydsl",
|
||||
"regexs",
|
||||
"Seata",
|
||||
"sonarlint",
|
||||
|
123
plusone-commons/pom.xml
Normal file
123
plusone-commons/pom.xml
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-parent</artifactId>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>plusone-commons</artifactId>
|
||||
|
||||
<description>
|
||||
常见工具集,结合 guava 使用。
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-dependencies</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- ========== Compile Dependencies ========== -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- ========== Test Dependencies ========== -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
|
||||
* <p>
|
||||
* 标识方法是读方法,如 getter。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see WriterMethod
|
||||
*/
|
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <p>标识方法为静态工厂方法
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
@@ -27,7 +27,7 @@ import java.lang.annotation.Documented;
|
||||
*
|
||||
* <p>标识方法为不支持的操作。该方法将抛出 {@link UnsupportedOperationException}。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @version 1.0
|
||||
* @since 1.0.0
|
||||
* @see UnsupportedOperationException
|
@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* ValueObject - 值对象
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Inherited
|
@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
|
||||
* 标识该方法是虚方法。
|
||||
* <p>该注解用于提醒、强调父类虽然有默认实现,但子类可以根据自己的需要覆写。</p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
|
||||
* <p>
|
||||
* 标识方法是写方法,如 setter。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see ReaderMethod
|
||||
*/
|
@@ -24,17 +24,15 @@
|
||||
* 标识<b>静态工厂方法</b>。
|
||||
* 《Effective Java》的 Item1 建议考虑用静态工厂方法替换构造器,
|
||||
* 因而考虑有一个注解可以标记一下静态工厂方法,以和其它方法进行区分。
|
||||
* </p>
|
||||
*
|
||||
* <h3>
|
||||
* 2. {@link ReaderMethod} 和 {@link WriterMethod}
|
||||
* </h3>
|
||||
* <p>
|
||||
* 分别标识<b>读方法</b>(如 getter)或<b>写方法</b>(如 setter)。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 最早是写了一个集合类,为了方便判断使用读写锁时,哪些情况下使用读锁,哪些情况下使用写锁。
|
||||
* </p>
|
||||
*
|
||||
* <h3>
|
||||
* 3. {@link UnsupportedOperation}
|
||||
@@ -42,23 +40,20 @@
|
||||
* <p>
|
||||
* 标识该方法不被支持或没有实现,将抛出 {@link UnsupportedOperationException}。
|
||||
* 为了方便在使用时,不需要点进源码,就能知道该方法没有实现。
|
||||
* </p>
|
||||
*
|
||||
* <h3>
|
||||
* 4. {@link Virtual}
|
||||
* </h3>
|
||||
* <p>
|
||||
* Java 非 final 的实例方法,对应 C++/C# 中的虚方法,允许被子类覆写。
|
||||
* Java 非 final 的实例方法,对应 C++/C# 中的虚方法,允许被子类覆写。
|
||||
* {@link Virtual} 注解旨在设计父类时,强调该方法父类虽然有默认实现,但子类可以根据自己的需要覆写。
|
||||
* </p>
|
||||
*
|
||||
* <h3>
|
||||
* 5. {@link ValueObject}
|
||||
* </h3>
|
||||
* <p>
|
||||
* 标记一个类,表示其作为值对象,区别于 Entity。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.annotation;
|
@@ -26,7 +26,7 @@ import javax.annotation.Nullable;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IWithCode<T> {
|
||||
|
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IWithIntCode {
|
||||
|
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IWithLongCode {
|
||||
|
@@ -27,7 +27,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* {@link Ref} 包装了一个值,表示对该值的应用。
|
||||
*
|
||||
* <p>灵感来自于 C# 的 {@value ref} 参数修饰符。C# 允许通过以下方式,将值返回给调用端:</p>
|
||||
* <p>灵感来自于 C# 的 {@code ref} 参数修饰符。C# 允许通过以下方式,将值返回给调用端:</p>
|
||||
* <pre>
|
||||
* void Method(ref int refArgument)
|
||||
* {
|
||||
@@ -51,7 +51,7 @@ import javax.annotation.Nullable;
|
||||
* <p>
|
||||
* 当一个方法需要产生多个结果时,无法有多个返回值,可以使用 {@link Ref} 作为参数传入,方法内部修改 {@link Ref} 的值。
|
||||
* 调用方在调用方法之后,使用 {@code getValue()} 获取结果。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* String method(final Ref<Integer> intRefArgument, final Ref<String> strRefArgument) {
|
||||
* intRefArgument.transformValue(i -> i + 44);
|
||||
@@ -67,7 +67,7 @@ import javax.annotation.Nullable;
|
||||
* System.out.println(result); // Output: Return string
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class Ref<T> {
|
@@ -20,8 +20,8 @@
|
||||
* <h3>1. Ref</h3>
|
||||
* <p>
|
||||
* {@link Ref} 包装了一个值,表示对该值的应用。
|
||||
* </p>
|
||||
* <p>灵感来自于 C# 的 {@value ref} 参数修饰符。C# 允许通过以下方式,将值返回给调用端:</p>
|
||||
*
|
||||
* <p>灵感来自于 C# 的 {@code ref} 参数修饰符。C# 允许通过以下方式,将值返回给调用端:</p>
|
||||
* <pre>
|
||||
* void Method(ref int refArgument)
|
||||
* {
|
||||
@@ -45,7 +45,7 @@
|
||||
* <p>
|
||||
* 当一个方法需要产生多个结果时,无法有多个返回值,可以使用 {@link Ref} 作为参数传入,方法内部修改 {@link Ref} 的值。
|
||||
* 调用方在调用方法之后,使用 {@code getValue()} 获取结果。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* String method(Ref<Integer> intRefArgument, Ref<String> strRefArgument) {
|
||||
* intRefArgument.transformValue(i -> i + 44);
|
||||
@@ -65,9 +65,8 @@
|
||||
* <p>
|
||||
* 类似于枚举这样的类型,通常需要设置固定的码值表示对应的含义。
|
||||
* 可实现 {@link IWithCode}、{@link IWithIntCode}、{@link IWithLongCode},便于在需要的地方对这些接口的实现进行处理。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@CheckReturnValue
|
||||
@ParametersAreNonnullByDefault
|
@@ -33,7 +33,7 @@ import com.google.common.collect.Table;
|
||||
/**
|
||||
* 集合工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class CollectionTools {
|
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <h2>集合<h2>
|
||||
* <h2>集合</h2>
|
||||
*
|
||||
* <h3>
|
||||
* 1. {@link CollectionTools}
|
||||
* </h3>
|
||||
* 集合工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package xyz.zhouxy.plusone.commons.collection;
|
@@ -21,7 +21,7 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* 正则表达式常量
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @see RegexConsts
|
||||
* @see xyz.zhouxy.plusone.commons.util.RegexTools
|
||||
*/
|
||||
@@ -31,7 +31,7 @@ public final class PatternConsts {
|
||||
* yyyyMMdd
|
||||
*
|
||||
* @see RegexConsts#BASIC_ISO_DATE
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public static final Pattern BASIC_ISO_DATE = Pattern.compile(RegexConsts.BASIC_ISO_DATE);
|
||||
|
@@ -19,7 +19,7 @@ package xyz.zhouxy.plusone.commons.constant;
|
||||
/**
|
||||
* 正则表达式常量
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @see PatternConsts
|
||||
*/
|
||||
public final class RegexConsts {
|
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <h2>常量<h2>
|
||||
* <h2>常量</h2>
|
||||
*
|
||||
* <h3>
|
||||
* 1. 正则常量
|
||||
* </h3>
|
||||
* {@link RegexConsts} 包含常见正则表达式;{@link PatternConsts} 包含对应的 {@link Pattern} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.constant;
|
||||
|
@@ -19,7 +19,7 @@ package xyz.zhouxy.plusone.commons.exception;
|
||||
/**
|
||||
* 数据不存在异常
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class DataNotExistsException extends Exception {
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.exception;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* 异常工厂
|
||||
*
|
||||
* @param <X> 异常类型
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IExceptionFactory<X extends Exception> {
|
||||
/**
|
||||
* 创建异常
|
||||
*
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
X create();
|
||||
|
||||
/**
|
||||
* 使用指定 {@code message} 创建异常
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
X create(String message);
|
||||
|
||||
/**
|
||||
* 使用指定 {@code cause} 创建异常
|
||||
*
|
||||
* @param cause 包装的异常
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
X create(Throwable cause);
|
||||
|
||||
/**
|
||||
* 使用指定 {@code message} 和 {@code cause} 创建异常
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @param cause 包装的异常
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
X create(String message, Throwable cause);
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.exception;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.Virtual;
|
||||
import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
|
||||
/**
|
||||
* 异常场景
|
||||
*
|
||||
* @param <TCode> 场景编码
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IExceptionType<TCode> extends IWithCode<TCode> {
|
||||
|
||||
/**
|
||||
* 默认异常信息
|
||||
*/
|
||||
String getDefaultMessage();
|
||||
|
||||
@Virtual
|
||||
default String getDescription() {
|
||||
return getDefaultMessage();
|
||||
}
|
||||
|
||||
}
|
@@ -17,25 +17,24 @@ package xyz.zhouxy.plusone.commons.exception;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
|
||||
/**
|
||||
* MultiTypesException
|
||||
* IMultiTypesException
|
||||
*
|
||||
* <p>
|
||||
* 异常在不同场景下被抛出,可以用不同的枚举值,表示不同的场景类型。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 异常实现 {@link MultiTypesException} 的 {@link #getType} 方法,返回对应的场景类型。
|
||||
* </p>
|
||||
* 异常实现 {@link IMultiTypesException} 的 {@link #getType} 方法,返回对应的场景类型。
|
||||
*
|
||||
* <p>
|
||||
* 表示场景类型的枚举实现 {@link ExceptionType},其中的工厂方法用于创建类型对象。
|
||||
* </p>
|
||||
* 表示场景类型的枚举实现 {@link IExceptionType},各个枚举值本身就是该场景的异常的工厂实例,
|
||||
* 使用其中的工厂方法用于创建对应类型的异常。
|
||||
*
|
||||
* <pre>
|
||||
* public final class LoginException
|
||||
* extends RuntimeException
|
||||
* implements MultiTypesException<LoginException, LoginException.Type> {
|
||||
* implements IMultiTypesException<LoginException.Type> {
|
||||
* private static final long serialVersionUID = 881293090625085616L;
|
||||
* private final Type type;
|
||||
* private LoginException(@Nonnull Type type, @Nonnull String message) {
|
||||
* super(message);
|
||||
@@ -61,7 +60,7 @@ import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* public enum Type implements ExceptionType<LoginException> {
|
||||
* public enum Type implements IExceptionType<String>, IExceptionFactory<LoginException> {
|
||||
* DEFAULT("00", "当前会话未登录"),
|
||||
* NOT_TOKEN("10", "未提供token"),
|
||||
* INVALID_TOKEN("20", "token无效"),
|
||||
@@ -117,75 +116,18 @@ import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
* <pre>
|
||||
* throw LoginException.Type.TOKEN_TIMEOUT.create();
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @param <T> 异常场景
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface MultiTypesException<E extends Exception, T extends MultiTypesException.ExceptionType<E>> {
|
||||
public interface IMultiTypesException<T extends IExceptionType<?>> {
|
||||
|
||||
/**
|
||||
* 异常类型
|
||||
*
|
||||
* @return 异常类型。通常是实现了 {@link ExceptionType} 的枚举。
|
||||
* @return 异常类型。通常是实现了 {@link IExceptionType} 的枚举。
|
||||
*/
|
||||
@Nonnull
|
||||
T getType();
|
||||
|
||||
/**
|
||||
* 获取异常类型编码
|
||||
*
|
||||
* @return 异常类型编码
|
||||
*/
|
||||
default @Nonnull String getTypeCode() {
|
||||
return getType().getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常类型
|
||||
*/
|
||||
public static interface ExceptionType<E extends Exception> extends IWithCode<String> {
|
||||
|
||||
/**
|
||||
* 默认异常信息
|
||||
*/
|
||||
String getDefaultMessage();
|
||||
|
||||
/**
|
||||
* 创建异常
|
||||
*
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
E create();
|
||||
|
||||
/**
|
||||
* 使用指定 {@code message} 创建异常
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
E create(String message);
|
||||
|
||||
/**
|
||||
* 使用指定 {@code cause} 创建异常
|
||||
*
|
||||
* @param cause 包装的异常
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
E create(Throwable cause);
|
||||
|
||||
/**
|
||||
* 使用指定 {@code message} 和 {@code cause} 创建异常
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @param cause 包装的异常
|
||||
* @return 异常对象
|
||||
*/
|
||||
@Nonnull
|
||||
E create(String message, Throwable cause);
|
||||
|
||||
}
|
||||
}
|
@@ -21,7 +21,6 @@ import java.time.format.DateTimeParseException;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.exception.business.RequestParamsException;
|
||||
import xyz.zhouxy.plusone.commons.exception.MultiTypesException.ExceptionType;
|
||||
|
||||
/**
|
||||
* 解析失败异常
|
||||
@@ -31,16 +30,16 @@ import xyz.zhouxy.plusone.commons.exception.MultiTypesException.ExceptionType;
|
||||
* 如果表示用户传参造成的解析失败,可使用 {@link RequestParamsException#RequestParamsException(Throwable)},
|
||||
* 将 ParsingFailureException 包装成 {@link RequestParamsException} 再抛出。
|
||||
* <pre>
|
||||
* throw new RequestParamsException(ParsingFailureException.of(ParsingFailureException.Type.NUMBER_PARSING_FAILURE));
|
||||
* throw new RequestParamsException(ParsingFailureException.Type.NUMBER_PARSING_FAILURE.create());
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class ParsingFailureException
|
||||
extends RuntimeException
|
||||
implements MultiTypesException<ParsingFailureException, ParsingFailureException.Type> {
|
||||
extends Exception
|
||||
implements IMultiTypesException<ParsingFailureException.Type> {
|
||||
private static final long serialVersionUID = 795996090625132616L;
|
||||
|
||||
private final Type type;
|
||||
|
||||
@@ -171,7 +170,7 @@ public final class ParsingFailureException
|
||||
/** XML 解析失败 */
|
||||
public static final Type XML_PARSING_FAILURE = Type.XML_PARSING_FAILURE;
|
||||
|
||||
public enum Type implements ExceptionType<ParsingFailureException> {
|
||||
public enum Type implements IExceptionType<String>, IExceptionFactory<ParsingFailureException> {
|
||||
DEFAULT("00", "解析失败"),
|
||||
NUMBER_PARSING_FAILURE("10", "数字转换失败"),
|
||||
DATE_TIME_PARSING_FAILURE("20", "时间解析失败"),
|
@@ -21,15 +21,15 @@ package xyz.zhouxy.plusone.commons.exception.business;
|
||||
*
|
||||
* <p>
|
||||
* 业务异常
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 通常表示业务中的意外情况。如:用户错误输入、缺失必填字段、用户余额不足等。</b>
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class BizException extends RuntimeException {
|
||||
private static final long serialVersionUID = 982585090625482416L;
|
||||
|
||||
private static final String DEFAULT_MSG = "业务异常";
|
||||
|
@@ -18,25 +18,26 @@ package xyz.zhouxy.plusone.commons.exception.business;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.exception.MultiTypesException.ExceptionType;
|
||||
import xyz.zhouxy.plusone.commons.exception.MultiTypesException;
|
||||
import xyz.zhouxy.plusone.commons.exception.IExceptionFactory;
|
||||
import xyz.zhouxy.plusone.commons.exception.IExceptionType;
|
||||
import xyz.zhouxy.plusone.commons.exception.IMultiTypesException;
|
||||
|
||||
/**
|
||||
* InvalidInputException
|
||||
*
|
||||
* <p>
|
||||
* 用户输入内容非法
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 属业务异常</b>
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class InvalidInputException
|
||||
extends RequestParamsException
|
||||
implements MultiTypesException<InvalidInputException, InvalidInputException.Type> {
|
||||
implements IMultiTypesException<InvalidInputException.Type> {
|
||||
private static final long serialVersionUID = -28994090625082516L;
|
||||
|
||||
private final Type type;
|
||||
|
||||
@@ -109,7 +110,7 @@ public final class InvalidInputException
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public enum Type implements ExceptionType<InvalidInputException> {
|
||||
public enum Type implements IExceptionType<String>, IExceptionFactory<InvalidInputException> {
|
||||
DEFAULT("00", "用户输入内容非法"),
|
||||
CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS("01", "包含非法恶意跳转链接"),
|
||||
CONTAINS_ILLEGAL_WORDS("02", "包含违禁敏感词"),
|
@@ -21,12 +21,12 @@ package xyz.zhouxy.plusone.commons.exception.business;
|
||||
*
|
||||
* <p>
|
||||
* 用户请求参数错误
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class RequestParamsException extends BizException {
|
||||
private static final long serialVersionUID = 448337090625192516L;
|
||||
|
||||
private static final String DEFAULT_MSG = "用户请求参数错误";
|
||||
|
@@ -17,6 +17,6 @@
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.exception.business;
|
@@ -15,23 +15,24 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <h2>异常<h2>
|
||||
* <h2>异常</h2>
|
||||
*
|
||||
* <h3>1. {@link MultiTypesException} - 多类型异常</h3>
|
||||
* <h3>1. {@link IMultiTypesException} - 多类型异常</h3>
|
||||
* <p>
|
||||
* 异常在不同场景下被抛出,可以用不同的枚举值,表示不同的场景类型。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 异常实现 {@link MultiTypesException} 的 {@link MultiTypesException#getType} 方法,返回对应的场景类型。
|
||||
* </p>
|
||||
* 异常实现 {@link IMultiTypesException} 的 {@link IMultiTypesException#getType} 方法,返回对应的场景类型。
|
||||
*
|
||||
* <p>
|
||||
* 表示场景类型的枚举实现 {@link MultiTypesException.ExceptionType},其中的工厂方法用于创建类型对象。
|
||||
* </p>
|
||||
* 表示场景类型的枚举实现 {@link IMultiTypesException.IExceptionType},各个枚举值本身就是该场景的异常的工厂实例,
|
||||
* 使用其中的工厂方法用于创建对应类型的异常。
|
||||
*
|
||||
* <pre>
|
||||
* public final class LoginException
|
||||
* extends RuntimeException
|
||||
* implements MultiTypesException<LoginException, LoginException.Type> {
|
||||
* implements IMultiTypesException<LoginException, LoginException.Type, String> {
|
||||
* private static final long serialVersionUID = 881293090625085616L;
|
||||
* private final Type type;
|
||||
* private LoginException(@Nonnull Type type, @Nonnull String message) {
|
||||
* super(message);
|
||||
@@ -57,7 +58,7 @@
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* public enum Type implements ExceptionType<LoginException> {
|
||||
* public enum Type implements IExceptionType<LoginException, String> {
|
||||
* DEFAULT("00", "当前会话未登录"),
|
||||
* NOT_TOKEN("10", "未提供token"),
|
||||
* INVALID_TOKEN("20", "token无效"),
|
||||
@@ -113,7 +114,6 @@
|
||||
* <pre>
|
||||
* throw LoginException.Type.TOKEN_TIMEOUT.create();
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <h3>2. 业务异常</h3>
|
||||
* 预设常见的业务异常。可继承 {@link BizException} 自定义业务异常。
|
||||
@@ -121,7 +121,7 @@
|
||||
* <h3>3. 系统异常</h3>
|
||||
* 预设常见的系统异常。可继承 {@link SysException} 自定义系统异常。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.exception;
|
||||
|
@@ -21,55 +21,61 @@ package xyz.zhouxy.plusone.commons.exception.system;
|
||||
*
|
||||
* <p>
|
||||
* 当数据操作的结果不符合预期时抛出。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 比如当一个 insert 或 update 操作时,预计影响数据库中的一行数据,但结果却影响了零条数据或多条数据,
|
||||
* 当出现这种始料未及的诡异情况时,抛出 {@link DataOperationResultException} 并回滚事务。
|
||||
* 后续需要排查原因。
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class DataOperationResultException extends SysException {
|
||||
private static final long serialVersionUID = 992754090625352516L;
|
||||
|
||||
private static final String DEFAULT_MSG = "数据操作的结果不符合预期";
|
||||
private final long expected;
|
||||
private final long actual;
|
||||
|
||||
/**
|
||||
* 使用默认 message 构造新的 {@code DataOperationResultException}。
|
||||
* {@code cause} 未初始化,后面可能会通过调用 {@link #initCause} 进行初始化。
|
||||
* 创建一个 {@code DataOperationResultException} 对象
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actual 实际影响的行数
|
||||
*/
|
||||
public DataOperationResultException() {
|
||||
super(DEFAULT_MSG);
|
||||
public DataOperationResultException(long expected, long actual) {
|
||||
super(String.format("The number of rows affected is expected to be %d, but is: %d", expected, actual));
|
||||
this.expected = expected;
|
||||
this.actual = actual;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的 {@code message} 构造新的 {@code DataOperationResultException}。
|
||||
* {@code cause} 未初始化,后面可能会通过调用 {@link #initCause} 进行初始化。
|
||||
* 创建一个 {@code DataOperationResultException} 对象
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @param expected 预期影响的行数
|
||||
* @param actual 实际影响的行数
|
||||
* @param message 错误信息
|
||||
*/
|
||||
public DataOperationResultException(String message) {
|
||||
public DataOperationResultException(long expected, long actual, String message) {
|
||||
super(message);
|
||||
this.expected = expected;
|
||||
this.actual = actual;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的 {@code cause} 构造新的 {@code DataOperationResultException}。
|
||||
* {@code message} 为 (cause==null ? null : cause.toString())。
|
||||
* 预期影响的行数
|
||||
*
|
||||
* @param cause 包装的异常
|
||||
* @return the expected
|
||||
*/
|
||||
public DataOperationResultException(Throwable cause) {
|
||||
super(cause);
|
||||
public long getExpected() {
|
||||
return expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的 {@code message} 和 {@code cause} 构造新的 {@code DataOperationResultException}。
|
||||
* 实际影响的行数
|
||||
*
|
||||
* @param message 异常信息
|
||||
* @param cause 包装的异常
|
||||
* @return the actual
|
||||
*/
|
||||
public DataOperationResultException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
public long getActual() {
|
||||
return actual;
|
||||
}
|
||||
}
|
@@ -21,9 +21,8 @@ package xyz.zhouxy.plusone.commons.exception.system;
|
||||
*
|
||||
* <p>
|
||||
* 在无法找到可访问的 Mac 地址时抛出
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class NoAvailableMacFoundException extends SysException {
|
@@ -21,12 +21,12 @@ package xyz.zhouxy.plusone.commons.exception.system;
|
||||
*
|
||||
* <p>
|
||||
* 通常表示应用代码存在问题,或因环境问题,引发异常。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SysException extends RuntimeException {
|
||||
private static final long serialVersionUID = -936435090625482516L;
|
||||
|
||||
private static final String DEFAULT_MSG = "系统异常";
|
||||
|
@@ -17,6 +17,6 @@
|
||||
/**
|
||||
* 系统异常
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.exception.system;
|
@@ -24,9 +24,8 @@ import com.google.common.annotations.Beta;
|
||||
* <p>
|
||||
* 一个特殊的 {@link java.util.function.UnaryOperator}。
|
||||
* 表示对 {@code boolean} 值的一元操作。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see java.util.function.UnaryOperator
|
||||
*/
|
@@ -24,9 +24,8 @@ import com.google.common.annotations.Beta;
|
||||
* <p>
|
||||
* 一个特殊的 {@link java.util.function.UnaryOperator}。
|
||||
* 表示对 {@code char} 的一元操作。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see java.util.function.UnaryOperator
|
||||
*/
|
@@ -21,11 +21,10 @@ package xyz.zhouxy.plusone.commons.function;
|
||||
*
|
||||
* <p>
|
||||
* 表示一个无入参无返回值的操作,可抛出异常。
|
||||
* </p>
|
||||
*
|
||||
* @param <E> 可抛出的异常类型
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
@@ -24,9 +24,8 @@ import java.util.function.Supplier;
|
||||
*
|
||||
* <p>
|
||||
* 返回 {@code Optional<T>} 对象。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see Optional
|
||||
* @see Supplier
|
@@ -23,9 +23,8 @@ import java.util.function.Predicate;
|
||||
*
|
||||
* <p>
|
||||
* {@link Predicate} 相关操作。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see Predicate
|
||||
*/
|
@@ -21,9 +21,8 @@ package xyz.zhouxy.plusone.commons.function;
|
||||
*
|
||||
* <p>
|
||||
* 允许抛出异常的消费操作。是一个特殊的 {@link java.util.function.Consumer}。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see java.util.function.Consumer
|
||||
*/
|
@@ -20,13 +20,12 @@ package xyz.zhouxy.plusone.commons.function;
|
||||
*
|
||||
* <p>
|
||||
* 接收一个参数,并返回一个结果,可以抛出异常。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param <R> 返回结果类型
|
||||
* @param <E> 异常类型
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0
|
||||
* @see java.util.function.Function
|
||||
*/
|
@@ -21,9 +21,8 @@ package xyz.zhouxy.plusone.commons.function;
|
||||
*
|
||||
* <p>
|
||||
* 接收一个参数,返回一个布尔值,可抛出异常。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see java.util.function.Predicate
|
||||
*/
|
@@ -21,12 +21,11 @@ package xyz.zhouxy.plusone.commons.function;
|
||||
*
|
||||
* <p>
|
||||
* 允许抛出异常的 Supplier 接口。
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 结果类型
|
||||
* @param <E> 异常类型
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see java.util.function.Supplier
|
||||
*/
|
@@ -25,7 +25,7 @@ import java.util.function.BiFunction;
|
||||
* <p>
|
||||
* 接受类型为 T 和 U 的两个参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see Optional
|
||||
* @see BiFunction
|
@@ -25,7 +25,7 @@ import java.util.function.Function;
|
||||
* <p>
|
||||
* 接受类型为 T 的参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see Optional
|
||||
* @see Function
|
@@ -20,7 +20,6 @@
|
||||
* <h3>1. PredicateTools</h3>
|
||||
* <p>
|
||||
* {@link PredicateTools} 用于 {@link java.util.function.Predicate} 的相关操作。
|
||||
* </p>
|
||||
*
|
||||
* <h3>2. Functional interfaces</h3>
|
||||
* <p>
|
||||
@@ -39,8 +38,7 @@
|
||||
* | Optional | ToOptionalBiFunction | Optional<R> apply(T,U) |
|
||||
* | Optional | ToOptionalFunction | Optional<R> apply(T) |
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.function;
|
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.gson.adapter;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* 包含 JSR-310 相关数据类型的 {@code TypeAdapter}
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.1.0
|
||||
* @see TypeAdapter
|
||||
* @see com.google.gson.GsonBuilder
|
||||
*/
|
||||
public class JSR310TypeAdapters {
|
||||
|
||||
/**
|
||||
* {@code LocalDate} 的 {@code TypeAdapter},
|
||||
* 用于 Gson 对 {@code LocalDate} 进行相互转换。
|
||||
*/
|
||||
public static final class LocalDateTypeAdapter
|
||||
extends TemporalAccessorTypeAdapter<LocalDate, LocalDateTypeAdapter> {
|
||||
|
||||
/**
|
||||
* 默认构造函数,
|
||||
* 使用 {@link DateTimeFormatter#ISO_LOCAL_DATE} 进行 {@link LocalDate} 的序列化与反序列化。
|
||||
*/
|
||||
public LocalDateTypeAdapter() {
|
||||
this(DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数,
|
||||
* 使用传入的 {@link DateTimeFormatter} 进行 {@link LocalDate} 的序列化与反序列化。
|
||||
*
|
||||
* @param formatter 用于序列化 {@link LocalDate} 的格式化器,不可为 {@code null}。
|
||||
*/
|
||||
public LocalDateTypeAdapter(DateTimeFormatter formatter) {
|
||||
super(LocalDate::from, formatter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code LocalDateTime} 的 {@code TypeAdapter},
|
||||
* 用于 Gson 对 {@code LocalDateTime} 进行相互转换。
|
||||
*/
|
||||
public static final class LocalDateTimeTypeAdapter
|
||||
extends TemporalAccessorTypeAdapter<LocalDateTime, LocalDateTimeTypeAdapter> {
|
||||
|
||||
/**
|
||||
* 默认构造函数,
|
||||
* 使用 {@link DateTimeFormatter#ISO_LOCAL_DATE_TIME} 进行 {@link LocalDateTime} 的序列化与反序列化。
|
||||
*/
|
||||
public LocalDateTimeTypeAdapter() {
|
||||
this(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数,
|
||||
* 使用传入的 {@link DateTimeFormatter} 进行 {@link LocalDateTime} 的序列化与反序列化。
|
||||
*
|
||||
* @param formatter 用于序列化 {@link LocalDateTime} 的格式化器,不可为 {@code null}。
|
||||
*/
|
||||
public LocalDateTimeTypeAdapter(DateTimeFormatter formatter) {
|
||||
super(LocalDateTime::from, formatter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code ZonedDateTime} 的 {@code TypeAdapter},
|
||||
* 用于 Gson 对 {@code ZonedDateTime} 进行相互转换。
|
||||
*/
|
||||
public static final class ZonedDateTimeTypeAdapter
|
||||
extends TemporalAccessorTypeAdapter<ZonedDateTime, ZonedDateTimeTypeAdapter> {
|
||||
|
||||
/**
|
||||
* 默认构造函数,
|
||||
* 使用 {@link DateTimeFormatter#ISO_ZONED_DATE_TIME} 进行 {@link ZonedDateTime} 的序列化与反序列化。
|
||||
*/
|
||||
public ZonedDateTimeTypeAdapter() {
|
||||
this(DateTimeFormatter.ISO_ZONED_DATE_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数,
|
||||
* 使用传入的 {@link DateTimeFormatter} 进行 {@link ZonedDateTime} 的序列化与反序列化。
|
||||
*
|
||||
* @param formatter 用于序列化 {@link ZonedDateTime} 的格式化器,不可为 {@code null}。
|
||||
*/
|
||||
public ZonedDateTimeTypeAdapter(DateTimeFormatter formatter) {
|
||||
super(ZonedDateTime::from, formatter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Instant} 的 {@code TypeAdapter},
|
||||
* 用于 Gson 对 {@code Instant} 进行相互转换。
|
||||
*
|
||||
* <p>
|
||||
* 使用 {@link DateTimeFormatter#ISO_INSTANT} 进行 {@link Instant} 的序列化与反序列化。
|
||||
*
|
||||
*/
|
||||
public static final class InstantTypeAdapter
|
||||
extends TemporalAccessorTypeAdapter<Instant, InstantTypeAdapter> {
|
||||
|
||||
public InstantTypeAdapter() {
|
||||
super(Instant::from, DateTimeFormatter.ISO_INSTANT);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class TemporalAccessorTypeAdapter<
|
||||
T extends TemporalAccessor,
|
||||
TTypeAdapter extends TemporalAccessorTypeAdapter<T, TTypeAdapter>>
|
||||
extends TypeAdapter<T> {
|
||||
|
||||
private final TemporalQuery<T> temporalQuery;
|
||||
|
||||
private final DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
protected TemporalAccessorTypeAdapter(
|
||||
TemporalQuery<T> temporalQuery, DateTimeFormatter dateTimeFormatter) {
|
||||
checkArgumentNotNull(dateTimeFormatter, "formatter must not be null.");
|
||||
this.temporalQuery = temporalQuery;
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
out.value(dateTimeFormatter.format(value));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public T read(JsonReader in) throws IOException {
|
||||
return dateTimeFormatter.parse(in.nextString(), temporalQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private JSR310TypeAdapters() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gson 相关类型适配器
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.gson.adapter;
|
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gson 相关辅助工具
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.gson;
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -32,7 +34,6 @@ import com.google.errorprone.annotations.Immutable;
|
||||
import xyz.zhouxy.plusone.commons.annotation.ReaderMethod;
|
||||
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
|
||||
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
|
||||
/**
|
||||
@@ -40,9 +41,8 @@ import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
*
|
||||
* <p>
|
||||
* 中国第二代居民身份证号
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see xyz.zhouxy.plusone.commons.constant.PatternConsts#CHINESE_2ND_ID_CARD_NUMBER
|
||||
*/
|
||||
@@ -87,13 +87,13 @@ public class Chinese2ndGenIDCardNumber
|
||||
*/
|
||||
public static Chinese2ndGenIDCardNumber of(final String idCardNumber) {
|
||||
try {
|
||||
AssertTools.checkArgument(StringTools.isNotBlank(idCardNumber), "二代居民身份证校验失败:号码为空");
|
||||
checkArgument(StringTools.isNotBlank(idCardNumber), "二代居民身份证校验失败:号码为空");
|
||||
final String value = idCardNumber.toUpperCase();
|
||||
final Matcher matcher = PatternConsts.CHINESE_2ND_ID_CARD_NUMBER.matcher(value);
|
||||
AssertTools.checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value);
|
||||
checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value);
|
||||
|
||||
final String provinceCode = matcher.group("province");
|
||||
AssertTools.checkArgument(Chinese2ndGenIDCardNumber.PROVINCE_CODES.containsKey(provinceCode));
|
||||
checkArgument(Chinese2ndGenIDCardNumber.PROVINCE_CODES.containsKey(provinceCode));
|
||||
|
||||
final String cityCode = matcher.group("city");
|
||||
final String countyCode = matcher.group("county");
|
@@ -16,13 +16,14 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkCondition;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.IWithIntCode;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public enum Gender implements IWithIntCode {
|
||||
UNKNOWN(0, "Unknown", "未知"),
|
||||
@@ -50,7 +51,7 @@ public enum Gender implements IWithIntCode {
|
||||
* @return 枚举值
|
||||
*/
|
||||
public static Gender of(int value) {
|
||||
AssertTools.checkCondition(0 <= value && value < VALUES.length,
|
||||
checkCondition(0 <= value && value < VALUES.length,
|
||||
() -> new EnumConstantNotPresentException(Gender.class, String.valueOf(value)));
|
||||
return VALUES[value];
|
||||
}
|
@@ -23,6 +23,8 @@ import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
|
||||
/**
|
||||
* 身份证号
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public interface IDCardNumber {
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -25,12 +27,11 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.ReaderMethod;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 带校验的字符串值对象
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @deprecated 弃用。使用工厂方法创建对象,并在其中进行校验即可。
|
||||
@@ -74,10 +75,10 @@ public abstract class ValidatableStringRecord<T extends ValidatableStringRecord<
|
||||
* @param errorMessage 正则不匹配时的错误信息
|
||||
*/
|
||||
protected ValidatableStringRecord(String value, Pattern pattern, String errorMessage) {
|
||||
AssertTools.checkArgument(Objects.nonNull(value), "The value cannot be null.");
|
||||
AssertTools.checkArgument(Objects.nonNull(pattern), "The pattern cannot be null.");
|
||||
checkArgument(Objects.nonNull(value), "The value cannot be null.");
|
||||
checkArgument(Objects.nonNull(pattern), "The pattern cannot be null.");
|
||||
this.matcher = pattern.matcher(value);
|
||||
AssertTools.checkArgument(this.matcher.matches(), errorMessage);
|
||||
checkArgument(this.matcher.matches(), errorMessage);
|
||||
this.value = value;
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ import xyz.zhouxy.plusone.commons.collection.CollectionTools;
|
||||
*
|
||||
* @param <T> 内容列表的元素类型
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @see PagingAndSortingQueryParams
|
||||
*/
|
||||
public class PageResult<T> {
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -27,7 +29,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.Virtual;
|
||||
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.plusone.commons.util.RegexTools;
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
|
||||
@@ -37,9 +38,9 @@ import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
* <p>
|
||||
* 根据传入的 {@code size} 和 {@code pageNum},
|
||||
* 提供 {@code getOffset} 方法计算 SQL 语句中 {@code offset} 的值。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @see PagingParams
|
||||
* @see PageResult
|
||||
*/
|
||||
public class PagingAndSortingQueryParams {
|
||||
@@ -60,10 +61,10 @@ public class PagingAndSortingQueryParams {
|
||||
* @param sortableProperties 可排序的属性。不可为空。
|
||||
*/
|
||||
public PagingAndSortingQueryParams(Map<String, String> sortableProperties) {
|
||||
AssertTools.checkArgument(CollectionTools.isNotEmpty(sortableProperties),
|
||||
checkArgument(CollectionTools.isNotEmpty(sortableProperties),
|
||||
"Sortable properties can not be empty.");
|
||||
sortableProperties.forEach((k, v) ->
|
||||
AssertTools.checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v),
|
||||
checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v),
|
||||
"Property name must not be blank."));
|
||||
this.sortableProperties = ImmutableMap.copyOf(sortableProperties);
|
||||
}
|
||||
@@ -107,7 +108,7 @@ public class PagingAndSortingQueryParams {
|
||||
public final PagingParams buildPagingParams() {
|
||||
final int sizeValue = this.size != null ? this.size : defaultSizeInternal();
|
||||
final long pageNumValue = this.pageNum != null ? this.pageNum : 1L;
|
||||
AssertTools.checkArgument(CollectionTools.isNotEmpty(this.orderBy),
|
||||
checkArgument(CollectionTools.isNotEmpty(this.orderBy),
|
||||
"The 'orderBy' cannot be empty");
|
||||
final List<SortableProperty> propertiesToSort = this.orderBy.stream()
|
||||
.map(this::generateSortableProperty)
|
||||
@@ -138,13 +139,13 @@ public class PagingAndSortingQueryParams {
|
||||
}
|
||||
|
||||
private SortableProperty generateSortableProperty(String orderByStr) {
|
||||
AssertTools.checkArgument(StringTools.isNotBlank(orderByStr));
|
||||
AssertTools.checkArgument(RegexTools.matches(orderByStr, SORT_STR_PATTERN));
|
||||
checkArgument(StringTools.isNotBlank(orderByStr));
|
||||
checkArgument(RegexTools.matches(orderByStr, SORT_STR_PATTERN));
|
||||
String[] propertyNameAndOrderType = orderByStr.split("-");
|
||||
AssertTools.checkArgument(propertyNameAndOrderType.length == 2);
|
||||
checkArgument(propertyNameAndOrderType.length == 2);
|
||||
|
||||
String propertyName = propertyNameAndOrderType[0];
|
||||
AssertTools.checkArgument(sortableProperties.containsKey(propertyName),
|
||||
checkArgument(sortableProperties.containsKey(propertyName),
|
||||
"The property name must be in the set of sortable properties.");
|
||||
String columnName = sortableProperties.get(propertyName);
|
||||
String orderType = propertyNameAndOrderType[1];
|
||||
@@ -164,7 +165,7 @@ public class PagingAndSortingQueryParams {
|
||||
SortableProperty(String propertyName, String columnName, String orderType) {
|
||||
this.propertyName = propertyName;
|
||||
this.columnName = columnName;
|
||||
AssertTools.checkArgument("ASC".equalsIgnoreCase(orderType) || "DESC".equalsIgnoreCase(orderType));
|
||||
checkArgument("ASC".equalsIgnoreCase(orderType) || "DESC".equalsIgnoreCase(orderType));
|
||||
this.orderType = orderType.toUpperCase();
|
||||
|
||||
this.sqlSnippet = this.propertyName + " " + this.orderType;
|
@@ -21,6 +21,12 @@ import java.util.List;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.model.dto.PagingAndSortingQueryParams.SortableProperty;
|
||||
|
||||
/**
|
||||
* 分页参数
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @see PagingAndSortingQueryParams
|
||||
*/
|
||||
public class PagingParams {
|
||||
|
||||
/** 每页大小 */
|
@@ -22,7 +22,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* 统一结果,对返回给前端的数据进行封装。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class UnifiedResponse<T> {
|
||||
|
@@ -21,7 +21,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* UnifiedResponse 工厂
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see UnifiedResponse
|
||||
*/
|
||||
@@ -40,7 +40,7 @@ public class UnifiedResponses {
|
||||
* @return {@code UnifiedResponse} 对象。
|
||||
* {@code code} = "2000000", {@code message} = "SUCCESS", {@code data} = null
|
||||
*/
|
||||
public static UnifiedResponse<Void> success() {
|
||||
public static <T> UnifiedResponse<T> success() {
|
||||
return new UnifiedResponse<>(SUCCESS_CODE, DEFAULT_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class UnifiedResponses {
|
||||
* @return {@code UnifiedResponse} 对象。
|
||||
* {@code code} = "2000000", {@code data} = null
|
||||
*/
|
||||
public static UnifiedResponse<Void> success(@Nullable String message) {
|
||||
public static <T> UnifiedResponse<T> success(@Nullable String message) {
|
||||
return new UnifiedResponse<>(SUCCESS_CODE, message);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class UnifiedResponses {
|
||||
* @param message 错误信息
|
||||
* @return {@code UnifiedResponse} 对象({@code data} 为 {@code null})
|
||||
*/
|
||||
public static UnifiedResponse<Void> error(String code, @Nullable String message) {
|
||||
public static <T> UnifiedResponse<T> error(String code, @Nullable String message) {
|
||||
return new UnifiedResponse<>(code, message);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ public class UnifiedResponses {
|
||||
* {@code message} 为异常的 {@code message},
|
||||
* {@code data} 为 {@code null}。
|
||||
*/
|
||||
public static UnifiedResponse<Void> error(String code, Throwable e) {
|
||||
public static <T> UnifiedResponse<T> error(String code, Throwable e) {
|
||||
return new UnifiedResponse<>(code, e.getMessage());
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public class UnifiedResponses {
|
||||
* @param message 响应信息
|
||||
* @return {@code UnifiedResponse} 对象({@code data} 为 {@code null})
|
||||
*/
|
||||
public static UnifiedResponse<Void> of(String code, @Nullable String message) {
|
||||
public static <T> UnifiedResponse<T> of(String code, @Nullable String message) {
|
||||
return new UnifiedResponse<>(code, message);
|
||||
}
|
||||
|
@@ -22,12 +22,12 @@
|
||||
* 分页组件由 {@link PagingAndSortingQueryParams} 作为入参,
|
||||
* 因为分页必须伴随着排序,不然可能出现同一个对象重复出现在不同页,有的对象不被查询到的情况,
|
||||
* 所以分页查询的入参必须包含排序条件。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 用户可继承 {@link PagingAndSortingQueryParams}
|
||||
* 构建自己的分页查询入参,需在构造器中调用 {@link PagingAndSortingQueryParams} 的构造器,传入一个 Map 作为白名单,
|
||||
* key 是供前端指定用于排序的属性名,value 是对应数据库中的字段名,只有在白名单中指定的属性名才允许作为排序条件。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* {@link PagingAndSortingQueryParams} 包含三个主要的属性:
|
||||
* <ul>
|
||||
@@ -37,21 +37,20 @@
|
||||
* </ul>
|
||||
* 其中 orderBy 是一个 List,可以指定多个排序条件,每个排序条件是一个字符串,
|
||||
* 格式为“属性名-ASC”或“属性名-DESC”,分别表示升序和降序。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 比如前端传入的 orderBy 为 ["name-ASC","age-DESC"],意味着要按 name 进行升序,name 相同的情况下则按 age 进行降序。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 使用时调用 {@link PagingAndSortingQueryParams#buildPagingParams()} 方法获取分页参数 {@link PagingParams}。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 分页结果可以存放到 {@link PageResult} 中,作为出参。
|
||||
* </p>
|
||||
*
|
||||
* <h3>2. {@link UnifiedResponse}</h3>
|
||||
* <p>
|
||||
* {@link UnifiedResponse} 对返回给前端的数据进行封装,包含 code、message、data。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 可使用 {@link UnifiedResponses} 快速构建 {@link UnifiedResponse} 对象。
|
||||
* {@link UnifiedResponses} 默认的成功代码为 "2000000",
|
||||
@@ -60,9 +59,8 @@
|
||||
* 中所示范的,继承 {@link UnifiedResponses} 实现自己的工厂类,
|
||||
* 自定义 SUCCESS_CODE 和 DEFAULT_SUCCESS_MSG 和工厂方法。
|
||||
* 见 <a href="http://zhouxy.xyz:3000/plusone/plusone-commons/issues/22">issue#22</a>。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
@@ -18,9 +18,8 @@
|
||||
* <h2>业务建模组件</h2>
|
||||
* <p>
|
||||
* 包含业务建模可能用到的性别、身份证等元素,也包含 DTO 相关类,如分页查询参数,响应结果,分页结果等。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package xyz.zhouxy.plusone.commons.model;
|
@@ -16,6 +16,9 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.time;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkCondition;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Month;
|
||||
import java.time.MonthDay;
|
||||
@@ -25,12 +28,11 @@ import com.google.common.collect.Range;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import xyz.zhouxy.plusone.commons.base.IWithIntCode;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 季度
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public enum Quarter implements IWithIntCode {
|
||||
/** 第一季度 */
|
||||
@@ -89,7 +91,7 @@ public enum Quarter implements IWithIntCode {
|
||||
*/
|
||||
@StaticFactoryMethod(Quarter.class)
|
||||
public static Quarter fromMonth(Month month) {
|
||||
AssertTools.checkNotNull(month);
|
||||
checkNotNull(month);
|
||||
final int monthValue = month.getValue();
|
||||
return of(computeQuarterValueInternal(monthValue));
|
||||
}
|
||||
@@ -246,7 +248,7 @@ public enum Quarter implements IWithIntCode {
|
||||
* @throws DateTimeException 如果给定的季度值不在有效范围内(1到4),将抛出异常
|
||||
*/
|
||||
public static int checkValidIntValue(int value) {
|
||||
AssertTools.checkCondition(value >= 1 && value <= 4,
|
||||
checkCondition(value >= 1 && value <= 4,
|
||||
() -> new DateTimeException("Invalid value for Quarter: " + value));
|
||||
return value;
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
package xyz.zhouxy.plusone.commons.time;
|
||||
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
@@ -32,12 +33,11 @@ import javax.annotation.Nullable;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 表示年份与季度
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@Immutable
|
||||
public final class YearQuarter implements Comparable<YearQuarter>, Serializable {
|
||||
@@ -93,7 +93,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(LocalDate date) {
|
||||
AssertTools.checkNotNull(date);
|
||||
checkNotNull(date);
|
||||
return new YearQuarter(date.getYear(), Quarter.fromMonth(date.getMonth()));
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(Date date) {
|
||||
AssertTools.checkNotNull(date);
|
||||
checkNotNull(date);
|
||||
@SuppressWarnings("deprecation")
|
||||
final int yearValue = YEAR.checkValidIntValue(date.getYear() + 1900L);
|
||||
@SuppressWarnings("deprecation")
|
||||
@@ -121,7 +121,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(Calendar date) {
|
||||
AssertTools.checkNotNull(date);
|
||||
checkNotNull(date);
|
||||
final int yearValue = ChronoField.YEAR.checkValidIntValue(date.get(Calendar.YEAR));
|
||||
final int monthValue = date.get(Calendar.MONTH) + 1;
|
||||
return new YearQuarter(yearValue, Quarter.fromMonth(monthValue));
|
||||
@@ -135,7 +135,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(YearMonth yearMonth) {
|
||||
AssertTools.checkNotNull(yearMonth);
|
||||
checkNotNull(yearMonth);
|
||||
return of(yearMonth.getYear(), Quarter.fromMonth(yearMonth.getMonth()));
|
||||
}
|
||||
|
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* <h2>时间 API<h2>
|
||||
* <h2>时间 API</h2>
|
||||
*
|
||||
* <h3>1. 季度 API</h3>
|
||||
*
|
||||
* 模仿 JDK 的 {@link java.time.Month} 和 {@link java.time.YearMonth},
|
||||
* 实现 {@link Quarter},{@link YearQuarter},对季度进行建模。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package xyz.zhouxy.plusone.commons.time;
|
@@ -16,6 +16,9 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -33,9 +36,8 @@ import javax.annotation.Nullable;
|
||||
*
|
||||
* <p>
|
||||
* 数组工具类
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ArrayTools {
|
||||
@@ -54,9 +56,9 @@ public class ArrayTools {
|
||||
|
||||
public static final int NOT_FOUND_INDEX = -1;
|
||||
|
||||
// #region - isNullOrEmpty
|
||||
// #region - isEmpty
|
||||
|
||||
// isNullOrEmpty
|
||||
// isEmpty
|
||||
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
@@ -65,84 +67,84 @@ public class ArrayTools {
|
||||
* @param <T> 数组中元素的类型
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static <T> boolean isNullOrEmpty(@Nullable T[] arr) {
|
||||
public static <T> boolean isEmpty(@Nullable T[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - char
|
||||
// isEmpty - char
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable char[] arr) {
|
||||
public static boolean isEmpty(@Nullable char[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - byte
|
||||
// isEmpty - byte
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable byte[] arr) {
|
||||
public static boolean isEmpty(@Nullable byte[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - short
|
||||
// isEmpty - short
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable short[] arr) {
|
||||
public static boolean isEmpty(@Nullable short[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - int
|
||||
// isEmpty - int
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable int[] arr) {
|
||||
public static boolean isEmpty(@Nullable int[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - long
|
||||
// isEmpty - long
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable long[] arr) {
|
||||
public static boolean isEmpty(@Nullable long[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - float
|
||||
// isEmpty - float
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable float[] arr) {
|
||||
public static boolean isEmpty(@Nullable float[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
// isNullOrEmpty - double
|
||||
// isEmpty - double
|
||||
/**
|
||||
* 检查给定数组是否为空
|
||||
*
|
||||
* @param arr 待检查的数组,可以为 {@code null}
|
||||
* @return 如果数组为 {@code null} 或长度为 0,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isNullOrEmpty(@Nullable double[] arr) {
|
||||
public static boolean isEmpty(@Nullable double[] arr) {
|
||||
return arr == null || arr.length == 0;
|
||||
}
|
||||
|
||||
@@ -259,7 +261,7 @@ public class ArrayTools {
|
||||
* @throws IllegalArgumentException 当参数为空时抛出
|
||||
*/
|
||||
public static <T> boolean isAllElementsNotNull(final T[] arr) {
|
||||
AssertTools.checkArgument(arr != null, "The array cannot be null.");
|
||||
checkArgument(arr != null, "The array cannot be null.");
|
||||
return Arrays.stream(arr).allMatch(Objects::nonNull);
|
||||
}
|
||||
|
||||
@@ -489,10 +491,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static char[] repeat(char[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_CHAR_ARRAY;
|
||||
@@ -524,10 +526,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static byte[] repeat(byte[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
@@ -559,10 +561,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static short[] repeat(short[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_SHORT_ARRAY;
|
||||
@@ -594,10 +596,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static int[] repeat(int[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_INT_ARRAY;
|
||||
@@ -629,10 +631,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static long[] repeat(long[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_LONG_ARRAY;
|
||||
@@ -664,10 +666,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static float[] repeat(float[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_FLOAT_ARRAY;
|
||||
@@ -699,10 +701,10 @@ public class ArrayTools {
|
||||
* @return 重复后的数组
|
||||
*/
|
||||
public static double[] repeat(double[] arr, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(arr));
|
||||
AssertTools.checkArgument(times >= 0,
|
||||
checkArgument(Objects.nonNull(arr));
|
||||
checkArgument(times >= 0,
|
||||
"The number of times must be greater than or equal to zero");
|
||||
AssertTools.checkArgument(maxLength >= 0,
|
||||
checkArgument(maxLength >= 0,
|
||||
"The max length must be greater than or equal to zero");
|
||||
if (times == 0) {
|
||||
return EMPTY_DOUBLE_ARRAY;
|
||||
@@ -748,7 +750,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(char[] a, int fromIndex, int toIndex, @Nullable char[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -791,7 +793,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(byte[] a, int fromIndex, int toIndex, @Nullable byte[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -834,7 +836,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(short[] a, int fromIndex, int toIndex, @Nullable short[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -877,7 +879,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(int[] a, int fromIndex, int toIndex, @Nullable int[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -920,7 +922,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(long[] a, int fromIndex, int toIndex, @Nullable long[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -963,7 +965,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(float[] a, int fromIndex, int toIndex, @Nullable float[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1006,7 +1008,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
public static void fill(double[] a, int fromIndex, int toIndex, @Nullable double[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1061,7 +1063,7 @@ public class ArrayTools {
|
||||
* @param values 填充内容
|
||||
*/
|
||||
private static <T> void fillInternal(T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
||||
AssertTools.checkArgument(Objects.nonNull(a));
|
||||
checkArgument(Objects.nonNull(a));
|
||||
if (values == null || values.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1088,7 +1090,7 @@ public class ArrayTools {
|
||||
// #region - indexOf
|
||||
|
||||
public static <T> int indexOf(@Nullable T[] arr, Predicate<? super T> predicate) {
|
||||
AssertTools.checkNotNull(predicate);
|
||||
checkNotNull(predicate);
|
||||
if (arr == null || arr.length == 0) {
|
||||
return NOT_FOUND_INDEX;
|
||||
}
|
||||
@@ -1193,7 +1195,7 @@ public class ArrayTools {
|
||||
// #region - lastIndexOf
|
||||
|
||||
public static <T> int lastIndexOf(@Nullable T[] arr, Predicate<? super T> predicate) {
|
||||
AssertTools.checkNotNull(predicate);
|
||||
checkNotNull(predicate);
|
||||
if (arr == null || arr.length == 0) {
|
||||
return NOT_FOUND_INDEX;
|
||||
}
|
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Copyright 2024-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 java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.exception.DataNotExistsException;
|
||||
import xyz.zhouxy.plusone.commons.exception.system.DataOperationResultException;
|
||||
|
||||
/**
|
||||
* 断言工具
|
||||
*
|
||||
* <p>
|
||||
* 本工具类不封装过多判断逻辑,鼓励充分使用项目中的工具类进行逻辑判断。
|
||||
*
|
||||
* <pre>
|
||||
* checkArgument(StringUtils.hasText(str), "The argument cannot be blank.");
|
||||
* checkState(ArrayUtils.isNotEmpty(result), "The result cannot be empty.");
|
||||
* checkCondition(!CollectionUtils.isEmpty(roles),
|
||||
* () -> new InvalidInputException("The roles cannot be empty."));
|
||||
* checkCondition(RegexTools.matches(email, PatternConsts.EMAIL),
|
||||
* "must be a well-formed email address");
|
||||
* </pre>
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class AssertTools {
|
||||
|
||||
// ================================
|
||||
// #region - Argument
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition) {
|
||||
checkCondition(condition, IllegalArgumentException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessage 异常信息
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition, @Nullable String errorMessage) {
|
||||
checkCondition(condition, () -> new IllegalArgumentException(errorMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||
checkCondition(condition, () -> new IllegalArgumentException(errorMessageSupplier.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查实参
|
||||
*
|
||||
* @param condition 判断参数是否符合条件的结果
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws IllegalArgumentException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkArgument(boolean condition,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkCondition(condition,
|
||||
() -> new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - Argument
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - ArgumentNotNull
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(@Nullable T obj) {
|
||||
checkCondition(obj != null, IllegalArgumentException::new);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(@Nullable T obj, String errorMessage) {
|
||||
checkCondition(obj != null, () -> new IllegalArgumentException(errorMessage));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
||||
checkCondition(obj != null, () -> new IllegalArgumentException(errorMessageSupplier.get()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断入参不为 {@code null}
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws IllegalArgumentException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> T checkArgumentNotNull(@Nullable T obj,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkCondition(obj != null,
|
||||
() -> new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - ArgumentNotNull
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - State
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition) {
|
||||
checkCondition(condition, IllegalStateException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessage 异常信息
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition, @Nullable String errorMessage) {
|
||||
checkCondition(condition, () -> new IllegalStateException(errorMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition, Supplier<String> errorMessageSupplier) {
|
||||
checkCondition(condition, () -> new IllegalStateException(errorMessageSupplier.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查状态
|
||||
*
|
||||
* @param condition 判断状态是否符合条件的结果
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws IllegalStateException 当条件不满足时抛出
|
||||
*/
|
||||
public static void checkState(boolean condition,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkCondition(condition,
|
||||
() -> new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - State
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - NotNull
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(@Nullable T obj) {
|
||||
checkCondition(obj != null, NullPointerException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(@Nullable T obj, String errorMessage) {
|
||||
checkCondition(obj != null, () -> new NullPointerException(errorMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(@Nullable T obj, Supplier<String> errorMessageSupplier) {
|
||||
checkCondition(obj != null, () -> new NullPointerException(errorMessageSupplier.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @throws NullPointerException 当 {@code obj} 为 {@code null} 时抛出
|
||||
*/
|
||||
public static <T> void checkNotNull(@Nullable T obj,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkCondition(obj != null,
|
||||
() -> new NullPointerException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - NotNull
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - Exists
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @return 如果 {@code obj} 存在,返回 {@code obj} 本身
|
||||
* @throws DataNotExistsException 当 {@code obj} 不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(@Nullable T obj)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(obj != null, DataNotExistsException::new);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @return 如果 {@code obj} 存在,返回 {@code obj} 本身
|
||||
* @throws DataNotExistsException 当 {@code obj} 不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(@Nullable T obj, String errorMessage)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(obj != null, () -> new DataNotExistsException(errorMessage));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @return 如果 {@code obj} 存在,返回 {@code obj} 本身
|
||||
* @throws DataNotExistsException 当 {@code obj} 不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(@Nullable T obj, Supplier<String> errorMessageSupplier)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(obj != null, () -> new DataNotExistsException(errorMessageSupplier.get()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param obj 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @return 如果 {@code obj} 存在,返回 {@code obj} 本身
|
||||
* @throws DataNotExistsException 当 {@code obj} 不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(@Nullable T obj,
|
||||
String errorMessageTemplate, Object... errorMessageArgs)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(obj != null,
|
||||
() -> new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param optional 入参
|
||||
* @return 如果 {@code optional} 存在,返回 {@code optional} 包含的值
|
||||
* @throws DataNotExistsException 当 {@code optional} 的值不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(Optional<T> optional)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(optional.isPresent(), DataNotExistsException::new);
|
||||
return optional.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param optional 入参
|
||||
* @param errorMessage 异常信息
|
||||
* @return 如果 {@code optional} 存在,返回 {@code optional} 包含的值
|
||||
* @throws DataNotExistsException 当 {@code optional} 的值不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(Optional<T> optional, String errorMessage)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(errorMessage));
|
||||
return optional.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param optional 入参
|
||||
* @param errorMessageSupplier 异常信息
|
||||
* @return 如果 {@code optional} 存在,返回 {@code optional} 包含的值
|
||||
* @throws DataNotExistsException 当 {@code optional} 的值不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(Optional<T> optional, Supplier<String> errorMessageSupplier)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(errorMessageSupplier.get()));
|
||||
return optional.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据是否存在
|
||||
*
|
||||
* @param <T> 入参类型
|
||||
* @param optional 入参
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
* @return 如果 {@code optional} 存在,返回 {@code optional} 包含的值
|
||||
* @throws DataNotExistsException 当 {@code optional} 的值不存在时抛出
|
||||
*/
|
||||
public static <T> T checkExists(Optional<T> optional,
|
||||
String errorMessageTemplate, Object... errorMessageArgs)
|
||||
throws DataNotExistsException {
|
||||
checkCondition(optional.isPresent(),
|
||||
() -> new DataNotExistsException(String.format(errorMessageTemplate, errorMessageArgs)));
|
||||
return optional.get();
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - Exists
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - AffectedRows
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
*/
|
||||
public static void checkAffectedRows(int expected, int actualRowCount) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessage 异常信息
|
||||
*/
|
||||
public static void checkAffectedRows(int expected, int actualRowCount,
|
||||
@Nullable String errorMessage) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageSupplier 异常信息
|
||||
*/
|
||||
public static void checkAffectedRows(int expected, int actualRowCount,
|
||||
Supplier<String> errorMessageSupplier) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount, errorMessageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
*/
|
||||
public static void checkAffectedRows(int expected, int actualRowCount,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount,
|
||||
String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
*/
|
||||
public static void checkAffectedRows(long expected, long actualRowCount) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessage 异常信息
|
||||
*/
|
||||
public static void checkAffectedRows(long expected, long actualRowCount,
|
||||
@Nullable String errorMessage) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageSupplier 异常信息
|
||||
*/
|
||||
public static void checkAffectedRows(long expected, long actualRowCount,
|
||||
Supplier<String> errorMessageSupplier) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount, errorMessageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量与预计不同时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param expected 预期影响的行数
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
*/
|
||||
public static void checkAffectedRows(long expected, long actualRowCount,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (expected != actualRowCount) {
|
||||
throw new DataOperationResultException(expected, actualRowCount,
|
||||
String.format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
*/
|
||||
public static void checkAffectedOneRow(int actualRowCount) {
|
||||
checkAffectedRows(1, actualRowCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessage 异常信息
|
||||
*/
|
||||
public static void checkAffectedOneRow(int actualRowCount, String errorMessage) {
|
||||
checkAffectedRows(1, actualRowCount, errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageSupplier 异常信息
|
||||
*/
|
||||
public static void checkAffectedOneRow(int actualRowCount, Supplier<String> errorMessageSupplier) {
|
||||
checkAffectedRows(1, actualRowCount, errorMessageSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
*/
|
||||
public static void checkAffectedOneRow(int actualRowCount,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkAffectedRows(1, actualRowCount, errorMessageTemplate, errorMessageArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param result 实际影响的数据量
|
||||
*/
|
||||
public static void checkAffectedOneRow(long result) {
|
||||
checkAffectedRows(1L, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessage 异常信息
|
||||
*/
|
||||
public static void checkAffectedOneRow(long actualRowCount, String errorMessage) {
|
||||
checkAffectedRows(1L, actualRowCount, errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageSupplier 异常信息
|
||||
*/
|
||||
public static void checkAffectedOneRow(long actualRowCount, Supplier<String> errorMessageSupplier) {
|
||||
checkAffectedRows(1L, actualRowCount, errorMessageSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当影响的数据量不为 1 时抛出 {@link DataOperationResultException}。
|
||||
*
|
||||
* @param actualRowCount 实际影响的行数
|
||||
* @param errorMessageTemplate 异常信息模板
|
||||
* @param errorMessageArgs 异常信息参数
|
||||
*/
|
||||
public static void checkAffectedOneRow(long actualRowCount,
|
||||
String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
checkAffectedRows(1L, actualRowCount, errorMessageTemplate, errorMessageArgs);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - AffectedRows
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - Condition
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 当条件不满足时抛出异常。
|
||||
*
|
||||
* @param <T> 异常类型
|
||||
* @param condition 条件
|
||||
* @param e 异常
|
||||
* @throws T 当条件不满足时抛出异常
|
||||
*/
|
||||
public static <T extends Exception> void checkCondition(boolean condition, Supplier<T> e)
|
||||
throws T {
|
||||
if (!condition) {
|
||||
throw e.get();
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - constructor
|
||||
// ================================
|
||||
|
||||
private AssertTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -28,9 +30,8 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
*
|
||||
* <p>
|
||||
* BigDecimal 工具类
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class BigDecimals {
|
||||
@@ -54,8 +55,8 @@ public class BigDecimals {
|
||||
* @return 当 {@code a} 大于 {@code b} 时返回 {@code true}
|
||||
*/
|
||||
public static boolean gt(BigDecimal a, BigDecimal b) {
|
||||
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||
checkNotNull(a, "Parameter could not be null.");
|
||||
checkNotNull(b, "Parameter could not be null.");
|
||||
return (a != b) && (a.compareTo(b) > 0);
|
||||
}
|
||||
|
||||
@@ -67,8 +68,8 @@ public class BigDecimals {
|
||||
* @return 当 {@code a} 大于等于 {@code b} 时返回 {@code true}
|
||||
*/
|
||||
public static boolean ge(BigDecimal a, BigDecimal b) {
|
||||
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||
checkNotNull(a, "Parameter could not be null.");
|
||||
checkNotNull(b, "Parameter could not be null.");
|
||||
return (a == b) || (a.compareTo(b) >= 0);
|
||||
}
|
||||
|
||||
@@ -80,8 +81,8 @@ public class BigDecimals {
|
||||
* @return 当 {@code a} 小于 {@code b} 时返回 {@code true}
|
||||
*/
|
||||
public static boolean lt(BigDecimal a, BigDecimal b) {
|
||||
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||
checkNotNull(a, "Parameter could not be null.");
|
||||
checkNotNull(b, "Parameter could not be null.");
|
||||
return (a != b) && (a.compareTo(b) < 0);
|
||||
}
|
||||
|
||||
@@ -93,8 +94,8 @@ public class BigDecimals {
|
||||
* @return 当 {@code a} 小于等于 {@code b} 时返回 {@code true}
|
||||
*/
|
||||
public static boolean le(BigDecimal a, BigDecimal b) {
|
||||
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||
checkNotNull(a, "Parameter could not be null.");
|
||||
checkNotNull(b, "Parameter could not be null.");
|
||||
return (a == b) || (a.compareTo(b) <= 0);
|
||||
}
|
||||
|
||||
@@ -105,7 +106,7 @@ public class BigDecimals {
|
||||
* @return 求和结果
|
||||
*/
|
||||
public static BigDecimal sum(final BigDecimal... numbers) {
|
||||
if (ArrayTools.isNullOrEmpty(numbers)) {
|
||||
if (ArrayTools.isEmpty(numbers)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal result = BigDecimals.nullToZero(numbers[0]);
|
@@ -40,7 +40,7 @@ import xyz.zhouxy.plusone.commons.time.YearQuarter;
|
||||
/**
|
||||
* 日期时间工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class DateTimeTools {
|
||||
|
||||
@@ -215,7 +215,6 @@ public class DateTimeTools {
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @param zone 时区
|
||||
@@ -230,7 +229,6 @@ public class DateTimeTools {
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param zone 时区
|
||||
@@ -245,7 +243,6 @@ public class DateTimeTools {
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上表示的还是还是同一时间戳的时间,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param timeZone 时区
|
||||
@@ -377,258 +374,6 @@ public class DateTimeTools {
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJodaInstant
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param instant {@link java.time.Instant} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.Instant instant) {
|
||||
return new org.joda.time.Instant(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.ZonedDateTime} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param zonedDateTime {@link java.time.ZonedDateTime} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.ZonedDateTime zonedDateTime) {
|
||||
return toJodaInstant(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定时区的地区时间,对应的时间戳。结果为 {@link org.joda.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime {@link java.time.LocalDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.LocalDateTime localDateTime, java.time.ZoneId zone) {
|
||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJavaInstant
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param instant {@link org.joda.time.Instant} 对象
|
||||
* @return {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.Instant instant) {
|
||||
return toInstant(instant.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.DateTime} 对象转换为 Java 的
|
||||
* {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param dateTime joda-time 中表示日期时间的 {@link org.joda.time.DateTime} 对象
|
||||
* @return Java 表示时间戳的 {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.DateTime dateTime) {
|
||||
return toInstant(dateTime.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 对象和
|
||||
* {@link org.joda.time.DateTimeZone} 对象
|
||||
* 转换为 Java 中的 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime
|
||||
* @param zone
|
||||
* @return
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone zone) {
|
||||
return toJavaInstant(localDateTime.toDateTime(zone));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJodaDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
|
||||
* 转换为 joda-time 的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param zonedDateTime 日期时间
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(java.time.ZonedDateTime zonedDateTime) {
|
||||
org.joda.time.DateTimeZone zone = org.joda.time.DateTimeZone.forID(zonedDateTime.getZone().getId());
|
||||
return toJodaInstant(zonedDateTime.toInstant()).toDateTime(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 java.time 中表示日期时间的 {@link java.time.LocalDateTime} 对象和表示时区的
|
||||
* {@link java.time.ZoneId} 对象转换为 joda-time 中对应的 {@link org.joda.time.DateTime}
|
||||
* 对象
|
||||
* 转换为 joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param zone 时区
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.LocalDateTime localDateTime,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(ZonedDateTime.of(localDateTime, zone).toInstant()).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算时间戳在指定时区对应的时间,结果使用 {@link org.joda.time.DateTime} 表示
|
||||
*
|
||||
* @param instant java.time 中的时间戳
|
||||
* @param zone java.time 中的时区
|
||||
* @return joda-time 中带时区的日期时间
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.Instant instant,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toZonedDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
|
||||
*
|
||||
* @param dateTime joda-time 中带时区的日期时间
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(org.joda.time.DateTime dateTime) {
|
||||
java.time.ZoneId zone = dateTime.getZone().toTimeZone().toZoneId();
|
||||
return toJavaInstant(dateTime.toInstant()).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 和
|
||||
* {@link org.joda.time.DateTimeZone}
|
||||
* 转换为 java.time 中的 {@link java.time.ZonedDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time 中的地区时间
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(localDateTime, dateTimeZone).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 joda-time 中的 {@link org.joda.time.Instant} 在指定时区的时间,用 Java 8+ 的
|
||||
* {@link java.time.ZonedDateTime} 表示
|
||||
*
|
||||
* @param instant joda-time 中的时间戳
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.Instant instant,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(instant).atZone(zone);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJodaLocalDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime Java 8 LocalDateTime
|
||||
* @return joda-time LocalDateTime
|
||||
*/
|
||||
public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) {
|
||||
java.time.ZoneId javaZone = java.time.ZoneId.systemDefault();
|
||||
org.joda.time.DateTimeZone jodaZone = toJodaZone(javaZone);
|
||||
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJavaLocalDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time LocalDateTime
|
||||
* @return Java 8 LocalDateTime
|
||||
*/
|
||||
public static java.time.LocalDateTime toJavaLocalDateTime(org.joda.time.LocalDateTime localDateTime) {
|
||||
org.joda.time.DateTimeZone jodaZone = org.joda.time.DateTimeZone.getDefault();
|
||||
java.time.ZoneId javaZone = toJavaZone(jodaZone);
|
||||
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - ZoneId <--> DateTimeZone
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param jodaZone joda-time API 中表示时区的对象
|
||||
* @return Java API 中表示时区的对象
|
||||
*/
|
||||
public static java.time.ZoneId toJavaZone(org.joda.time.DateTimeZone jodaZone) {
|
||||
return jodaZone.toTimeZone().toZoneId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param zone Java API 中表示时区的对象
|
||||
* @return joda-time API 中表示时区的对象
|
||||
*/
|
||||
public static org.joda.time.DateTimeZone toJodaZone(java.time.ZoneId zone) {
|
||||
return org.joda.time.DateTimeZone.forID(zone.getId());
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - YearQuarter & Quarter
|
||||
// ================================
|
@@ -16,6 +16,9 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkCondition;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -23,7 +26,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* 枚举工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public final class EnumTools {
|
||||
|
||||
@@ -43,7 +46,7 @@ public final class EnumTools {
|
||||
@Deprecated
|
||||
private static <E extends Enum<?>> E valueOfInternal(Class<E> enumType, int ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
E[] values = enumType.getEnumConstants();
|
||||
AssertTools.checkCondition((ordinal >= 0 && ordinal < values.length),
|
||||
checkCondition((ordinal >= 0 && ordinal < values.length),
|
||||
() -> new EnumConstantNotPresentException(enumType, Integer.toString(ordinal)));
|
||||
return values[ordinal];
|
||||
}
|
||||
@@ -59,7 +62,7 @@ public final class EnumTools {
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> enumType, int ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
AssertTools.checkNotNull(enumType, "Enum type must not be null.");
|
||||
checkNotNull(enumType, "Enum type must not be null.");
|
||||
return valueOfInternal(enumType, ordinal);
|
||||
}
|
||||
|
||||
@@ -76,7 +79,7 @@ public final class EnumTools {
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> enumType, // NOSONAR 该方法弃用,但不删掉
|
||||
@Nullable Integer ordinal, @Nullable E defaultValue) {
|
||||
AssertTools.checkNotNull(enumType);
|
||||
checkNotNull(enumType);
|
||||
return null == ordinal ? defaultValue : valueOfInternal(enumType, ordinal);
|
||||
}
|
||||
|
||||
@@ -95,8 +98,8 @@ public final class EnumTools {
|
||||
Class<E> enumType,
|
||||
@Nullable Integer ordinal,
|
||||
Supplier<E> defaultValue) {
|
||||
AssertTools.checkNotNull(enumType);
|
||||
AssertTools.checkNotNull(defaultValue);
|
||||
checkNotNull(enumType);
|
||||
checkNotNull(defaultValue);
|
||||
return null == ordinal ? defaultValue.get() : valueOfInternal(enumType, ordinal);
|
||||
}
|
||||
|
||||
@@ -112,7 +115,7 @@ public final class EnumTools {
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E getValueOrDefault(Class<E> enumType, @Nullable Integer ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
return getValueOrDefault(enumType, ordinal, () -> {
|
||||
AssertTools.checkNotNull(enumType, "Enum type must not be null.");
|
||||
checkNotNull(enumType, "Enum type must not be null.");
|
||||
E[] values = enumType.getEnumConstants();
|
||||
return values[0];
|
||||
});
|
||||
@@ -133,10 +136,10 @@ public final class EnumTools {
|
||||
}
|
||||
|
||||
public static <E extends Enum<?>> Integer checkOrdinal(Class<E> enumType, Integer ordinal) {
|
||||
AssertTools.checkNotNull(enumType, "Enum type must not be null.");
|
||||
AssertTools.checkNotNull(ordinal, "Ordinal must not be null.");
|
||||
checkNotNull(enumType, "Enum type must not be null.");
|
||||
checkNotNull(ordinal, "Ordinal must not be null.");
|
||||
E[] values = enumType.getEnumConstants();
|
||||
AssertTools.checkCondition(ordinal >= 0 && ordinal < values.length,
|
||||
checkCondition(ordinal >= 0 && ordinal < values.length,
|
||||
() -> new EnumConstantNotPresentException(enumType, Integer.toString(ordinal)));
|
||||
return ordinal;
|
||||
}
|
||||
@@ -180,7 +183,7 @@ public final class EnumTools {
|
||||
Class<E> enumType,
|
||||
@Nullable Integer ordinal,
|
||||
@Nullable Integer defaultValue) {
|
||||
AssertTools.checkNotNull(enumType);
|
||||
checkNotNull(enumType);
|
||||
return checkOrdinalOrGetInternal(enumType, ordinal, () -> checkOrdinalOrDefaultInternal(enumType, defaultValue, null));
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -33,7 +35,8 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
*
|
||||
* 参考 <a href="https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/">Enumeration classes</a>
|
||||
*
|
||||
* @deprecated 设计 Enumeration 的灵感来自于 .net 社区,因为 C# 的枚举不带行为。
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @deprecated 设计 Enumeration 的灵感来自于 .net 社区,因为 C# 的枚举不带行为。
|
||||
* 但 Java 的枚举可以带行为,故大多数情况下不需要这种设计。
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -43,7 +46,7 @@ public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移
|
||||
protected final String name;
|
||||
|
||||
protected Enumeration(final int id, final String name) {
|
||||
AssertTools.checkArgument(StringTools.isNotBlank(name), "Name of enumeration must has text.");
|
||||
checkArgument(StringTools.isNotBlank(name), "Name of enumeration must has text.");
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
@@ -125,7 +128,7 @@ public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移
|
||||
* @return 枚举对象
|
||||
*/
|
||||
public T get(int id) {
|
||||
AssertTools.checkArgument(this.valueMap.containsKey(id), "[%s] 对应的值不存在", id);
|
||||
checkArgument(this.valueMap.containsKey(id), "[%s] 对应的值不存在", id);
|
||||
return this.valueMap.get(id);
|
||||
}
|
||||
|
@@ -16,8 +16,9 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -26,11 +27,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*
|
||||
* <p>
|
||||
* 生成 UUID 和 修改版雪花ID(Seata 版本)
|
||||
* </p>
|
||||
*
|
||||
* @see UUID
|
||||
* @see IdWorker
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class IdGenerator {
|
||||
|
||||
@@ -70,7 +70,7 @@ public class IdGenerator {
|
||||
* @return UUID 字符串
|
||||
*/
|
||||
public static String toSimpleString(UUID uuid) {
|
||||
AssertTools.checkArgument(Objects.nonNull(uuid));
|
||||
checkArgumentNotNull(uuid);
|
||||
return (uuidDigits(uuid.getMostSignificantBits() >> 32, 8) +
|
||||
uuidDigits(uuid.getMostSignificantBits() >> 16, 4) +
|
||||
uuidDigits(uuid.getMostSignificantBits(), 4) +
|
@@ -34,7 +34,7 @@ import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
||||
* <li>每个机器线程安全地生成序列,前面加上机器的id,这样就不会与其它机器的id相冲突。</li>
|
||||
* <li>时间戳作为序列的“预留位”,它更像是应用启动时最开始的序列的一部分,在一个时间戳里生成 4096 个 id 之后,直接生成下一个时间戳的 id。</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 详情见以下介绍:
|
||||
* <ul>
|
||||
@@ -43,7 +43,7 @@ import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
||||
* <li><a href="https://juejin.cn/post/7264387737276203065">在开源项目中看到一个改良版的雪花算法,现在它是你的了。</a></li>
|
||||
* <li><a href="https://juejin.cn/post/7265516484029743138">关于若干读者,阅读“改良版雪花算法”后提出的几个共性问题的回复。</a></li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class IdWorker {
|
||||
|
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Joda-Time 工具类
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class JodaTimeTools {
|
||||
|
||||
// ================================
|
||||
// #region - toJodaInstant
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param instant {@link java.time.Instant} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.Instant instant) {
|
||||
return new org.joda.time.Instant(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.ZonedDateTime} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param zonedDateTime {@link java.time.ZonedDateTime} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.ZonedDateTime zonedDateTime) {
|
||||
return toJodaInstant(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定时区的地区时间,对应的时间戳。结果为 {@link org.joda.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime {@link java.time.LocalDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.LocalDateTime localDateTime, java.time.ZoneId zone) {
|
||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJavaInstant
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param instant {@link org.joda.time.Instant} 对象
|
||||
* @return {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.Instant instant) {
|
||||
return DateTimeTools.toInstant(instant.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.DateTime} 对象转换为 Java 的
|
||||
* {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param dateTime joda-time 中表示日期时间的 {@link org.joda.time.DateTime} 对象
|
||||
* @return Java 表示时间戳的 {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.DateTime dateTime) {
|
||||
return DateTimeTools.toInstant(dateTime.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 对象和
|
||||
* {@link org.joda.time.DateTimeZone} 对象
|
||||
* 转换为 Java 中的 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime
|
||||
* @param zone
|
||||
* @return
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone zone) {
|
||||
return toJavaInstant(localDateTime.toDateTime(zone));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJodaDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
|
||||
* 转换为 joda-time 的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param zonedDateTime 日期时间
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(java.time.ZonedDateTime zonedDateTime) {
|
||||
org.joda.time.DateTimeZone zone = org.joda.time.DateTimeZone.forID(zonedDateTime.getZone().getId());
|
||||
return toJodaInstant(zonedDateTime.toInstant()).toDateTime(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 java.time 中表示日期时间的 {@link java.time.LocalDateTime} 对象和表示时区的
|
||||
* {@link java.time.ZoneId} 对象转换为 joda-time 中对应的 {@link org.joda.time.DateTime}
|
||||
* 对象
|
||||
* 转换为 joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param zone 时区
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.LocalDateTime localDateTime,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone).toInstant()).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算时间戳在指定时区对应的时间,结果使用 {@link org.joda.time.DateTime} 表示
|
||||
*
|
||||
* @param instant java.time 中的时间戳
|
||||
* @param zone java.time 中的时区
|
||||
* @return joda-time 中带时区的日期时间
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.Instant instant,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toZonedDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
|
||||
*
|
||||
* @param dateTime joda-time 中带时区的日期时间
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(org.joda.time.DateTime dateTime) {
|
||||
java.time.ZoneId zone = dateTime.getZone().toTimeZone().toZoneId();
|
||||
return toJavaInstant(dateTime.toInstant()).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 和
|
||||
* {@link org.joda.time.DateTimeZone}
|
||||
* 转换为 java.time 中的 {@link java.time.ZonedDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time 中的地区时间
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(localDateTime, dateTimeZone).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 joda-time 中的 {@link org.joda.time.Instant} 在指定时区的时间,用 Java 8+ 的
|
||||
* {@link java.time.ZonedDateTime} 表示
|
||||
*
|
||||
* @param instant joda-time 中的时间戳
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.Instant instant,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(instant).atZone(zone);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJodaLocalDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime Java 8 LocalDateTime
|
||||
* @return joda-time LocalDateTime
|
||||
*/
|
||||
public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) {
|
||||
java.time.ZoneId javaZone = java.time.ZoneId.systemDefault();
|
||||
org.joda.time.DateTimeZone jodaZone = toJodaZone(javaZone);
|
||||
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - toJavaLocalDateTime
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time LocalDateTime
|
||||
* @return Java 8 LocalDateTime
|
||||
*/
|
||||
public static java.time.LocalDateTime toJavaLocalDateTime(org.joda.time.LocalDateTime localDateTime) {
|
||||
org.joda.time.DateTimeZone jodaZone = org.joda.time.DateTimeZone.getDefault();
|
||||
java.time.ZoneId javaZone = toJavaZone(jodaZone);
|
||||
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - ZoneId <--> DateTimeZone
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param jodaZone joda-time API 中表示时区的对象
|
||||
* @return Java API 中表示时区的对象
|
||||
*/
|
||||
public static java.time.ZoneId toJavaZone(org.joda.time.DateTimeZone jodaZone) {
|
||||
return jodaZone.toTimeZone().toZoneId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param zone Java API 中表示时区的对象
|
||||
* @return joda-time API 中表示时区的对象
|
||||
*/
|
||||
public static org.joda.time.DateTimeZone toJodaZone(java.time.ZoneId zone) {
|
||||
return org.joda.time.DateTimeZone.forID(zone.getId());
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 私有构造方法
|
||||
*/
|
||||
private JodaTimeTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* 数字工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public class Numbers {
|
||||
|
||||
@@ -108,7 +108,7 @@ public class Numbers {
|
||||
* @return 求和结果
|
||||
*/
|
||||
public static BigInteger sum(final BigInteger... numbers) {
|
||||
if (ArrayTools.isNullOrEmpty(numbers)) {
|
||||
if (ArrayTools.isEmpty(numbers)) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
BigInteger result = Numbers.nullToZero(numbers[0]);
|
@@ -31,7 +31,7 @@ import com.google.common.annotations.Beta;
|
||||
* <p>
|
||||
* 提供一些 Optional 相关的方法
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
* @see Optional
|
||||
* @see OptionalInt
|
||||
@@ -45,7 +45,6 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalInt} 后,由
|
||||
* {@link OptionalInt#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalInt} 实例
|
||||
@@ -58,7 +57,6 @@ public class OptionalTools {
|
||||
* 将 {@code Optional<Integer>} 对象转为 {@link OptionalInt} 对象。
|
||||
* <p>
|
||||
* {@code Optional<Integer>} 将整数包装了两次,改为使用 {@link OptionalInt} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
* @param optionalObj {@code Optional<Integer>} 对象
|
||||
* @return {@link OptionalInt} 实例
|
||||
@@ -72,7 +70,6 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalLong} 后,由
|
||||
* {@link OptionalLong#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalLong} 实例
|
||||
@@ -85,7 +82,6 @@ public class OptionalTools {
|
||||
* 将 {@code Optional<Long>} 转为 {@link OptionalLong}。
|
||||
* <p>
|
||||
* {@code Optional<Long>} 将整数包装了两次,改为使用 {@link OptionalLong} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
* @param optionalObj 包装对象
|
||||
* @return {@link OptionalLong} 实例
|
||||
@@ -99,7 +95,6 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalDouble} 后,由
|
||||
* {@link OptionalDouble#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalDouble} 实例
|
||||
@@ -112,7 +107,6 @@ public class OptionalTools {
|
||||
* 将 {@code Optional<Double>} 转为 {@link OptionalDouble}。
|
||||
* <p>
|
||||
* {@code Optional<Double>} 将整数包装了两次,改为使用 {@link OptionalDouble} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
* @param optionalObj 包装对象
|
||||
* @return {@link OptionalDouble} 实例
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Objects;
|
||||
@@ -26,8 +28,8 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
* 随机工具类
|
||||
* <p>
|
||||
* 建议调用方自行维护 Random 对象
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public final class RandomTools {
|
||||
|
||||
@@ -67,21 +69,21 @@ public final class RandomTools {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomStr(Random random, char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(random, sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String randomStr(char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String secureRandomStr(char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||
}
|
||||
|
||||
@@ -96,21 +98,21 @@ public final class RandomTools {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomStr(Random random, String sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(random, sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String randomStr(String sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String secureRandomStr(String sourceCharacters, int length) {
|
||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
checkArgument(Objects.nonNull(sourceCharacters), "Source characters cannot be null.");
|
||||
checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||
}
|
||||
|
@@ -16,27 +16,44 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
/**
|
||||
* 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存大概 256 个)。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用。
|
||||
*
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
public final class RegexTools {
|
||||
|
||||
private static final int DEFAULT_CACHE_INITIAL_CAPACITY = 64;
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
private static final Map<String, Pattern> PATTERN_CACHE
|
||||
= new ConcurrentHashMap<>(DEFAULT_CACHE_INITIAL_CAPACITY);
|
||||
private static final int DEFAULT_FLAG = 0;
|
||||
private static final LoadingCache<RegexAndFlags, Pattern> PATTERN_CACHE = CacheBuilder
|
||||
.newBuilder()
|
||||
.maximumSize(MAX_CACHE_SIZE)
|
||||
.build(new CacheLoader<RegexAndFlags, Pattern>() {
|
||||
@SuppressWarnings("null")
|
||||
public Pattern load(@Nonnull RegexAndFlags regexAndFlags) {
|
||||
return regexAndFlags.compilePattern();
|
||||
}
|
||||
});
|
||||
|
||||
// ================================
|
||||
// #region - getPattern
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例。
|
||||
@@ -46,8 +63,20 @@ public final class RegexTools {
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern getPattern(final String pattern, final boolean cachePattern) {
|
||||
AssertTools.checkNotNull(pattern);
|
||||
return cachePattern ? cacheAndGetPatternInternal(pattern) : getPatternInternal(pattern);
|
||||
return getPattern(pattern, DEFAULT_FLAG, cachePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例。
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern getPattern(final String pattern, final int flags, final boolean cachePattern) {
|
||||
checkNotNull(pattern);
|
||||
return cachePattern ? cacheAndGetPatternInternal(pattern, flags) : getPatternInternal(pattern, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,34 +86,29 @@ public final class RegexTools {
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern getPattern(final String pattern) {
|
||||
AssertTools.checkNotNull(pattern);
|
||||
return getPatternInternal(pattern);
|
||||
return getPattern(pattern, DEFAULT_FLAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
* 获取 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return {@link Pattern} 实例数组
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern[] getPatterns(final String[] patterns, final boolean cachePattern) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
return cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
@Nonnull
|
||||
public static Pattern getPattern(final String pattern, final int flags) {
|
||||
checkNotNull(pattern);
|
||||
return getPatternInternal(pattern, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
public static Pattern[] getPatterns(final String[] patterns) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
return getPatternsInternal(patterns);
|
||||
}
|
||||
// ================================
|
||||
// #endregion - getPattern
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - matches
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。
|
||||
@@ -94,7 +118,7 @@ public final class RegexTools {
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final Pattern pattern) {
|
||||
AssertTools.checkNotNull(pattern);
|
||||
checkNotNull(pattern);
|
||||
return matchesInternal(input, pattern);
|
||||
}
|
||||
|
||||
@@ -105,9 +129,9 @@ public final class RegexTools {
|
||||
* @param patterns 正则
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
return matchesOneInternal(input, patterns);
|
||||
public static boolean matchesAny(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
return matchesAnyInternal(input, patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +142,7 @@ public final class RegexTools {
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
return matchesAllInternal(input, patterns);
|
||||
}
|
||||
|
||||
@@ -132,11 +156,21 @@ public final class RegexTools {
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final String pattern,
|
||||
final boolean cachePattern) {
|
||||
AssertTools.checkNotNull(pattern);
|
||||
Pattern p = cachePattern
|
||||
? cacheAndGetPatternInternal(pattern)
|
||||
: getPatternInternal(pattern);
|
||||
return matchesInternal(input, p);
|
||||
return matches(input, pattern, DEFAULT_FLAG, cachePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final String pattern, final int flags,
|
||||
final boolean cachePattern) {
|
||||
return matchesInternal(input, getPattern(pattern, flags, cachePattern));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,69 +181,29 @@ public final class RegexTools {
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final String pattern) {
|
||||
AssertTools.checkNotNull(pattern);
|
||||
return matchesInternal(input, getPatternInternal(pattern));
|
||||
return matches(input, pattern, DEFAULT_FLAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code patterns} 中的一个。
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns,
|
||||
final boolean cachePattern) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
final Pattern[] patternSet = cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
return matchesOneInternal(input, patternSet);
|
||||
public static boolean matches(@Nullable final CharSequence input,
|
||||
final String pattern, final int flags) {
|
||||
return matchesInternal(input, getPattern(pattern, flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code patterns} 中的一个。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
final Pattern[] patternSet = getPatternsInternal(patterns);
|
||||
return matchesOneInternal(input, patternSet);
|
||||
}
|
||||
// ================================
|
||||
// #endregion - matches
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配全部正则。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns,
|
||||
final boolean cachePattern) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
final Pattern[] patternSet = cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
return matchesAllInternal(input, patternSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配全部正则。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns) {
|
||||
AssertTools.checkArgument(ArrayTools.isAllElementsNotNull(patterns));
|
||||
final Pattern[] patternSet = getPatternsInternal(patterns);
|
||||
return matchesAllInternal(input, patternSet);
|
||||
}
|
||||
// ================================
|
||||
// #region - getMatcher
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 生成 Matcher。
|
||||
@@ -219,8 +213,8 @@ public final class RegexTools {
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final Pattern pattern) {
|
||||
AssertTools.checkNotNull(input);
|
||||
AssertTools.checkNotNull(pattern);
|
||||
checkNotNull(input);
|
||||
checkNotNull(pattern);
|
||||
return pattern.matcher(input);
|
||||
}
|
||||
|
||||
@@ -233,12 +227,21 @@ public final class RegexTools {
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final String pattern, boolean cachePattern) {
|
||||
AssertTools.checkNotNull(input);
|
||||
AssertTools.checkNotNull(pattern);
|
||||
final Pattern p = cachePattern
|
||||
? cacheAndGetPatternInternal(pattern)
|
||||
: getPatternInternal(pattern);
|
||||
return p.matcher(input);
|
||||
return getMatcher(input, pattern, DEFAULT_FLAG, cachePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Matcher。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input,
|
||||
final String pattern, final int flags, boolean cachePattern) {
|
||||
return getMatcher(input, getPattern(pattern, flags, cachePattern));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,70 +252,56 @@ public final class RegexTools {
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final String pattern) {
|
||||
AssertTools.checkNotNull(input);
|
||||
AssertTools.checkNotNull(pattern);
|
||||
return getPatternInternal(pattern).matcher(input);
|
||||
return getMatcher(input, pattern, DEFAULT_FLAG);
|
||||
}
|
||||
|
||||
// ========== internal methods ==========
|
||||
/**
|
||||
* 生成 Matcher。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final String pattern, final int flags) {
|
||||
checkNotNull(input);
|
||||
checkNotNull(pattern);
|
||||
return getPatternInternal(pattern, flags).matcher(input);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - getMatcher
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - internal methods
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例。
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
@Nonnull
|
||||
private static Pattern cacheAndGetPatternInternal(final String pattern) {
|
||||
if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) {
|
||||
return PATTERN_CACHE.computeIfAbsent(pattern, Pattern::compile);
|
||||
}
|
||||
Pattern result = PATTERN_CACHE.get(pattern);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return Pattern.compile(pattern);
|
||||
private static Pattern cacheAndGetPatternInternal(final String pattern, final int flags) {
|
||||
final RegexAndFlags regexAndFlags = new RegexAndFlags(pattern, flags);
|
||||
return PATTERN_CACHE.getUnchecked(regexAndFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param flags 正则表达式匹配标识
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
@Nonnull
|
||||
private static Pattern getPatternInternal(final String pattern) {
|
||||
Pattern result = PATTERN_CACHE.get(pattern);
|
||||
if (result == null) {
|
||||
result = Pattern.compile(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
@Nonnull
|
||||
private static Pattern[] cacheAndGetPatternsInternal(final String[] patterns) {
|
||||
return Arrays.stream(patterns)
|
||||
.map(RegexTools::cacheAndGetPatternInternal)
|
||||
.toArray(Pattern[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
@Nonnull
|
||||
private static Pattern[] getPatternsInternal(final String[] patterns) {
|
||||
return Arrays.stream(patterns)
|
||||
.map(RegexTools::getPatternInternal)
|
||||
.toArray(Pattern[]::new);
|
||||
private static Pattern getPatternInternal(final String pattern, final int flags) {
|
||||
final RegexAndFlags regexAndFlags = new RegexAndFlags(pattern, flags);
|
||||
return Optional.ofNullable(PATTERN_CACHE.getIfPresent(regexAndFlags))
|
||||
.orElseGet(regexAndFlags::compilePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,7 +322,7 @@ public final class RegexTools {
|
||||
* @param patterns 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
private static boolean matchesOneInternal(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
private static boolean matchesAnyInternal(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
return input != null
|
||||
&& Arrays.stream(patterns)
|
||||
.anyMatch(pattern -> pattern.matcher(input).matches());
|
||||
@@ -352,8 +341,49 @@ public final class RegexTools {
|
||||
.allMatch(pattern -> pattern.matcher(input).matches());
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - internal methods
|
||||
// ================================
|
||||
|
||||
private RegexTools() {
|
||||
// 不允许实例化
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #region - RegexAndFlags
|
||||
// ================================
|
||||
|
||||
private static final class RegexAndFlags {
|
||||
private final String regex;
|
||||
private final int flags;
|
||||
|
||||
private RegexAndFlags(String regex, int flags) {
|
||||
this.regex = regex;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
private final Pattern compilePattern() {
|
||||
return Pattern.compile(regex, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(regex, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!(obj instanceof RegexAndFlags))
|
||||
return false;
|
||||
RegexAndFlags other = (RegexAndFlags) obj;
|
||||
return Objects.equals(regex, other.regex) && flags == other.flags;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - RegexAndFlags
|
||||
// ================================
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -73,9 +75,9 @@ public class SnowflakeIdGenerator {
|
||||
* @param datacenterId 数据中心ID (0~31)
|
||||
*/
|
||||
public SnowflakeIdGenerator(final long workerId, final long datacenterId) {
|
||||
AssertTools.checkArgument((workerId <= MAX_WORKER_ID && workerId >= 0),
|
||||
checkArgument((workerId <= MAX_WORKER_ID && workerId >= 0),
|
||||
"WorkerId can't be greater than %s or less than 0.", MAX_WORKER_ID);
|
||||
AssertTools.checkArgument((datacenterId <= MAX_DATACENTER_ID && datacenterId >= 0),
|
||||
checkArgument((datacenterId <= MAX_DATACENTER_ID && datacenterId >= 0),
|
||||
"DatacenterId can't be greater than %s or less than 0.", MAX_DATACENTER_ID);
|
||||
this.datacenterIdAndWorkerId
|
||||
= (datacenterId << DATACENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT);
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgument;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
@@ -31,9 +33,8 @@ import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||
*
|
||||
* <p>
|
||||
* 字符串工具类。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class StringTools {
|
||||
@@ -111,7 +112,7 @@ public class StringTools {
|
||||
* @return 结果
|
||||
*/
|
||||
public static String repeat(final String str, int times, int maxLength) {
|
||||
AssertTools.checkArgument(Objects.nonNull(str));
|
||||
checkArgument(Objects.nonNull(str));
|
||||
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
||||
}
|
||||
|
||||
@@ -211,8 +212,8 @@ public class StringTools {
|
||||
if (src == null || src.isEmpty()) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
AssertTools.checkArgument(front >= 0 && end >= 0);
|
||||
AssertTools.checkArgument((front + end) <= src.length(), "需要截取的长度不能大于原字符串长度");
|
||||
checkArgument(front >= 0 && end >= 0);
|
||||
checkArgument((front + end) <= src.length(), "需要截取的长度不能大于原字符串长度");
|
||||
final char[] charArray = src.toCharArray();
|
||||
for (int i = front; i < charArray.length - end; i++) {
|
||||
charArray[i] = replacedChar;
|
||||
@@ -220,6 +221,23 @@ public class StringTools {
|
||||
return String.valueOf(charArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为带引号的字符串
|
||||
*
|
||||
* @param value 值
|
||||
* @return 带引号的字符串
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static String toQuotedString(@Nullable String value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
if (value.isEmpty()) {
|
||||
return "\"\"";
|
||||
}
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
|
||||
private StringTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
@@ -30,7 +32,7 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* TreeBuilder
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class TreeBuilder<T, TSubTree extends T, TIdentity> {
|
||||
@@ -76,7 +78,7 @@ public class TreeBuilder<T, TSubTree extends T, TIdentity> {
|
||||
* @param nodes 平铺的节点列表
|
||||
*/
|
||||
public List<T> buildTree(Collection<T> nodes) {
|
||||
AssertTools.checkNotNull(nodes);
|
||||
checkNotNull(nodes);
|
||||
return buildTreeInternal(nodes, this.defaultComparator);
|
||||
}
|
||||
|
||||
@@ -93,7 +95,7 @@ public class TreeBuilder<T, TSubTree extends T, TIdentity> {
|
||||
* <b>仅影响调用 addChild 的顺序,如果操作对象本身对应的控制了子节点的顺序,无法影响其相关逻辑。</b>
|
||||
*/
|
||||
public List<T> buildTree(Collection<T> nodes, @Nullable Comparator<? super T> comparator) {
|
||||
AssertTools.checkNotNull(nodes);
|
||||
checkNotNull(nodes);
|
||||
final Comparator<? super T> c = (comparator != null) ? comparator : this.defaultComparator;
|
||||
return buildTreeInternal(nodes, c);
|
||||
}
|
@@ -18,9 +18,8 @@
|
||||
* <h2>工具类</h2>
|
||||
* <p>
|
||||
* 包含树构建器({@link TreeBuilder})、断言工具({@link AssertTools})、ID 生成器({@link IdGenerator})及其它实用工具类。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package xyz.zhouxy.plusone.commons.util;
|
@@ -17,12 +17,12 @@
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkNotNull;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
class IWithCodeTests {
|
||||
|
||||
@@ -91,7 +91,7 @@ class IWithCodeTests {
|
||||
private final String code;
|
||||
|
||||
WithCode(String code) {
|
||||
AssertTools.checkNotNull(code);
|
||||
checkNotNull(code);
|
||||
this.code = code;
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS.create();
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS.getCode(), e.getTypeCode());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS.getDefaultMessage(), e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -50,7 +49,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.create(message);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -62,7 +60,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.PICTURE_CONTAINS_ILLEGAL_INFORMATION.create(message);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.PICTURE_CONTAINS_ILLEGAL_INFORMATION, e.getType());
|
||||
assertEquals(InvalidInputException.Type.PICTURE_CONTAINS_ILLEGAL_INFORMATION.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -77,7 +74,6 @@ public class InvalidInputExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(InvalidInputException.Type.INFRINGE_COPYRIGHT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.INFRINGE_COPYRIGHT.getCode(), e.getTypeCode());
|
||||
log.info("{}", e.getMessage());
|
||||
assertEquals(nfe.toString(), e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
@@ -92,7 +88,6 @@ public class InvalidInputExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -106,7 +101,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS.create(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -120,7 +114,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.create(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -134,7 +127,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.create(message, npe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -148,7 +140,6 @@ public class InvalidInputExceptionTests {
|
||||
throw InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.create(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS, e.getType());
|
||||
assertEquals(InvalidInputException.Type.CONTAINS_ILLEGAL_WORDS.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -167,7 +158,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException();
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getDefaultMessage(), e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -179,7 +169,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -191,7 +180,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -206,7 +194,6 @@ public class InvalidInputExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
log.info("{}", e.getMessage());
|
||||
assertEquals(nfe.toString(), e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
@@ -221,7 +208,6 @@ public class InvalidInputExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -235,7 +221,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -249,7 +234,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -263,7 +247,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message, npe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -277,7 +260,6 @@ public class InvalidInputExceptionTests {
|
||||
throw new InvalidInputException(message, nfe);
|
||||
});
|
||||
assertSame(InvalidInputException.Type.DEFAULT, e.getType());
|
||||
assertEquals(InvalidInputException.Type.DEFAULT.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
@@ -41,7 +41,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.DATE_TIME_PARSING_FAILURE.create();
|
||||
});
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getDefaultMessage(), e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -53,7 +52,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.JSON_PARSING_FAILURE.create(message);
|
||||
});
|
||||
assertSame(ParsingFailureException.Type.JSON_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.Type.JSON_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -65,7 +63,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.XML_PARSING_FAILURE.create(message);
|
||||
});
|
||||
assertSame(ParsingFailureException.XML_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.XML_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -80,7 +77,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
log.info("{}", e.getMessage());
|
||||
assertEquals(nfe.toString(), e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
@@ -95,7 +91,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -109,7 +104,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.NUMBER_PARSING_FAILURE.create(message, nfe);
|
||||
});
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -123,7 +117,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.DATE_TIME_PARSING_FAILURE.create(message, nfe);
|
||||
});
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertSame(nfe, e.getCause());
|
||||
}
|
||||
@@ -137,7 +130,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.DATE_TIME_PARSING_FAILURE.create(message, npe);
|
||||
});
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -151,7 +143,6 @@ public class ParsingFailureExceptionTests {
|
||||
throw ParsingFailureException.DATE_TIME_PARSING_FAILURE.create(message, nfe);
|
||||
});
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -175,7 +166,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(dtpe.getMessage(), e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -189,7 +179,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getDefaultMessage(), e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -206,7 +195,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -223,7 +211,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -238,7 +225,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -253,7 +239,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.DATE_TIME_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.DATE_TIME_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -277,7 +262,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(dtpe.getMessage(), e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -291,7 +275,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getDefaultMessage(), e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -308,7 +291,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -325,7 +307,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertSame(dtpe, e.getCause());
|
||||
}
|
||||
@@ -340,7 +321,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertEquals(message, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
@@ -355,7 +335,6 @@ public class ParsingFailureExceptionTests {
|
||||
});
|
||||
|
||||
assertSame(ParsingFailureException.NUMBER_PARSING_FAILURE, e.getType());
|
||||
assertEquals(ParsingFailureException.NUMBER_PARSING_FAILURE.getCode(), e.getTypeCode());
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.gson.adapter;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.temporal.ChronoField;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.commons.gson.adapter.JSR310TypeAdapters.*;
|
||||
|
||||
@Slf4j
|
||||
public final class JSR310TypeAdaptersTests {
|
||||
|
||||
final Gson gsonWithDefaultFormatter = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter().nullSafe())
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter().nullSafe())
|
||||
.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter().nullSafe())
|
||||
.registerTypeAdapter(Instant.class, new InstantTypeAdapter().nullSafe())
|
||||
.create();
|
||||
|
||||
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
||||
final DateTimeFormatter localDateTimeFormatter = new DateTimeFormatterBuilder()
|
||||
.appendPattern("yyyy/MM/dd HH:mm:ss")
|
||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||
.toFormatter();
|
||||
final DateTimeFormatter zonedDateTimeFormatter = new DateTimeFormatterBuilder()
|
||||
.appendPattern("yyyy/MM/dd HH:mm:ss")
|
||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||
.appendZoneId()
|
||||
.toFormatter();
|
||||
final Gson gsonWithSpecifiedFormatter = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter(dateFormatter).nullSafe())
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter(localDateTimeFormatter).nullSafe())
|
||||
.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter(zonedDateTimeFormatter).nullSafe())
|
||||
.create();
|
||||
|
||||
final LocalDate date = LocalDate.of(2025, 6, 6);
|
||||
final LocalDateTime localDateTime = date.atTime(6, 6, 6, 666000000);
|
||||
final ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("+08:00"));
|
||||
final Instant instant = zonedDateTime.toInstant();
|
||||
|
||||
@DisplayName("测试使用 TypeAdapter 中默认的 formatter 进行序列化")
|
||||
@Test
|
||||
void test_serialize_defaultFormatter() {
|
||||
Foo foo = new Foo();
|
||||
foo.localDate = date;
|
||||
foo.localDateTime = localDateTime;
|
||||
foo.zonedDateTime = zonedDateTime;
|
||||
foo.instant = instant;
|
||||
|
||||
String json = String.format(
|
||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\",\"instant\":\"%s\"}",
|
||||
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
||||
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime),
|
||||
DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||
);
|
||||
|
||||
assertEquals(json, gsonWithDefaultFormatter.toJson(foo));
|
||||
}
|
||||
|
||||
@DisplayName("测试指定 formatter 进行序列化")
|
||||
@Test
|
||||
void test_serialize_specifiedFormatter() {
|
||||
Foo foo = new Foo();
|
||||
foo.localDate = date;
|
||||
foo.localDateTime = localDateTime;
|
||||
foo.zonedDateTime = zonedDateTime;
|
||||
|
||||
String json = String.format(
|
||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\"}",
|
||||
dateFormatter.format(date),
|
||||
localDateTimeFormatter.format(localDateTime),
|
||||
zonedDateTimeFormatter.format(zonedDateTime)
|
||||
);
|
||||
|
||||
assertEquals(json, gsonWithSpecifiedFormatter.toJson(foo));
|
||||
}
|
||||
|
||||
@DisplayName("测试使用 TypeAdapter 中默认的 formatter 进行反序列化")
|
||||
@Test
|
||||
void test_deserialize_defaultFormatter() {
|
||||
String json = String.format(
|
||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\",\"instant\":\"%s\"}",
|
||||
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
||||
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime),
|
||||
DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||
);
|
||||
Foo foo = gsonWithDefaultFormatter.fromJson(json, Foo.class);
|
||||
assertEquals(date, foo.localDate);
|
||||
assertEquals(localDateTime, foo.localDateTime);
|
||||
assertEquals(zonedDateTime, foo.zonedDateTime);
|
||||
assertEquals(instant, foo.instant);
|
||||
}
|
||||
|
||||
@DisplayName("测试指定 formatter 进行反序列化")
|
||||
@Test
|
||||
void test_deserialize_specifiedFormatter() {
|
||||
String json = String.format(
|
||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\"}",
|
||||
dateFormatter.format(date),
|
||||
localDateTimeFormatter.format(localDateTime),
|
||||
zonedDateTimeFormatter.format(zonedDateTime)
|
||||
);
|
||||
Foo foo = gsonWithSpecifiedFormatter.fromJson(json, Foo.class);
|
||||
assertEquals(date, foo.localDate);
|
||||
assertEquals(localDateTime, foo.localDateTime);
|
||||
assertEquals(zonedDateTime, foo.zonedDateTime);
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
LocalDate localDate;
|
||||
LocalDateTime localDateTime;
|
||||
ZonedDateTime zonedDateTime;
|
||||
Instant instant;
|
||||
}
|
||||
}
|
@@ -558,11 +558,11 @@ class CustomUnifiedResponseFactoryTests {
|
||||
public static final String SUCCESS_CODE = "0000000";
|
||||
public static final String DEFAULT_SUCCESS_MSG = "成功";
|
||||
|
||||
public static UnifiedResponse<Void> success() {
|
||||
public static <T> UnifiedResponse<T> success() {
|
||||
return of(SUCCESS_CODE, DEFAULT_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
public static UnifiedResponse<Void> success(@Nullable String message) {
|
||||
public static <T> UnifiedResponse<T> success(@Nullable String message) {
|
||||
return of(SUCCESS_CODE, message);
|
||||
}
|
||||
|
@@ -19,14 +19,12 @@ package xyz.zhouxy.plusone.commons.model.dto.test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Statement;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -45,9 +43,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -57,6 +52,9 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.gson.adapter.JSR310TypeAdapters.LocalDateTimeTypeAdapter;
|
||||
import xyz.zhouxy.plusone.commons.gson.adapter.JSR310TypeAdapters.LocalDateTypeAdapter;
|
||||
import xyz.zhouxy.plusone.commons.model.dto.PageResult;
|
||||
import xyz.zhouxy.plusone.commons.model.dto.PagingAndSortingQueryParams;
|
||||
import xyz.zhouxy.plusone.commons.model.dto.PagingParams;
|
||||
@@ -187,31 +185,8 @@ public class PagingAndSortingQueryParamsTests {
|
||||
@Test
|
||||
void testGson() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDate.class, new TypeAdapter<LocalDate>() {
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, LocalDate value) throws IOException {
|
||||
out.value(DateTimeFormatter.ISO_DATE.format(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate read(JsonReader in) throws IOException {
|
||||
return LocalDate.parse(in.nextString(), DateTimeFormatter.ISO_DATE);
|
||||
}
|
||||
|
||||
})
|
||||
.registerTypeAdapter(LocalDateTime.class, new TypeAdapter<LocalDateTime>() {
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, LocalDateTime value) throws IOException {
|
||||
out.value(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime read(JsonReader in) throws IOException {
|
||||
return LocalDateTime.parse(in.nextString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
}
|
||||
})
|
||||
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter().nullSafe())
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter().nullSafe())
|
||||
.create();
|
||||
try (SqlSession session = sqlSessionFactory.openSession()) {
|
||||
AccountQueryParams params = gson.fromJson(JSON_STR, AccountQueryParams.class);
|
||||
@@ -245,7 +220,7 @@ public class PagingAndSortingQueryParamsTests {
|
||||
/**
|
||||
* 账号信息查询参数
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY108 <luquanlion@outlook.com>
|
||||
*/
|
||||
@ToString(callSuper = true)
|
||||
class AccountQueryParams extends PagingAndSortingQueryParams {
|
@@ -57,53 +57,53 @@ public class ArrayToolsTests {
|
||||
static final double[] EMPTY_DOUBLE_ARRAY = {};
|
||||
|
||||
// ================================
|
||||
// #region - isNullOrEmpty
|
||||
// #region - isEmpty
|
||||
// ================================
|
||||
|
||||
@Test
|
||||
void isNullOrEmpty_NullArray_ReturnsTrue() {
|
||||
void isEmpty_NullArray_ReturnsTrue() {
|
||||
assertAll(
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_STRING_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_INTEGER_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_CHAR_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_BYTE_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_SHORT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_INT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_LONG_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_FLOAT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(NULL_DOUBLE_ARRAY)));
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_STRING_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_INTEGER_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_CHAR_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_BYTE_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_SHORT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_INT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_LONG_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_FLOAT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(NULL_DOUBLE_ARRAY)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNullOrEmpty_EmptyArray_ReturnsTrue() {
|
||||
void isEmpty_EmptyArray_ReturnsTrue() {
|
||||
assertAll(
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_STRING_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_INTEGER_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_CHAR_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_BYTE_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_SHORT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_INT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_LONG_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_FLOAT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isNullOrEmpty(EMPTY_DOUBLE_ARRAY)));
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_STRING_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_INTEGER_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_CHAR_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_BYTE_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_SHORT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_INT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_LONG_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_FLOAT_ARRAY)),
|
||||
() -> assertTrue(ArrayTools.isEmpty(EMPTY_DOUBLE_ARRAY)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNullOrEmpty_NonEmptyArray_ReturnsFalse() {
|
||||
void isEmpty_NonEmptyArray_ReturnsFalse() {
|
||||
assertAll(
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new String[] { "a" })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new Integer[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new char[] { 'a' })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new byte[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new short[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new int[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new long[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new float[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isNullOrEmpty(new double[] { 1 })));
|
||||
() -> assertFalse(ArrayTools.isEmpty(new String[] { "a" })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new Integer[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new char[] { 'a' })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new byte[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new short[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new int[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new long[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new float[] { 1 })),
|
||||
() -> assertFalse(ArrayTools.isEmpty(new double[] { 1 })));
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - isNullOrEmpty
|
||||
// #endregion - isEmpty
|
||||
// ================================
|
||||
|
||||
// ================================
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user