Compare commits
16 Commits
1.0.0
...
88ca20cd6a
Author | SHA1 | Date | |
---|---|---|---|
88ca20cd6a | |||
e98fe66b65 | |||
872d42aef0 | |||
3f08b08910 | |||
4c1ee87b4d | |||
a9c8fec81a | |||
29519f3489 | |||
26efd1125e | |||
b912f4b063 | |||
90da2b8eaa | |||
8d3bbbc56b | |||
bdd6e61160 | |||
f024a08dd2 | |||
cb2eb0633f | |||
0f7ab8fed5 | |||
0c4cfd3044 |
219
README.md
Normal file
219
README.md
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
## 一、annotation - 注解
|
||||||
|
### 1. StaticFactoryMethod
|
||||||
|
标识静态工厂方法。 *《Effective Java》* 的 **Item1** 建议考虑用静态工厂方法替换构造器, 因而考虑有一个注解可以标记一下静态工厂方法,以和其它方法进行区分。
|
||||||
|
|
||||||
|
### 2. ReaderMethod 和 WriterMethod
|
||||||
|
分别标识读方法(如 getter)或写方法(如 setter)。
|
||||||
|
|
||||||
|
最早是写了一个集合类,为了方便判断使用读写锁时,哪些情况下使用读锁,哪些情况下使用写锁。
|
||||||
|
|
||||||
|
### 3. UnsupportedOperation
|
||||||
|
标识该方法不被支持或没有实现,将抛出 `UnsupportedOperationException`。 为了方便在使用时,不需要点进源码,就能知道该方法没有实现。
|
||||||
|
|
||||||
|
### 4. Virtual
|
||||||
|
Java 非 final 的实例方法,对应 C++/C# 中的虚方法,允许被子类覆写。 Virtual 注解旨在设计父类时,强调该方法父类虽然有默认实现,但子类可以根据自己的需要覆写。
|
||||||
|
|
||||||
|
### 5. ValueObject
|
||||||
|
标记一个类,表示其作为值对象,区别于 Entity。
|
||||||
|
|
||||||
|
## 二、base - 基础组件
|
||||||
|
### 1. Ref
|
||||||
|
`Ref` 包装了一个值,表示对该值的应用。
|
||||||
|
|
||||||
|
灵感来自于 C# 的 ref 参数修饰符。C# 允许通过以下方式,将值返回给调用端:
|
||||||
|
```C#
|
||||||
|
void Method(ref int refArgument)
|
||||||
|
{
|
||||||
|
refArgument = refArgument + 44;
|
||||||
|
}
|
||||||
|
|
||||||
|
int number = 1;
|
||||||
|
Method(ref number);
|
||||||
|
Console.WriteLine(number); // Output: 45
|
||||||
|
```
|
||||||
|
`Ref` 使 Java 可以达到类似的效果,如:
|
||||||
|
```java
|
||||||
|
void method(Ref<Integer> refArgument) {
|
||||||
|
refArgument.transformValue(i -> i + 44);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Integer> number = Ref.of(1);
|
||||||
|
method(number);
|
||||||
|
System.out.println(number.getValue()); // Output: 45
|
||||||
|
```
|
||||||
|
当一个方法需要产生多个结果时,无法有多个返回值,可以使用 `Ref` 作为参数传入,方法内部修改 `Ref` 的值。 调用方在调用方法之后,使用 `getValue()` 获取结果。
|
||||||
|
```java
|
||||||
|
String method(Ref<Integer> intRefArgument, Ref<String> strRefArgument) {
|
||||||
|
intRefArgument.transformValue(i -> i + 44);
|
||||||
|
strRefArgument.setValue("Hello " + strRefArgument.getValue());
|
||||||
|
return "Return string";
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Integer> number = Ref.of(1);
|
||||||
|
Ref<String> str = Ref.of("Java");
|
||||||
|
String result = method(number, str);
|
||||||
|
System.out.println(number.getValue()); // Output: 45
|
||||||
|
System.out.println(str.getValue()); // Output: Hello Java
|
||||||
|
System.out.println(result); // Output: Return string
|
||||||
|
```
|
||||||
|
### 2. IWithCode
|
||||||
|
类似于枚举这样的类型,通常需要设置固定的码值表示对应的含义。 可实现 `IWithCode`、`IWithIntCode`、`IWithLongCode`,便于在需要的地方对这些接口的实现进行处理。
|
||||||
|
|
||||||
|
## 三、collection - 集合
|
||||||
|
### 1. CollectionTools
|
||||||
|
集合工具类
|
||||||
|
|
||||||
|
## 四、constant - 常量
|
||||||
|
### 1. 正则常量
|
||||||
|
`RegexConsts` 包含常见正则表达式;`PatternConsts` 包含对应的 `Pattern` 对象
|
||||||
|
|
||||||
|
## 五、exception - 异常
|
||||||
|
### 1. MultiTypesException - 多类型异常
|
||||||
|
异常在不同场景下被抛出,可以用不同的枚举值,表示不同的场景类型。
|
||||||
|
|
||||||
|
异常实现 `MultiTypesException` 的 `MultiTypesException#getType` 方法,返回对应的场景类型。
|
||||||
|
|
||||||
|
表示场景类型的枚举实现 `MultiTypesException.ExceptionType`,其中的工厂方法用于创建类型对象。
|
||||||
|
```java
|
||||||
|
public final class LoginException
|
||||||
|
extends RuntimeException
|
||||||
|
implements MultiTypesException<LoginException, LoginException.Type> {
|
||||||
|
private final Type type;
|
||||||
|
private LoginException(@Nonnull Type type, @Nonnull String message) {
|
||||||
|
super(message);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginException(@Nonnull Type type, @Nonnull Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginException(@Nonnull Type type,
|
||||||
|
@Nonnull String message,
|
||||||
|
@Nonnull Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull Type getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
public enum Type implements ExceptionType {
|
||||||
|
DEFAULT("00", "当前会话未登录"),
|
||||||
|
NOT_TOKEN("10", "未提供token"),
|
||||||
|
INVALID_TOKEN("20", "token无效"),
|
||||||
|
TOKEN_TIMEOUT("30", "token已过期"),
|
||||||
|
BE_REPLACED("40", "token已被顶下线"),
|
||||||
|
KICK_OUT("50", "token已被踢下线"),
|
||||||
|
;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final String code;
|
||||||
|
@Nonnull
|
||||||
|
private final String defaultMessage;
|
||||||
|
|
||||||
|
Type(@Nonnull String code, @Nonnull String defaultMessage) {
|
||||||
|
this.code = code;
|
||||||
|
this.defaultMessage = defaultMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull String getDefaultMessage() {
|
||||||
|
return defaultMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull LoginException create() {
|
||||||
|
return new LoginException(this, this.defaultMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull LoginException create(String message) {
|
||||||
|
return new LoginException(this, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull LoginException create(Throwable cause) {
|
||||||
|
return new LoginException(this, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nonnull LoginException create(String message, Throwable cause) {
|
||||||
|
return new LoginException(this, message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
使用时,可以使用这种方式创建并抛出异常:
|
||||||
|
```java
|
||||||
|
throw LoginException.Type.TOKEN_TIMEOUT.create();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 业务异常
|
||||||
|
预设常见的业务异常。可继承 `BizException` 自定义业务异常。
|
||||||
|
|
||||||
|
### 3. 系统异常
|
||||||
|
预设常见的系统异常。可继承 `SysException` 自定义系统异常。
|
||||||
|
|
||||||
|
## 六、function - 函数式编程
|
||||||
|
### 1. PredicateTools
|
||||||
|
`PredicateTools` 用于 `Predicate` 的相关操作。
|
||||||
|
|
||||||
|
### 2. Functional interfaces
|
||||||
|
补充可能用得上的函数式接口:
|
||||||
|
|
||||||
|
| Group | FunctionalInterface | method |
|
||||||
|
| ------------- | -------------------- | -------------------------------- |
|
||||||
|
| UnaryOperator | BoolUnaryOperator | boolean applyAsBool (boolean) |
|
||||||
|
| UnaryOperator | CharUnaryOperator | char applyAsChar(char) |
|
||||||
|
| Throwing | Executable | void execute() throws E |
|
||||||
|
| Throwing | ThrowingConsumer | void accept(T) throws E |
|
||||||
|
| Throwing | ThrowingFunction | R apply(T) throws E |
|
||||||
|
| Throwing | ThrowingPredicate | boolean test(T) throws E |
|
||||||
|
| Throwing | ThrowingSupplier | T get() throws E |
|
||||||
|
| Optional | OptionalSupplier | Optional<T> get() throws E |
|
||||||
|
| Optional | ToOptionalBiFunction | Optional<R> apply(T,U) |
|
||||||
|
| Optional | ToOptionalFunction | Optional<R> apply(T) |
|
||||||
|
|
||||||
|
## 七、model - 业务建模组件
|
||||||
|
包含业务建模可能用到的性别、身份证等元素,也包含数据传输对象,如分页查询参数、响应结果、分页结果等。
|
||||||
|
|
||||||
|
### 数据传输对象
|
||||||
|
#### 1. 分页
|
||||||
|
分页组件由 `PagingAndSortingQueryParams` 作为入参, 因为分页必须伴随着排序,不然可能出现同一个对象重复出现在不同页,有的对象不被查询到的情况, 所以分页查询的入参必须包含排序条件。
|
||||||
|
|
||||||
|
用户可继承 `PagingAndSortingQueryParams` 构建自己的分页查询入参,需在构造器中调用 `PagingAndSortingQueryParams` 的构造器,传入一个 Map 作为白名单, key 是供前端指定用于排序的**属性名**,value 是对应数据库中的**字段名**,只有在白名单中指定的属性名才允许作为排序条件。
|
||||||
|
|
||||||
|
`PagingAndSortingQueryParams` 包含三个主要的属性:
|
||||||
|
- **size** - 每页显示的记录数
|
||||||
|
- **pageNum** - 当前页码
|
||||||
|
- **orderBy** - 排序条件
|
||||||
|
其中 `orderBy` 是一个 List,可以指定多个排序条件,每个排序条件是一个字符串, 格式为“**属性名-ASC**”或“**属性名-DESC**”,分别表示升序和降序。
|
||||||
|
|
||||||
|
比如前端传入的 orderBy 为 ["name-ASC","age-DESC"],意味着要按 name 进行升序,name 相同的情况下则按 age 进行降序。
|
||||||
|
|
||||||
|
使用时调用 `PagingAndSortingQueryParams#buildPagingParams()` 方法获取分页参数 `PagingParams`。
|
||||||
|
|
||||||
|
分页结果可以存放到 `PageResult` 中,作为出参。
|
||||||
|
|
||||||
|
#### 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)。
|
||||||
|
|
||||||
|
## 八、time - 时间 API
|
||||||
|
### 1. 季度
|
||||||
|
模仿 JDK 的 `java.time.Month` 和 `java.time.YearMonth`, 实现 `Quarter`、`YearQuarter`,对季度进行建模。
|
||||||
|
|
||||||
|
## 九、util - 工具类
|
||||||
|
包含树构建器(`TreeBuilder`)、断言工具(`AssertTools`)、ID 生成器(`IdGenerator`)及其它实用工具类。
|
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>注解</h2>
|
||||||
|
*
|
||||||
|
* <h3>
|
||||||
|
* 1. {@link StaticFactoryMethod}
|
||||||
|
* </h3>
|
||||||
|
* <p>
|
||||||
|
* 标识<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}
|
||||||
|
* </h3>
|
||||||
|
* <p>
|
||||||
|
* 标识该方法不被支持或没有实现,将抛出 {@link UnsupportedOperationException}。
|
||||||
|
* 为了方便在使用时,不需要点进源码,就能知道该方法没有实现。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h3>
|
||||||
|
* 4. {@link Virtual}
|
||||||
|
* </h3>
|
||||||
|
* <p>
|
||||||
|
* 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>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.annotation;
|
@@ -15,9 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础组件
|
* <h2>基础组件</h2>
|
||||||
*
|
*
|
||||||
* <h2>Ref</h2>
|
* <h3>1. Ref</h3>
|
||||||
* <p>
|
* <p>
|
||||||
* {@link Ref} 包装了一个值,表示对该值的应用。
|
* {@link Ref} 包装了一个值,表示对该值的应用。
|
||||||
* </p>
|
* </p>
|
||||||
@@ -61,11 +61,13 @@
|
|||||||
* System.out.println(result); // Output: Return string
|
* System.out.println(result); // Output: Return string
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* <h2>IWithCode</h2>
|
* <h3>2. IWithCode</h3>
|
||||||
* <p>
|
* <p>
|
||||||
* 类似于枚举之类的类,通常需要设置固定的码值表示对应的含义。
|
* 类似于枚举这样的类型,通常需要设置固定的码值表示对应的含义。
|
||||||
* 可实现 {@link IWithCode}、{@link IWithIntCode}、{@link IWithLongCode},便于在需要的地方对这些接口的实现进行处理。
|
* 可实现 {@link IWithCode}、{@link IWithIntCode}、{@link IWithLongCode},便于在需要的地方对这些接口的实现进行处理。
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
*/
|
*/
|
||||||
@CheckReturnValue
|
@CheckReturnValue
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>集合<h2>
|
||||||
|
*
|
||||||
|
* <h3>
|
||||||
|
* 1. {@link CollectionTools}
|
||||||
|
* </h3>
|
||||||
|
* 集合工具类
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package xyz.zhouxy.plusone.commons.collection;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023-2024 the original author or authors.
|
* Copyright 2023-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -61,7 +61,7 @@ public final class PatternConsts {
|
|||||||
*
|
*
|
||||||
* @see RegexConsts#EMAIL
|
* @see RegexConsts#EMAIL
|
||||||
*/
|
*/
|
||||||
public static final Pattern EMAIL = Pattern.compile(RegexConsts.EMAIL);
|
public static final Pattern EMAIL = Pattern.compile(RegexConsts.EMAIL, Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中国大陆手机号
|
* 中国大陆手机号
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022-2024 the original author or authors.
|
* Copyright 2022-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,6 +32,9 @@ public final class RegexConsts {
|
|||||||
|
|
||||||
public static final String CAPTCHA = "^\\w{4,6}$";
|
public static final String CAPTCHA = "^\\w{4,6}$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* from https://emailregex.com/
|
||||||
|
*/
|
||||||
public static final String EMAIL
|
public static final String EMAIL
|
||||||
= "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")"
|
= "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")"
|
||||||
+ "@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";
|
+ "@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>常量<h2>
|
||||||
|
*
|
||||||
|
* <h3>
|
||||||
|
* 1. 正则常量
|
||||||
|
* </h3>
|
||||||
|
* {@link RegexConsts} 包含常见正则表达式;{@link PatternConsts} 包含对应的 {@link Pattern} 对象。
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.constant;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务异常
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.exception.business;
|
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>异常<h2>
|
||||||
|
*
|
||||||
|
* <h3>1. {@link MultiTypesException} - 多类型异常</h3>
|
||||||
|
* <p>
|
||||||
|
* 异常在不同场景下被抛出,可以用不同的枚举值,表示不同的场景类型。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 异常实现 {@link MultiTypesException} 的 {@link MultiTypesException#getType} 方法,返回对应的场景类型。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 表示场景类型的枚举实现 {@link MultiTypesException.ExceptionType},其中的工厂方法用于创建类型对象。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* public final class LoginException
|
||||||
|
* extends RuntimeException
|
||||||
|
* implements MultiTypesException<LoginException, LoginException.Type> {
|
||||||
|
* private final Type type;
|
||||||
|
* private LoginException(@Nonnull Type type, @Nonnull String message) {
|
||||||
|
* super(message);
|
||||||
|
* this.type = type;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* private LoginException(@Nonnull Type type, @Nonnull Throwable cause) {
|
||||||
|
* super(cause);
|
||||||
|
* this.type = type;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* private LoginException(@Nonnull Type type,
|
||||||
|
* @Nonnull String message,
|
||||||
|
* @Nonnull Throwable cause) {
|
||||||
|
* super(message, cause);
|
||||||
|
* this.type = type;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull Type getType() {
|
||||||
|
* return this.type;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // ...
|
||||||
|
*
|
||||||
|
* public enum Type implements ExceptionType<LoginException> {
|
||||||
|
* DEFAULT("00", "当前会话未登录"),
|
||||||
|
* NOT_TOKEN("10", "未提供token"),
|
||||||
|
* INVALID_TOKEN("20", "token无效"),
|
||||||
|
* TOKEN_TIMEOUT("30", "token已过期"),
|
||||||
|
* BE_REPLACED("40", "token已被顶下线"),
|
||||||
|
* KICK_OUT("50", "token已被踢下线"),
|
||||||
|
* ;
|
||||||
|
*
|
||||||
|
* @Nonnull
|
||||||
|
* private final String code;
|
||||||
|
* @Nonnull
|
||||||
|
* private final String defaultMessage;
|
||||||
|
*
|
||||||
|
* Type(@Nonnull String code, @Nonnull String defaultMessage) {
|
||||||
|
* this.code = code;
|
||||||
|
* this.defaultMessage = defaultMessage;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull String getCode() {
|
||||||
|
* return code;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull String getDefaultMessage() {
|
||||||
|
* return defaultMessage;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull LoginException create() {
|
||||||
|
* return new LoginException(this, this.defaultMessage);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull LoginException create(String message) {
|
||||||
|
* return new LoginException(this, message);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull LoginException create(Throwable cause) {
|
||||||
|
* return new LoginException(this, cause);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public @Nonnull LoginException create(String message, Throwable cause) {
|
||||||
|
* return new LoginException(this, message, cause);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* 使用时,可以使用这种方式创建并抛出异常:
|
||||||
|
* <pre>
|
||||||
|
* throw LoginException.Type.TOKEN_TIMEOUT.create();
|
||||||
|
* </pre>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h3>2. 业务异常</h3>
|
||||||
|
* 预设常见的业务异常。可继承 {@link BizException} 自定义业务异常。
|
||||||
|
*
|
||||||
|
* <h3>3. 系统异常</h3>
|
||||||
|
* 预设常见的系统异常。可继承 {@link SysException} 自定义系统异常。
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.exception;
|
||||||
|
|
||||||
|
import xyz.zhouxy.plusone.commons.exception.business.*;
|
||||||
|
import xyz.zhouxy.plusone.commons.exception.system.*;
|
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统异常
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.exception.system;
|
@@ -15,16 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数式编程
|
* <h2>函数式编程</h2>
|
||||||
*
|
*
|
||||||
* <h2>PredicateTools</h2>
|
* <h3>1. PredicateTools</h3>
|
||||||
* <p>
|
* <p>
|
||||||
* {@link PredicateTools} 用于 {@link java.util.function.Predicate} 的相关操作。
|
* {@link PredicateTools} 用于 {@link java.util.function.Predicate} 的相关操作。
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <h2>Functional interfaces</h2>
|
* <h3>2. Functional interfaces</h3>
|
||||||
* <p>
|
* <p>
|
||||||
* 补充一些 JDK 没有,而项目中可能用得上的函数式接口:
|
* 补充可能用得上的函数式接口:
|
||||||
* <pre>
|
* <pre>
|
||||||
* | Group | FunctionalInterface | method |
|
* | Group | FunctionalInterface | method |
|
||||||
* | ------------- | -------------------- | -------------------------------- |
|
* | ------------- | -------------------- | -------------------------------- |
|
||||||
@@ -40,5 +40,7 @@
|
|||||||
* | Optional | ToOptionalFunction | Optional<R> apply(T) |
|
* | Optional | ToOptionalFunction | Optional<R> apply(T) |
|
||||||
* </pre>
|
* </pre>
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
*/
|
*/
|
||||||
package xyz.zhouxy.plusone.commons.function;
|
package xyz.zhouxy.plusone.commons.function;
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>数据传输对象</h2>
|
||||||
|
*
|
||||||
|
* <h3>1. 分页</h3>
|
||||||
|
* <p>
|
||||||
|
* 分页组件由 {@link PagingAndSortingQueryParams} 作为入参,
|
||||||
|
* 因为分页必须伴随着排序,不然可能出现同一个对象重复出现在不同页,有的对象不被查询到的情况,
|
||||||
|
* 所以分页查询的入参必须包含排序条件。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 用户可继承 {@link PagingAndSortingQueryParams}
|
||||||
|
* 构建自己的分页查询入参,需在构造器中调用 {@link PagingAndSortingQueryParams} 的构造器,传入一个 Map 作为白名单,
|
||||||
|
* key 是供前端指定用于排序的属性名,value 是对应数据库中的字段名,只有在白名单中指定的属性名才允许作为排序条件。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* {@link PagingAndSortingQueryParams} 包含三个主要的属性:
|
||||||
|
* <ul>
|
||||||
|
* <li>size - 每页显示的记录数</li>
|
||||||
|
* <li>pageNum - 当前页码</li>
|
||||||
|
* <li>orderBy - 排序条件</li>
|
||||||
|
* </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",
|
||||||
|
* 用户按测试类 CustomUnifiedResponseFactoryTests 中所示范的,继承 {@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>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.model.dto;
|
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>业务建模组件</h2>
|
||||||
|
* <p>
|
||||||
|
* 包含业务建模可能用到的性别、身份证等元素,也包含 DTO 相关类,如分页查询参数,响应结果,分页结果等。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.model;
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2024 the original author or authors.
|
* Copyright 2024-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -86,6 +86,7 @@ public enum Quarter implements IWithIntCode {
|
|||||||
*/
|
*/
|
||||||
@StaticFactoryMethod(Quarter.class)
|
@StaticFactoryMethod(Quarter.class)
|
||||||
public static Quarter fromMonth(Month month) {
|
public static Quarter fromMonth(Month month) {
|
||||||
|
AssertTools.checkNotNull(month);
|
||||||
final int monthValue = month.getValue();
|
final int monthValue = month.getValue();
|
||||||
return of(computeQuarterValueInternal(monthValue));
|
return of(computeQuarterValueInternal(monthValue));
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.errorprone.annotations.Immutable;
|
import com.google.errorprone.annotations.Immutable;
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
|||||||
/** 季度结束日期 */
|
/** 季度结束日期 */
|
||||||
private final LocalDate lastDate;
|
private final LocalDate lastDate;
|
||||||
|
|
||||||
private YearQuarter(int year, @Nonnull Quarter quarter) {
|
private YearQuarter(int year, Quarter quarter) {
|
||||||
this.year = year;
|
this.year = year;
|
||||||
this.quarter = quarter;
|
this.quarter = quarter;
|
||||||
this.firstDate = quarter.firstMonthDay().atYear(year);
|
this.firstDate = quarter.firstMonthDay().atYear(year);
|
||||||
@@ -249,7 +249,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (this == obj)
|
if (this == obj)
|
||||||
return true;
|
return true;
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
@@ -264,6 +264,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
|
|||||||
|
|
||||||
// #region - compare
|
// #region - compare
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(YearQuarter other) {
|
public int compareTo(YearQuarter other) {
|
||||||
int cmp = (this.year - other.year);
|
int cmp = (this.year - other.year);
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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>
|
||||||
|
*/
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package xyz.zhouxy.plusone.commons.time;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2024 the original author or authors.
|
* Copyright 2024-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,7 +26,6 @@ import java.util.Objects;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +258,7 @@ public class ArrayTools {
|
|||||||
*
|
*
|
||||||
* @throws IllegalArgumentException 当参数为空时抛出
|
* @throws IllegalArgumentException 当参数为空时抛出
|
||||||
*/
|
*/
|
||||||
public static <T> boolean isAllElementsNotNull(@Nonnull final T[] arr) {
|
public static <T> boolean isAllElementsNotNull(final T[] arr) {
|
||||||
AssertTools.checkArgument(arr != null, "The array cannot be null.");
|
AssertTools.checkArgument(arr != null, "The array cannot be null.");
|
||||||
return Arrays.stream(arr).allMatch(Objects::nonNull);
|
return Arrays.stream(arr).allMatch(Objects::nonNull);
|
||||||
}
|
}
|
||||||
@@ -622,15 +621,15 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - char
|
// fill - char
|
||||||
|
|
||||||
public static void fill(char[] a, char[] values) {
|
public static void fill(char[] a, @Nullable char[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(char[] a, String values) {
|
public static void fill(char[] a, @Nullable String values) {
|
||||||
fill(a, 0, a.length, values != null ? values.toCharArray() : EMPTY_CHAR_ARRAY);
|
fill(a, 0, a.length, values != null ? values.toCharArray() : EMPTY_CHAR_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(char[] a, int fromIndex, int toIndex, char[] values) {
|
public static void fill(char[] a, int fromIndex, int toIndex, @Nullable char[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -655,11 +654,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - byte
|
// fill - byte
|
||||||
|
|
||||||
public static void fill(byte[] a, byte[] values) {
|
public static void fill(byte[] a, @Nullable byte[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(byte[] a, int fromIndex, int toIndex, byte[] values) {
|
public static void fill(byte[] a, int fromIndex, int toIndex, @Nullable byte[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -684,11 +683,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - short
|
// fill - short
|
||||||
|
|
||||||
public static void fill(short[] a, short[] values) {
|
public static void fill(short[] a, @Nullable short[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(short[] a, int fromIndex, int toIndex, short[] values) {
|
public static void fill(short[] a, int fromIndex, int toIndex, @Nullable short[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -713,11 +712,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - int
|
// fill - int
|
||||||
|
|
||||||
public static void fill(int[] a, int[] values) {
|
public static void fill(int[] a, @Nullable int[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(int[] a, int fromIndex, int toIndex, int[] values) {
|
public static void fill(int[] a, int fromIndex, int toIndex, @Nullable int[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -742,11 +741,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - long
|
// fill - long
|
||||||
|
|
||||||
public static void fill(long[] a, long[] values) {
|
public static void fill(long[] a, @Nullable long[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(long[] a, int fromIndex, int toIndex, long[] values) {
|
public static void fill(long[] a, int fromIndex, int toIndex, @Nullable long[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -771,11 +770,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - float
|
// fill - float
|
||||||
|
|
||||||
public static void fill(float[] a, float[] values) {
|
public static void fill(float[] a, @Nullable float[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(float[] a, int fromIndex, int toIndex, float[] values) {
|
public static void fill(float[] a, int fromIndex, int toIndex, @Nullable float[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -800,11 +799,11 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - double
|
// fill - double
|
||||||
|
|
||||||
public static void fill(double[] a, double[] values) {
|
public static void fill(double[] a, @Nullable double[] values) {
|
||||||
fill(a, 0, a.length, values);
|
fill(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fill(double[] a, int fromIndex, int toIndex, double[] values) {
|
public static void fill(double[] a, int fromIndex, int toIndex, @Nullable double[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -829,15 +828,15 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// fill - T
|
// fill - T
|
||||||
|
|
||||||
public static <T> void fill(@Nonnull T[] a, T[] values) {
|
public static <T> void fill(T[] a, @Nullable T[] values) {
|
||||||
fillInternal(a, 0, a.length, values);
|
fillInternal(a, 0, a.length, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> void fill(@Nonnull T[] a, int fromIndex, int toIndex, T[] values) {
|
public static <T> void fill(T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
||||||
fillInternal(a, fromIndex, toIndex, values);
|
fillInternal(a, fromIndex, toIndex, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void fillInternal(@Nonnull T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
private static <T> void fillInternal(T[] a, int fromIndex, int toIndex, @Nullable T[] values) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(a));
|
AssertTools.checkArgument(Objects.nonNull(a));
|
||||||
if (values == null || values.length == 0) {
|
if (values == null || values.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -864,9 +863,9 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// #region - indexOf
|
// #region - indexOf
|
||||||
|
|
||||||
public static <T> int indexOfWithPredicate(T[] arr, Predicate<? super T> predicate) {
|
public static <T> int indexOfWithPredicate(@Nullable T[] arr, Predicate<? super T> predicate) {
|
||||||
AssertTools.checkNotNull(predicate);
|
AssertTools.checkNotNull(predicate);
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -877,12 +876,12 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> int indexOf(T[] arr, T obj) {
|
public static <T> int indexOf(@Nullable T[] arr, @Nullable T obj) {
|
||||||
return indexOfWithPredicate(arr, item -> Objects.equals(item, obj));
|
return indexOfWithPredicate(arr, item -> Objects.equals(item, obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(char[] arr, char value) {
|
public static int indexOf(@Nullable char[] arr, char value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -893,8 +892,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(byte[] arr, byte value) {
|
public static int indexOf(@Nullable byte[] arr, byte value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -905,8 +904,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(short[] arr, short value) {
|
public static int indexOf(@Nullable short[] arr, short value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -917,8 +916,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(int[] arr, int value) {
|
public static int indexOf(@Nullable int[] arr, int value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -929,8 +928,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(long[] arr, long value) {
|
public static int indexOf(@Nullable long[] arr, long value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -941,8 +940,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(float[] arr, float value) {
|
public static int indexOf(@Nullable float[] arr, float value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -953,8 +952,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int indexOf(double[] arr, double value) {
|
public static int indexOf(@Nullable double[] arr, double value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
@@ -969,9 +968,9 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// #region - lastIndexOf
|
// #region - lastIndexOf
|
||||||
|
|
||||||
public static <T> int lastIndexOfWithPredicate(T[] arr, @Nonnull Predicate<? super T> predicate) {
|
public static <T> int lastIndexOfWithPredicate(@Nullable T[] arr, Predicate<? super T> predicate) {
|
||||||
AssertTools.checkNotNull(predicate);
|
AssertTools.checkNotNull(predicate);
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -986,8 +985,8 @@ public class ArrayTools {
|
|||||||
return lastIndexOfWithPredicate(arr, item -> Objects.equals(item, obj));
|
return lastIndexOfWithPredicate(arr, item -> Objects.equals(item, obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(char[] arr, char value) {
|
public static int lastIndexOf(@Nullable char[] arr, char value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -998,8 +997,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(byte[] arr, byte value) {
|
public static int lastIndexOf(@Nullable byte[] arr, byte value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1010,8 +1009,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(short[] arr, short value) {
|
public static int lastIndexOf(@Nullable short[] arr, short value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1022,8 +1021,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(int[] arr, int value) {
|
public static int lastIndexOf(@Nullable int[] arr, int value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1034,8 +1033,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(long[] arr, long value) {
|
public static int lastIndexOf(@Nullable long[] arr, long value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1046,8 +1045,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(float[] arr, float value) {
|
public static int lastIndexOf(@Nullable float[] arr, float value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1058,8 +1057,8 @@ public class ArrayTools {
|
|||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int lastIndexOf(double[] arr, double value) {
|
public static int lastIndexOf(@Nullable double[] arr, double value) {
|
||||||
if (isNullOrEmpty(arr)) {
|
if (arr == null || arr.length == 0) {
|
||||||
return NOT_FOUND_INDEX;
|
return NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
for (int i = arr.length - 1; i >= 0; i--) {
|
for (int i = arr.length - 1; i >= 0; i--) {
|
||||||
@@ -1074,39 +1073,39 @@ public class ArrayTools {
|
|||||||
|
|
||||||
// #region - contains
|
// #region - contains
|
||||||
|
|
||||||
public static <T> boolean contains(T[] arr, T obj) {
|
public static <T> boolean contains(@Nullable T[] arr, @Nullable T obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(char[] arr, char obj) {
|
public static boolean contains(@Nullable char[] arr, char obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(byte[] arr, byte obj) {
|
public static boolean contains(@Nullable byte[] arr, byte obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(short[] arr, short obj) {
|
public static boolean contains(@Nullable short[] arr, short obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(int[] arr, int obj) {
|
public static boolean contains(@Nullable int[] arr, int obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(long[] arr, long obj) {
|
public static boolean contains(@Nullable long[] arr, long obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(float[] arr, float obj) {
|
public static boolean contains(@Nullable float[] arr, float obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean contains(double[] arr, double obj) {
|
public static boolean contains(@Nullable double[] arr, double obj) {
|
||||||
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
return indexOf(arr, obj) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean containsValue(BigDecimal[] arr, BigDecimal obj) {
|
public static boolean containsValue(@Nullable BigDecimal[] arr, @Nullable BigDecimal obj) {
|
||||||
return indexOfWithPredicate(arr, item -> BigDecimals.equalsValue(item, obj)) > NOT_FOUND_INDEX;
|
return indexOfWithPredicate(arr, item -> BigDecimals.equalsValue(item, obj)) > NOT_FOUND_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2024 the original author or authors.
|
* Copyright 2024-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,7 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import xyz.zhouxy.plusone.commons.exception.DataNotExistsException;
|
import xyz.zhouxy.plusone.commons.exception.DataNotExistsException;
|
||||||
import xyz.zhouxy.plusone.commons.exception.system.DataOperationResultException;
|
import xyz.zhouxy.plusone.commons.exception.system.DataOperationResultException;
|
||||||
@@ -55,12 +55,12 @@ public class AssertTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link IllegalArgumentException} if the {@code condition} is false. */
|
/** Throw {@link IllegalArgumentException} if the {@code condition} is false. */
|
||||||
public static void checkArgument(boolean condition, String errMsg) {
|
public static void checkArgument(boolean condition, @Nullable String errMsg) {
|
||||||
checkCondition(condition, () -> new IllegalArgumentException(errMsg));
|
checkCondition(condition, () -> new IllegalArgumentException(errMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link IllegalArgumentException} if the {@code condition} is false. */
|
/** Throw {@link IllegalArgumentException} if the {@code condition} is false. */
|
||||||
public static void checkArgument(boolean condition, @Nonnull Supplier<String> messageSupplier) {
|
public static void checkArgument(boolean condition, Supplier<String> messageSupplier) {
|
||||||
checkCondition(condition, () -> new IllegalArgumentException(messageSupplier.get()));
|
checkCondition(condition, () -> new IllegalArgumentException(messageSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,12 +83,12 @@ public class AssertTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link IllegalStateException} if the {@code condition} is false. */
|
/** Throw {@link IllegalStateException} if the {@code condition} is false. */
|
||||||
public static void checkState(boolean condition, String errMsg) {
|
public static void checkState(boolean condition, @Nullable String errMsg) {
|
||||||
checkCondition(condition, () -> new IllegalStateException(errMsg));
|
checkCondition(condition, () -> new IllegalStateException(errMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link IllegalStateException} if the {@code condition} is false. */
|
/** Throw {@link IllegalStateException} if the {@code condition} is false. */
|
||||||
public static void checkState(boolean condition, @Nonnull Supplier<String> messageSupplier) {
|
public static void checkState(boolean condition, Supplier<String> messageSupplier) {
|
||||||
checkCondition(condition, () -> new IllegalStateException(messageSupplier.get()));
|
checkCondition(condition, () -> new IllegalStateException(messageSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,22 +106,22 @@ public class AssertTools {
|
|||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
||||||
public static <T> void checkNotNull(T obj) {
|
public static <T> void checkNotNull(@Nullable T obj) {
|
||||||
checkCondition(obj != null, NullPointerException::new);
|
checkCondition(obj != null, NullPointerException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
||||||
public static <T> void checkNotNull(T obj, String errMsg) {
|
public static <T> void checkNotNull(@Nullable T obj, String errMsg) {
|
||||||
checkCondition(obj != null, () -> new NullPointerException(errMsg));
|
checkCondition(obj != null, () -> new NullPointerException(errMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
||||||
public static <T> void checkNotNull(T obj, @Nonnull Supplier<String> messageSupplier) {
|
public static <T> void checkNotNull(@Nullable T obj, Supplier<String> messageSupplier) {
|
||||||
checkCondition(obj != null, () -> new NullPointerException(messageSupplier.get()));
|
checkCondition(obj != null, () -> new NullPointerException(messageSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
/** Throw {@link NullPointerException} if the {@code obj} is null. */
|
||||||
public static <T> void checkNotNull(T obj, String format, Object... args) {
|
public static <T> void checkNotNull(@Nullable T obj, String format, Object... args) {
|
||||||
checkCondition(obj != null, () -> new NullPointerException(String.format(format, args)));
|
checkCondition(obj != null, () -> new NullPointerException(String.format(format, args)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,56 +134,56 @@ public class AssertTools {
|
|||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
||||||
public static <T> T checkExists(T obj)
|
public static <T> T checkExists(@Nullable T obj)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(Objects.nonNull(obj), DataNotExistsException::new);
|
checkCondition(Objects.nonNull(obj), DataNotExistsException::new);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
||||||
public static <T> T checkExists(T obj, String message)
|
public static <T> T checkExists(@Nullable T obj, String message)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(message));
|
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(message));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
||||||
public static <T> T checkExists(T obj, @Nonnull Supplier<String> messageSupplier)
|
public static <T> T checkExists(@Nullable T obj, Supplier<String> messageSupplier)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(messageSupplier.get()));
|
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(messageSupplier.get()));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
/** Throw {@link DataNotExistsException} if the {@code obj} is null. */
|
||||||
public static <T> T checkExists(T obj, String format, Object... args)
|
public static <T> T checkExists(@Nullable T obj, String format, Object... args)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(String.format(format, args)));
|
checkCondition(Objects.nonNull(obj), () -> new DataNotExistsException(String.format(format, args)));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
||||||
public static <T> T checkExists(@Nonnull Optional<T> optional)
|
public static <T> T checkExists(Optional<T> optional)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), DataNotExistsException::new);
|
checkCondition(optional.isPresent(), DataNotExistsException::new);
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
||||||
public static <T> T checkExists(@Nonnull Optional<T> optional, String message)
|
public static <T> T checkExists(Optional<T> optional, String message)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(message));
|
checkCondition(optional.isPresent(), () -> new DataNotExistsException(message));
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
||||||
public static <T> T checkExists(@Nonnull Optional<T> optional, @Nonnull Supplier<String> messageSupplier)
|
public static <T> T checkExists(Optional<T> optional, Supplier<String> messageSupplier)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(messageSupplier.get()));
|
checkCondition(optional.isPresent(), () -> new DataNotExistsException(messageSupplier.get()));
|
||||||
return optional.get();
|
return optional.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
/** Throw {@link DataNotExistsException} if the {@code optional} is present. */
|
||||||
public static <T> T checkExists(@Nonnull Optional<T> optional, String format, Object... args)
|
public static <T> T checkExists(Optional<T> optional, String format, Object... args)
|
||||||
throws DataNotExistsException {
|
throws DataNotExistsException {
|
||||||
checkCondition(optional.isPresent(), () -> new DataNotExistsException(String.format(format, args)));
|
checkCondition(optional.isPresent(), () -> new DataNotExistsException(String.format(format, args)));
|
||||||
return optional.get();
|
return optional.get();
|
||||||
@@ -202,17 +202,18 @@ public class AssertTools {
|
|||||||
"The number of rows affected is expected to be %d, but is: %d", expectedValue, result);
|
"The number of rows affected is expected to be %d, but is: %d", expectedValue, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(int expectedValue, int result, String message) {
|
public static void checkAffectedRows(int expectedValue, int result, @Nullable String message) {
|
||||||
checkCondition(expectedValue == result, () -> new DataOperationResultException(message));
|
checkCondition(expectedValue == result, () -> new DataOperationResultException(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(int expectedValue, int result,
|
public static void checkAffectedRows(int expectedValue, int result,
|
||||||
@Nonnull Supplier<String> messageSupplier) {
|
Supplier<String> messageSupplier) {
|
||||||
checkCondition(expectedValue == result,
|
checkCondition(expectedValue == result,
|
||||||
() -> new DataOperationResultException(messageSupplier.get()));
|
() -> new DataOperationResultException(messageSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(int expectedValue, int result, String format, Object... args) {
|
public static void checkAffectedRows(int expectedValue, int result,
|
||||||
|
String format, Object... args) {
|
||||||
checkCondition(expectedValue == result,
|
checkCondition(expectedValue == result,
|
||||||
() -> new DataOperationResultException(String.format(format, args)));
|
() -> new DataOperationResultException(String.format(format, args)));
|
||||||
}
|
}
|
||||||
@@ -222,17 +223,18 @@ public class AssertTools {
|
|||||||
"The number of rows affected is expected to be %d, but is: %d", expectedValue, result);
|
"The number of rows affected is expected to be %d, but is: %d", expectedValue, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(long expectedValue, long result, String message) {
|
public static void checkAffectedRows(long expectedValue, long result, @Nullable String message) {
|
||||||
checkCondition(expectedValue == result, () -> new DataOperationResultException(message));
|
checkCondition(expectedValue == result, () -> new DataOperationResultException(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(long expectedValue, long result,
|
public static void checkAffectedRows(long expectedValue, long result,
|
||||||
@Nonnull Supplier<String> messageSupplier) {
|
Supplier<String> messageSupplier) {
|
||||||
checkCondition(expectedValue == result,
|
checkCondition(expectedValue == result,
|
||||||
() -> new DataOperationResultException(messageSupplier.get()));
|
() -> new DataOperationResultException(messageSupplier.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedRows(long expectedValue, long result, String format, Object... args) {
|
public static void checkAffectedRows(long expectedValue, long result,
|
||||||
|
String format, Object... args) {
|
||||||
checkCondition(expectedValue == result,
|
checkCondition(expectedValue == result,
|
||||||
() -> new DataOperationResultException(String.format(format, args)));
|
() -> new DataOperationResultException(String.format(format, args)));
|
||||||
}
|
}
|
||||||
@@ -246,7 +248,7 @@ public class AssertTools {
|
|||||||
checkAffectedRows(1, result, message);
|
checkAffectedRows(1, result, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedOneRow(int result, @Nonnull Supplier<String> messageSupplier) {
|
public static void checkAffectedOneRow(int result, Supplier<String> messageSupplier) {
|
||||||
checkAffectedRows(1, result, messageSupplier);
|
checkAffectedRows(1, result, messageSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,11 +265,12 @@ public class AssertTools {
|
|||||||
checkAffectedRows(1L, result, message);
|
checkAffectedRows(1L, result, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedOneRow(long result, @Nonnull Supplier<String> messageSupplier) {
|
public static void checkAffectedOneRow(long result, Supplier<String> messageSupplier) {
|
||||||
checkAffectedRows(1L, result, messageSupplier);
|
checkAffectedRows(1L, result, messageSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkAffectedOneRow(long result, String format, Object... args) {
|
public static void checkAffectedOneRow(long result,
|
||||||
|
String format, Object... args) {
|
||||||
checkAffectedRows(1L, result, format, args);
|
checkAffectedRows(1L, result, format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +282,7 @@ public class AssertTools {
|
|||||||
// #region - Condition
|
// #region - Condition
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
public static <T extends Exception> void checkCondition(boolean condition, @Nonnull Supplier<T> e)
|
public static <T extends Exception> void checkCondition(boolean condition, Supplier<T> e)
|
||||||
throws T {
|
throws T {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw e.get();
|
throw e.get();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023-2024 the original author or authors.
|
* Copyright 2023-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -46,7 +46,9 @@ public class BigDecimals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean ge(BigDecimal a, BigDecimal b) {
|
public static boolean ge(BigDecimal a, BigDecimal b) {
|
||||||
return gt(a, b) || equalsValue(a, b);
|
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||||
|
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||||
|
return (a == b) || (a.compareTo(b) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean lt(BigDecimal a, BigDecimal b) {
|
public static boolean lt(BigDecimal a, BigDecimal b) {
|
||||||
@@ -56,7 +58,9 @@ public class BigDecimals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean le(BigDecimal a, BigDecimal b) {
|
public static boolean le(BigDecimal a, BigDecimal b) {
|
||||||
return lt(a, b) || equalsValue(a, b);
|
AssertTools.checkNotNull(a, "Parameter could not be null.");
|
||||||
|
AssertTools.checkNotNull(b, "Parameter could not be null.");
|
||||||
|
return (a == b) || (a.compareTo(b) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BigDecimal sum(final BigDecimal... numbers) {
|
public static BigDecimal sum(final BigDecimal... numbers) {
|
||||||
@@ -79,7 +83,7 @@ public class BigDecimals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@StaticFactoryMethod(BigDecimal.class)
|
@StaticFactoryMethod(BigDecimal.class)
|
||||||
public static BigDecimal of(final String val) {
|
public static BigDecimal of(@Nullable final String val) {
|
||||||
return (StringTools.isNotBlank(val)) ? new BigDecimal(val) : BigDecimal.ZERO;
|
return (StringTools.isNotBlank(val)) ? new BigDecimal(val) : BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023-2024 the original author or authors.
|
* Copyright 2023-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -44,7 +44,9 @@ import xyz.zhouxy.plusone.commons.time.YearQuarter;
|
|||||||
*/
|
*/
|
||||||
public class DateTimeTools {
|
public class DateTimeTools {
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toString
|
// #region - toString
|
||||||
|
// ================================
|
||||||
|
|
||||||
public static String toYearString(int year) {
|
public static String toYearString(int year) {
|
||||||
return Integer.toString(YEAR.checkValidIntValue(year));
|
return Integer.toString(YEAR.checkValidIntValue(year));
|
||||||
@@ -70,9 +72,13 @@ public class DateTimeTools {
|
|||||||
return String.format("%02d", month.getValue());
|
return String.format("%02d", month.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toDate
|
// #region - toDate
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将时间戳转换为 {@link Date} 对象
|
* 将时间戳转换为 {@link Date} 对象
|
||||||
@@ -137,9 +143,13 @@ public class DateTimeTools {
|
|||||||
return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant());
|
return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toInstant
|
// #region - toInstant
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将时间戳转换为 {@link Instant} 对象
|
* 将时间戳转换为 {@link Instant} 对象
|
||||||
@@ -192,9 +202,13 @@ public class DateTimeTools {
|
|||||||
return ZonedDateTime.of(localDateTime, zone).toInstant();
|
return ZonedDateTime.of(localDateTime, zone).toInstant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toZonedDateTime
|
// #region - toZonedDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取时间戳在指定时区的地区时间。
|
* 获取时间戳在指定时区的地区时间。
|
||||||
@@ -285,9 +299,13 @@ public class DateTimeTools {
|
|||||||
return ZonedDateTime.of(localDateTime, zone);
|
return ZonedDateTime.of(localDateTime, zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toLocalDateTime
|
// #region - toLocalDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取时间戳在指定时区的地区时间。
|
* 获取时间戳在指定时区的地区时间。
|
||||||
@@ -355,11 +373,13 @@ public class DateTimeTools {
|
|||||||
return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone);
|
return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
// ====================
|
// ================================
|
||||||
|
|
||||||
// #region - toJodaInstant
|
// #region - toJodaInstant
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
|
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
|
||||||
@@ -392,9 +412,13 @@ public class DateTimeTools {
|
|||||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toJavaInstant
|
// #region - toJavaInstant
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
|
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
|
||||||
@@ -432,9 +456,13 @@ public class DateTimeTools {
|
|||||||
return toJavaInstant(localDateTime.toDateTime(zone));
|
return toJavaInstant(localDateTime.toDateTime(zone));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toJodaDateTime
|
// #region - toJodaDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
|
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
|
||||||
@@ -479,9 +507,13 @@ public class DateTimeTools {
|
|||||||
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toZonedDateTime
|
// #region - toZonedDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
|
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
|
||||||
@@ -511,7 +543,7 @@ public class DateTimeTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 joda-time 中的 {@link org.joda.time.Instant} 在指定时区的时间,用 Java 8
|
* 获取 joda-time 中的 {@link org.joda.time.Instant} 在指定时区的时间,用 Java 8+ 的
|
||||||
* {@link java.time.ZonedDateTime} 表示
|
* {@link java.time.ZonedDateTime} 表示
|
||||||
*
|
*
|
||||||
* @param instant joda-time 中的时间戳
|
* @param instant joda-time 中的时间戳
|
||||||
@@ -525,9 +557,13 @@ public class DateTimeTools {
|
|||||||
return toJavaInstant(instant).atZone(zone);
|
return toJavaInstant(instant).atZone(zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toJodaLocalDateTime
|
// #region - toJodaLocalDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
|
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
|
||||||
@@ -541,9 +577,13 @@ public class DateTimeTools {
|
|||||||
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - toJavaLocalDateTime
|
// #region - toJavaLocalDateTime
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
|
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
|
||||||
@@ -557,9 +597,13 @@ public class DateTimeTools {
|
|||||||
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - ZoneId <--> DateTimeZone
|
// #region - ZoneId <--> DateTimeZone
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||||
@@ -581,9 +625,13 @@ public class DateTimeTools {
|
|||||||
return org.joda.time.DateTimeZone.forID(zone.getId());
|
return org.joda.time.DateTimeZone.forID(zone.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #region - YearQuarter & Quarter
|
// #region - YearQuarter & Quarter
|
||||||
|
// ================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定日期所在季度
|
* 获取指定日期所在季度
|
||||||
@@ -646,10 +694,12 @@ public class DateTimeTools {
|
|||||||
return YearQuarter.of(date);
|
return YearQuarter.of(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
// #endregion
|
// #endregion
|
||||||
|
// ================================
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// #region - others
|
// #region - start & end
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
public static LocalDate startDateOfYear(int year) {
|
public static LocalDate startDateOfYear(int year) {
|
||||||
@@ -668,6 +718,86 @@ public class DateTimeTools {
|
|||||||
return date.plusDays(1L).atStartOfDay(zone);
|
return date.plusDays(1L).atStartOfDay(zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - start & end
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isFuture
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
public static boolean isFuture(Date date) {
|
||||||
|
return date.after(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(Calendar date) {
|
||||||
|
return date.after(Calendar.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(Instant instant) {
|
||||||
|
return instant.isAfter(Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(long timeMillis) {
|
||||||
|
return timeMillis > System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(LocalDate date) {
|
||||||
|
return date.isAfter(LocalDate.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(LocalDateTime dateTime) {
|
||||||
|
return dateTime.isAfter(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFuture(ZonedDateTime dateTime) {
|
||||||
|
return dateTime.isAfter(ZonedDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isFuture
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isPast
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
public static boolean isPast(Date date) {
|
||||||
|
return date.before(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(Calendar date) {
|
||||||
|
return date.before(Calendar.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(Instant instant) {
|
||||||
|
return instant.isBefore(Instant.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(long timeMillis) {
|
||||||
|
return timeMillis < System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(LocalDate date) {
|
||||||
|
return date.isBefore(LocalDate.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(LocalDateTime dateTime) {
|
||||||
|
return dateTime.isBefore(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPast(ZonedDateTime dateTime) {
|
||||||
|
return dateTime.isBefore(ZonedDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isPast
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - others
|
||||||
|
// ================================
|
||||||
|
|
||||||
public static Range<LocalDateTime> toDateTimeRange(LocalDate date) {
|
public static Range<LocalDateTime> toDateTimeRange(LocalDate date) {
|
||||||
return Range.closedOpen(date.atStartOfDay(), startOfNextDate(date));
|
return Range.closedOpen(date.atStartOfDay(), startOfNextDate(date));
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022-2024 the original author or authors.
|
* Copyright 2022-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,7 +18,6 @@ package xyz.zhouxy.plusone.commons.util;
|
|||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +41,7 @@ public final class EnumTools {
|
|||||||
* @deprecated 不推荐使用枚举的 ordinal。
|
* @deprecated 不推荐使用枚举的 ordinal。
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private static <E extends Enum<?>> E valueOfInternal(@Nonnull Class<E> enumType, int ordinal) { // NOSONAR 该方法弃用,但不删掉
|
private static <E extends Enum<?>> E valueOfInternal(Class<E> enumType, int ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||||
E[] values = enumType.getEnumConstants();
|
E[] values = enumType.getEnumConstants();
|
||||||
AssertTools.checkCondition((ordinal >= 0 && ordinal < values.length),
|
AssertTools.checkCondition((ordinal >= 0 && ordinal < values.length),
|
||||||
() -> new EnumConstantNotPresentException(enumType, Integer.toString(ordinal)));
|
() -> new EnumConstantNotPresentException(enumType, Integer.toString(ordinal)));
|
||||||
@@ -76,7 +75,7 @@ public final class EnumTools {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static <E extends Enum<?>> E valueOf(Class<E> enumType, // NOSONAR 该方法弃用,但不删掉
|
public static <E extends Enum<?>> E valueOf(Class<E> enumType, // NOSONAR 该方法弃用,但不删掉
|
||||||
@Nullable Integer ordinal, E defaultValue) {
|
@Nullable Integer ordinal, @Nullable E defaultValue) {
|
||||||
AssertTools.checkNotNull(enumType);
|
AssertTools.checkNotNull(enumType);
|
||||||
return null == ordinal ? defaultValue : valueOfInternal(enumType, ordinal);
|
return null == ordinal ? defaultValue : valueOfInternal(enumType, ordinal);
|
||||||
}
|
}
|
||||||
@@ -190,7 +189,7 @@ public final class EnumTools {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static <E extends Enum<?>> Integer checkOrdinalOrDefaultInternal(
|
private static <E extends Enum<?>> Integer checkOrdinalOrDefaultInternal(
|
||||||
@Nonnull Class<E> enumType,
|
Class<E> enumType,
|
||||||
@Nullable Integer ordinal,
|
@Nullable Integer ordinal,
|
||||||
@Nullable Integer defaultValue) {
|
@Nullable Integer defaultValue) {
|
||||||
return ordinal != null
|
return ordinal != null
|
||||||
@@ -200,9 +199,9 @@ public final class EnumTools {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static <E extends Enum<?>> Integer checkOrdinalOrGetInternal(
|
private static <E extends Enum<?>> Integer checkOrdinalOrGetInternal(
|
||||||
@Nonnull Class<E> enumType,
|
Class<E> enumType,
|
||||||
@Nullable Integer ordinal,
|
@Nullable Integer ordinal,
|
||||||
@Nonnull Supplier<Integer> defaultValueSupplier) {
|
Supplier<Integer> defaultValueSupplier) {
|
||||||
return ordinal != null
|
return ordinal != null
|
||||||
? checkOrdinal(enumType, ordinal)
|
? checkOrdinal(enumType, ordinal)
|
||||||
: defaultValueSupplier.get();
|
: defaultValueSupplier.get();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022-2024 the original author or authors.
|
* Copyright 2022-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,8 @@ import java.util.Objects;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,6 +56,7 @@ public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
@Override
|
@Override
|
||||||
public final int compareTo(final T o) {
|
public final int compareTo(final T o) {
|
||||||
return Integer.compare(this.id, o.id);
|
return Integer.compare(this.id, o.id);
|
||||||
@@ -65,7 +68,7 @@ public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean equals(final Object obj) {
|
public final boolean equals(@Nullable final Object obj) {
|
||||||
if (this == obj)
|
if (this == obj)
|
||||||
return true;
|
return true;
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
|
@@ -21,8 +21,6 @@ import java.util.Objects;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID 生成器
|
* ID 生成器
|
||||||
*
|
*
|
||||||
@@ -50,7 +48,7 @@ public class IdGenerator {
|
|||||||
return toSimpleString(UUID.randomUUID());
|
return toSimpleString(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toSimpleString(@Nonnull UUID uuid) {
|
public static String toSimpleString(UUID uuid) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(uuid));
|
AssertTools.checkArgument(Objects.nonNull(uuid));
|
||||||
return (uuidDigits(uuid.getMostSignificantBits() >> 32, 8) +
|
return (uuidDigits(uuid.getMostSignificantBits() >> 32, 8) +
|
||||||
uuidDigits(uuid.getMostSignificantBits() >> 16, 4) +
|
uuidDigits(uuid.getMostSignificantBits() >> 16, 4) +
|
||||||
|
@@ -22,6 +22,8 @@ import java.util.Enumeration;
|
|||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,7 +117,7 @@ public class IdWorker {
|
|||||||
* init workerId
|
* init workerId
|
||||||
* @param workerId if null, then auto generate one
|
* @param workerId if null, then auto generate one
|
||||||
*/
|
*/
|
||||||
private void initWorkerId(Long workerId) {
|
private void initWorkerId(@Nullable Long workerId) {
|
||||||
if (workerId == null) {
|
if (workerId == null) {
|
||||||
workerId = generateWorkerId();
|
workerId = generateWorkerId();
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ import javax.annotation.Nullable;
|
|||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OptionalUtil
|
* OptionalTools
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 提供一些 Optional 相关的方法
|
* 提供一些 Optional 相关的方法
|
||||||
|
@@ -22,8 +22,6 @@ import java.util.Objects;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 随机工具类
|
* 随机工具类
|
||||||
* <p>
|
* <p>
|
||||||
@@ -68,20 +66,20 @@ public final class RandomTools {
|
|||||||
* @param length 字符串长度
|
* @param length 字符串长度
|
||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
public static String randomStr(@Nonnull Random random, @Nonnull char[] sourceCharacters, int length) {
|
public static String randomStr(Random random, char[] sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(random, sourceCharacters, length);
|
return randomStrInternal(random, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomStr(@Nonnull char[] sourceCharacters, int length) {
|
public static String randomStr(char[] sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String secureRandomStr(@Nonnull char[] sourceCharacters, int length) {
|
public static String secureRandomStr(char[] sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||||
@@ -97,20 +95,20 @@ public final class RandomTools {
|
|||||||
* @param length 字符串长度
|
* @param length 字符串长度
|
||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
public static String randomStr(@Nonnull Random random, @Nonnull String sourceCharacters, int length) {
|
public static String randomStr(Random random, String sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
AssertTools.checkArgument(Objects.nonNull(random), "Random cannot be null.");
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(random, sourceCharacters, length);
|
return randomStrInternal(random, sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomStr(@Nonnull String sourceCharacters, int length) {
|
public static String randomStr(String sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String secureRandomStr(@Nonnull String sourceCharacters, int length) {
|
public static String secureRandomStr(String sourceCharacters, int length) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(sourceCharacters), "Source characters 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.");
|
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||||
@@ -126,7 +124,7 @@ public final class RandomTools {
|
|||||||
* @param length 字符串长度
|
* @param length 字符串长度
|
||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
private static String randomStrInternal(@Nonnull Random random, @Nonnull char[] sourceCharacters, int length) {
|
private static String randomStrInternal(Random random, char[] sourceCharacters, int length) {
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return StringTools.EMPTY_STRING;
|
return StringTools.EMPTY_STRING;
|
||||||
}
|
}
|
||||||
@@ -147,7 +145,7 @@ public final class RandomTools {
|
|||||||
* @param length 字符串长度
|
* @param length 字符串长度
|
||||||
* @return 随机字符串
|
* @return 随机字符串
|
||||||
*/
|
*/
|
||||||
private static String randomStrInternal(@Nonnull Random random, @Nonnull String sourceCharacters, int length) {
|
private static String randomStrInternal(Random random, String sourceCharacters, int length) {
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return StringTools.EMPTY_STRING;
|
return StringTools.EMPTY_STRING;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023-2024 the original author or authors.
|
* Copyright 2023-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -272,7 +272,7 @@ public final class RegexTools {
|
|||||||
* @return {@link Pattern} 实例
|
* @return {@link Pattern} 实例
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static Pattern cacheAndGetPatternInternal(@Nonnull final String pattern) {
|
private static Pattern cacheAndGetPatternInternal(final String pattern) {
|
||||||
if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) {
|
if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) {
|
||||||
return PATTERN_CACHE.computeIfAbsent(pattern, Pattern::compile);
|
return PATTERN_CACHE.computeIfAbsent(pattern, Pattern::compile);
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@ public final class RegexTools {
|
|||||||
* @return {@link Pattern} 实例
|
* @return {@link Pattern} 实例
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static Pattern getPatternInternal(@Nonnull final String pattern) {
|
private static Pattern getPatternInternal(final String pattern) {
|
||||||
Pattern result = PATTERN_CACHE.get(pattern);
|
Pattern result = PATTERN_CACHE.get(pattern);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = Pattern.compile(pattern);
|
result = Pattern.compile(pattern);
|
||||||
@@ -305,7 +305,7 @@ public final class RegexTools {
|
|||||||
* @return {@link Pattern} 实例数组
|
* @return {@link Pattern} 实例数组
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static Pattern[] cacheAndGetPatternsInternal(@Nonnull final String[] patterns) {
|
private static Pattern[] cacheAndGetPatternsInternal(final String[] patterns) {
|
||||||
return Arrays.stream(patterns)
|
return Arrays.stream(patterns)
|
||||||
.map(RegexTools::cacheAndGetPatternInternal)
|
.map(RegexTools::cacheAndGetPatternInternal)
|
||||||
.toArray(Pattern[]::new);
|
.toArray(Pattern[]::new);
|
||||||
@@ -318,7 +318,7 @@ public final class RegexTools {
|
|||||||
* @return {@link Pattern} 实例数组
|
* @return {@link Pattern} 实例数组
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static Pattern[] getPatternsInternal(@Nonnull final String[] patterns) {
|
private static Pattern[] getPatternsInternal(final String[] patterns) {
|
||||||
return Arrays.stream(patterns)
|
return Arrays.stream(patterns)
|
||||||
.map(RegexTools::getPatternInternal)
|
.map(RegexTools::getPatternInternal)
|
||||||
.toArray(Pattern[]::new);
|
.toArray(Pattern[]::new);
|
||||||
@@ -331,17 +331,17 @@ public final class RegexTools {
|
|||||||
* @param pattern 正则
|
* @param pattern 正则
|
||||||
* @return 判断结果
|
* @return 判断结果
|
||||||
*/
|
*/
|
||||||
private static boolean matchesInternal(@Nullable final CharSequence input, @Nonnull final Pattern pattern) {
|
private static boolean matchesInternal(@Nullable final CharSequence input, final Pattern pattern) {
|
||||||
return input != null && pattern.matcher(input).matches();
|
return input != null && pattern.matcher(input).matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean matchesOneInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) {
|
private static boolean matchesOneInternal(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||||
return input != null
|
return input != null
|
||||||
&& Arrays.stream(patterns)
|
&& Arrays.stream(patterns)
|
||||||
.anyMatch(pattern -> pattern.matcher(input).matches());
|
.anyMatch(pattern -> pattern.matcher(input).matches());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean matchesAllInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) {
|
private static boolean matchesAllInternal(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||||
return input != null
|
return input != null
|
||||||
&& Arrays.stream(patterns)
|
&& Arrays.stream(patterns)
|
||||||
.allMatch(pattern -> pattern.matcher(input).matches());
|
.allMatch(pattern -> pattern.matcher(input).matches());
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2024 the original author or authors.
|
* Copyright 2024-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,16 +16,30 @@
|
|||||||
|
|
||||||
package xyz.zhouxy.plusone.commons.util;
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
@Beta
|
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StringTools
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 字符串工具类。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
public class StringTools {
|
public class StringTools {
|
||||||
|
|
||||||
public static final String EMPTY_STRING = "";
|
public static final String EMPTY_STRING = "";
|
||||||
|
|
||||||
public static boolean isNotBlank(final String cs) {
|
public static boolean isNotBlank(@Nullable final String cs) {
|
||||||
if (cs == null || cs.isEmpty()) {
|
if (cs == null || cs.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -37,15 +51,50 @@ public class StringTools {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isBlank(@Nullable String cs) {
|
||||||
|
if (cs == null || cs.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < cs.length(); i++) {
|
||||||
|
if (!Character.isWhitespace(cs.charAt(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static String repeat(String str, int times) {
|
public static String repeat(String str, int times) {
|
||||||
return repeat(str, times, Integer.MAX_VALUE);
|
return repeat(str, times, Integer.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String repeat(String str, int times, int maxLength) {
|
public static String repeat(final String str, int times, int maxLength) {
|
||||||
AssertTools.checkArgument(Objects.nonNull(str));
|
AssertTools.checkArgument(Objects.nonNull(str));
|
||||||
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isNotEmpty(@Nullable final String cs) {
|
||||||
|
return cs != null && !cs.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmpty(@Nullable final String cs) {
|
||||||
|
return cs == null || cs.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Beta
|
||||||
|
public static boolean isEmail(@Nullable final String cs) {
|
||||||
|
return RegexTools.matches(cs, PatternConsts.EMAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Beta
|
||||||
|
public static boolean isURL(@Nullable final String cs) {
|
||||||
|
try {
|
||||||
|
new URL(cs);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private StringTools() {
|
private StringTools() {
|
||||||
throw new IllegalStateException("Utility class");
|
throw new IllegalStateException("Utility class");
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ public class TreeBuilder<T, TSubTree extends T, TIdentity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TreeBuilder(Function<T, TIdentity> identityGetter, Function<T, Optional<TIdentity>> parentIdentityGetter,
|
public TreeBuilder(Function<T, TIdentity> identityGetter, Function<T, Optional<TIdentity>> parentIdentityGetter,
|
||||||
BiConsumer<TSubTree, T> addChild, Comparator<? super T> defaultComparator) {
|
BiConsumer<TSubTree, T> addChild, @Nullable Comparator<? super T> defaultComparator) {
|
||||||
this.identityGetter = identityGetter;
|
this.identityGetter = identityGetter;
|
||||||
this.parentIdentityGetter = parentIdentityGetter;
|
this.parentIdentityGetter = parentIdentityGetter;
|
||||||
this.addChildMethod = addChild;
|
this.addChildMethod = addChild;
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>工具类</h2>
|
||||||
|
* <p>
|
||||||
|
* 包含树构建器({@link TreeBuilder})、断言工具({@link AssertTools})、ID 生成器({@link IdGenerator})及其它实用工具类。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
*/
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package xyz.zhouxy.plusone.commons.util;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
@@ -36,6 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@SuppressWarnings("null")
|
||||||
public class YearQuarterTests {
|
public class YearQuarterTests {
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
@@ -588,7 +589,7 @@ public class YearQuarterTests {
|
|||||||
Year.MIN_VALUE,
|
Year.MIN_VALUE,
|
||||||
Year.MAX_VALUE,
|
Year.MAX_VALUE,
|
||||||
})
|
})
|
||||||
void of_ValidYearMonth_CreatesYearMnoth_Q1(int year) {
|
void of_ValidYearMonth_CreatesYearMonth_Q1(int year) {
|
||||||
{
|
{
|
||||||
YearMonth yearMonth = YearMonth.of(year, 1);
|
YearMonth yearMonth = YearMonth.of(year, 1);
|
||||||
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
||||||
@@ -619,7 +620,7 @@ public class YearQuarterTests {
|
|||||||
Year.MIN_VALUE,
|
Year.MIN_VALUE,
|
||||||
Year.MAX_VALUE,
|
Year.MAX_VALUE,
|
||||||
})
|
})
|
||||||
void of_ValidYearMonth_CreatesYearMnoth_Q2(int year) {
|
void of_ValidYearMonth_CreatesYearMonth_Q2(int year) {
|
||||||
{
|
{
|
||||||
YearMonth yearMonth = YearMonth.of(year, 4);
|
YearMonth yearMonth = YearMonth.of(year, 4);
|
||||||
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
||||||
@@ -650,7 +651,7 @@ public class YearQuarterTests {
|
|||||||
Year.MIN_VALUE,
|
Year.MIN_VALUE,
|
||||||
Year.MAX_VALUE,
|
Year.MAX_VALUE,
|
||||||
})
|
})
|
||||||
void of_ValidYearMonth_CreatesYearMnoth_Q3(int year) {
|
void of_ValidYearMonth_CreatesYearMonth_Q3(int year) {
|
||||||
{
|
{
|
||||||
YearMonth yearMonth = YearMonth.of(year, 7);
|
YearMonth yearMonth = YearMonth.of(year, 7);
|
||||||
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
||||||
@@ -681,7 +682,7 @@ public class YearQuarterTests {
|
|||||||
Year.MIN_VALUE,
|
Year.MIN_VALUE,
|
||||||
Year.MAX_VALUE,
|
Year.MAX_VALUE,
|
||||||
})
|
})
|
||||||
void of_ValidYearMonth_CreatesYearMnoth_Q4(int year) {
|
void of_ValidYearMonth_CreatesYearMonth_Q4(int year) {
|
||||||
{
|
{
|
||||||
YearMonth yearMonth = YearMonth.of(year, 10);
|
YearMonth yearMonth = YearMonth.of(year, 10);
|
||||||
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
YearQuarter yearQuarter = YearQuarter.of(yearMonth);
|
||||||
@@ -712,7 +713,7 @@ public class YearQuarterTests {
|
|||||||
Year.MIN_VALUE,
|
Year.MIN_VALUE,
|
||||||
Year.MAX_VALUE,
|
Year.MAX_VALUE,
|
||||||
})
|
})
|
||||||
void of_NullYearMonth_CreatesYearMnoth_Q4(int year) {
|
void of_NullYearMonth_CreatesYearMonth_Q4(int year) {
|
||||||
YearMonth yearMonth = null;
|
YearMonth yearMonth = null;
|
||||||
assertThrows(NullPointerException.class,
|
assertThrows(NullPointerException.class,
|
||||||
() -> YearQuarter.of(yearMonth));
|
() -> YearQuarter.of(yearMonth));
|
||||||
|
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@SuppressWarnings("null")
|
||||||
public class BigDecimalsTests {
|
public class BigDecimalsTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -435,32 +435,117 @@ class DateTimeToolsTests {
|
|||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// #region - others
|
// #region - start & end
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void startDateOfYear() {
|
void testStartAndEndDateOfYear() {
|
||||||
assertEquals(LocalDate.of(2008, 1, 1), DateTimeTools.startDateOfYear(2008));
|
assertEquals(LocalDate.of(2008, 1, 1), DateTimeTools.startDateOfYear(2008));
|
||||||
assertEquals(LocalDate.of(2008, 12, 31), DateTimeTools.endDateOfYear(2008));
|
assertEquals(LocalDate.of(2008, 12, 31), DateTimeTools.endDateOfYear(2008));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStartOfNextDate() {
|
||||||
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0),
|
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0),
|
||||||
DateTimeTools.startOfNextDate(LOCAL_DATE));
|
DateTimeTools.startOfNextDate(LOCAL_DATE));
|
||||||
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0).atZone(SYS_ZONE_ID),
|
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0).atZone(SYS_ZONE_ID),
|
||||||
DateTimeTools.startOfNextDate(LOCAL_DATE, SYS_ZONE_ID));
|
DateTimeTools.startOfNextDate(LOCAL_DATE, SYS_ZONE_ID));
|
||||||
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0).atZone(ZONE_ID),
|
assertEquals(LocalDateTime.of(2024, 12, 30, 0, 0, 0).atZone(ZONE_ID),
|
||||||
DateTimeTools.startOfNextDate(LOCAL_DATE, ZONE_ID));
|
DateTimeTools.startOfNextDate(LOCAL_DATE, ZONE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - start & end
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isFuture & isPast
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_isFuture_And_isPast_WhenFuture() {
|
||||||
|
Date date = new Date(Instant.now().plusSeconds(10).toEpochMilli());
|
||||||
|
assertTrue(DateTimeTools.isFuture(date));
|
||||||
|
assertFalse(DateTimeTools.isPast(date));
|
||||||
|
|
||||||
|
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("+01:00"));
|
||||||
|
calendar.add(Calendar.SECOND, 10);
|
||||||
|
assertTrue(DateTimeTools.isFuture(calendar));
|
||||||
|
assertFalse(DateTimeTools.isPast(calendar));
|
||||||
|
|
||||||
|
Instant instant = Instant.now().plusSeconds(10);
|
||||||
|
assertTrue(DateTimeTools.isFuture(instant));
|
||||||
|
assertFalse(DateTimeTools.isPast(instant));
|
||||||
|
|
||||||
|
long timeMillis = Instant.now().plusSeconds(10).toEpochMilli();
|
||||||
|
assertTrue(DateTimeTools.isFuture(timeMillis));
|
||||||
|
assertFalse(DateTimeTools.isPast(timeMillis));
|
||||||
|
|
||||||
|
LocalDate localDate = LocalDate.now().plusDays(1);
|
||||||
|
assertTrue(DateTimeTools.isFuture(localDate));
|
||||||
|
assertFalse(DateTimeTools.isPast(localDate));
|
||||||
|
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(10);
|
||||||
|
assertTrue(DateTimeTools.isFuture(localDateTime));
|
||||||
|
assertFalse(DateTimeTools.isPast(localDateTime));
|
||||||
|
|
||||||
|
ZonedDateTime zonedDateTime = Instant.now().plusSeconds(10).atZone(ZoneId.of("+01:00"));
|
||||||
|
assertTrue(DateTimeTools.isFuture(zonedDateTime));
|
||||||
|
assertFalse(DateTimeTools.isPast(zonedDateTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_isFuture_And_isPast_WhenPast() {
|
||||||
|
Date date = new Date(Instant.now().minusSeconds(10).toEpochMilli());
|
||||||
|
assertFalse(DateTimeTools.isFuture(date));
|
||||||
|
assertTrue(DateTimeTools.isPast(date));
|
||||||
|
|
||||||
|
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("+01:00"));
|
||||||
|
calendar.add(Calendar.SECOND, -10);
|
||||||
|
assertFalse(DateTimeTools.isFuture(calendar));
|
||||||
|
assertTrue(DateTimeTools.isPast(calendar));
|
||||||
|
|
||||||
|
Instant instant = Instant.now().minusSeconds(10);
|
||||||
|
assertFalse(DateTimeTools.isFuture(instant));
|
||||||
|
assertTrue(DateTimeTools.isPast(instant));
|
||||||
|
|
||||||
|
long timeMillis = Instant.now().minusSeconds(10).toEpochMilli();
|
||||||
|
assertFalse(DateTimeTools.isFuture(timeMillis));
|
||||||
|
assertTrue(DateTimeTools.isPast(timeMillis));
|
||||||
|
|
||||||
|
LocalDate localDate = LocalDate.now().minusDays(1);
|
||||||
|
assertFalse(DateTimeTools.isFuture(localDate));
|
||||||
|
assertTrue(DateTimeTools.isPast(localDate));
|
||||||
|
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.now().minusSeconds(10);
|
||||||
|
assertFalse(DateTimeTools.isFuture(localDateTime));
|
||||||
|
assertTrue(DateTimeTools.isPast(localDateTime));
|
||||||
|
|
||||||
|
ZonedDateTime zonedDateTime = Instant.now().minusSeconds(10).atZone(ZoneId.of("+01:00"));
|
||||||
|
assertFalse(DateTimeTools.isFuture(zonedDateTime));
|
||||||
|
assertTrue(DateTimeTools.isPast(zonedDateTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isFuture & isPast
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - others
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void startDateTimeRange() {
|
||||||
Range<LocalDateTime> localDateTimeRange = DateTimeTools.toDateTimeRange(LOCAL_DATE);
|
Range<LocalDateTime> localDateTimeRange = DateTimeTools.toDateTimeRange(LOCAL_DATE);
|
||||||
assertEquals(LOCAL_DATE.atStartOfDay(), localDateTimeRange.lowerEndpoint());
|
assertEquals(LOCAL_DATE.atStartOfDay(), localDateTimeRange.lowerEndpoint());
|
||||||
|
assertEquals(LocalDate.of(2024, 12, 30).atStartOfDay(), localDateTimeRange.upperEndpoint());
|
||||||
assertTrue(localDateTimeRange.contains(LOCAL_DATE.atStartOfDay()));
|
assertTrue(localDateTimeRange.contains(LOCAL_DATE.atStartOfDay()));
|
||||||
assertEquals(LocalDate.of(2024, 12, 30).atStartOfDay(), localDateTimeRange.upperEndpoint());
|
|
||||||
assertEquals(LocalDate.of(2024, 12, 30).atStartOfDay(), localDateTimeRange.upperEndpoint());
|
|
||||||
assertFalse(localDateTimeRange.contains(LocalDate.of(2024, 12, 30).atStartOfDay()));
|
assertFalse(localDateTimeRange.contains(LocalDate.of(2024, 12, 30).atStartOfDay()));
|
||||||
|
|
||||||
Range<ZonedDateTime> zonedDateTimeRange = DateTimeTools.toDateTimeRange(LOCAL_DATE, SYS_ZONE_ID);
|
Range<ZonedDateTime> zonedDateTimeRange = DateTimeTools.toDateTimeRange(LOCAL_DATE, SYS_ZONE_ID);
|
||||||
assertEquals(LOCAL_DATE.atStartOfDay().atZone(SYS_ZONE_ID), zonedDateTimeRange.lowerEndpoint());
|
assertEquals(LOCAL_DATE.atStartOfDay().atZone(SYS_ZONE_ID), zonedDateTimeRange.lowerEndpoint());
|
||||||
|
assertEquals(LocalDate.of(2024, 12, 30).atStartOfDay().atZone(SYS_ZONE_ID), zonedDateTimeRange.upperEndpoint());
|
||||||
assertTrue(zonedDateTimeRange.contains(LOCAL_DATE.atStartOfDay().atZone(SYS_ZONE_ID)));
|
assertTrue(zonedDateTimeRange.contains(LOCAL_DATE.atStartOfDay().atZone(SYS_ZONE_ID)));
|
||||||
assertEquals(ZonedDateTime.of(LocalDate.of(2024, 12, 30).atStartOfDay(), SYS_ZONE_ID), zonedDateTimeRange.upperEndpoint());
|
|
||||||
assertEquals(ZonedDateTime.of(LocalDate.of(2024, 12, 30).atStartOfDay(), SYS_ZONE_ID), zonedDateTimeRange.upperEndpoint());
|
|
||||||
assertFalse(zonedDateTimeRange.contains(LocalDate.of(2024, 12, 30).atStartOfDay().atZone(SYS_ZONE_ID)));
|
assertFalse(zonedDateTimeRange.contains(LocalDate.of(2024, 12, 30).atStartOfDay().atZone(SYS_ZONE_ID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +565,10 @@ class DateTimeToolsTests {
|
|||||||
assertThrows(DateTimeException.class, () -> DateTimeTools.toYearString(Year.MIN_VALUE - 1));
|
assertThrows(DateTimeException.class, () -> DateTimeTools.toYearString(Year.MIN_VALUE - 1));
|
||||||
assertThrows(DateTimeException.class, () -> DateTimeTools.toYearString(Year.MAX_VALUE + 1));
|
assertThrows(DateTimeException.class, () -> DateTimeTools.toYearString(Year.MAX_VALUE + 1));
|
||||||
|
|
||||||
|
assertEquals("2024", DateTimeTools.toYearString(Year.of(2024)));
|
||||||
|
assertEquals("999999999", DateTimeTools.toYearString(Year.of(Year.MAX_VALUE)));
|
||||||
|
assertEquals("-999999999", DateTimeTools.toYearString(Year.of(Year.MIN_VALUE)));
|
||||||
|
|
||||||
assertEquals("01", DateTimeTools.toMonthStringMM(1));
|
assertEquals("01", DateTimeTools.toMonthStringMM(1));
|
||||||
assertEquals("02", DateTimeTools.toMonthStringMM(2));
|
assertEquals("02", DateTimeTools.toMonthStringMM(2));
|
||||||
assertEquals("3", DateTimeTools.toMonthStringM(3));
|
assertEquals("3", DateTimeTools.toMonthStringM(3));
|
||||||
|
@@ -30,7 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings({"deprecation", "null"})
|
||||||
public
|
public
|
||||||
class EnumToolsTests {
|
class EnumToolsTests {
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
/**
|
/**
|
||||||
* {@link OptionalTools} 单元测试
|
* {@link OptionalTools} 单元测试
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("null")
|
||||||
public
|
public
|
||||||
class OptionalToolsTests {
|
class OptionalToolsTests {
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@SuppressWarnings("null")
|
||||||
public
|
public
|
||||||
class RegexToolsTests {
|
class RegexToolsTests {
|
||||||
|
|
||||||
|
@@ -28,9 +28,14 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
public
|
public
|
||||||
class StringToolsTests {
|
class StringToolsTests {
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isNotBlank
|
||||||
|
// ================================
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void isNotBlank_NullString_ReturnsFalse() {
|
void isNotBlank_NullString_ReturnsFalse() {
|
||||||
assertFalse(StringTools.isNotBlank(null));
|
assertFalse(StringTools.isNotBlank(null));
|
||||||
@@ -51,6 +56,206 @@ class StringToolsTests {
|
|||||||
assertTrue(StringTools.isNotBlank("Hello"));
|
assertTrue(StringTools.isNotBlank("Hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isNotBlank
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isBlank
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isBlank_NullString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isBlank(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isBlank_EmptyString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isBlank(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isBlank_WhitespaceString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isBlank(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isBlank_NonWhitespaceString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isBlank("Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isBlank
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isNotEmpty
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isNotEmpty_NullString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isNotEmpty(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isNotEmpty_EmptyString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isNotEmpty(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isNotEmpty_WhitespaceString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isNotEmpty(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isNotEmpty_NonWhitespaceString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isNotEmpty("Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isNotEmpty
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isEmpty
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isEmpty_NullString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isEmpty(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isEmpty_EmptyString_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isEmpty(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isEmpty_WhitespaceString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isEmpty(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isEmpty_NonWhitespaceString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isEmpty("Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isEmpty
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - EMAIL
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidEmails() {
|
||||||
|
assertTrue(StringTools.isEmail("test@example.com"));
|
||||||
|
assertTrue(StringTools.isEmail("user.name+tag+sorting@example.com"));
|
||||||
|
assertTrue(StringTools.isEmail("user@sub.example.com"));
|
||||||
|
assertTrue(StringTools.isEmail("user@123.123.123.123"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidEmails() {
|
||||||
|
assertFalse(StringTools.isEmail(".username@example.com"));
|
||||||
|
assertFalse(StringTools.isEmail("@missingusername.com"));
|
||||||
|
assertFalse(StringTools.isEmail("plainaddress"));
|
||||||
|
assertFalse(StringTools.isEmail("username..username@example.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username.@example.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@-example.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@-example.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@.com.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@.com.my"));
|
||||||
|
assertFalse(StringTools.isEmail("username@.com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@com."));
|
||||||
|
assertFalse(StringTools.isEmail("username@com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@example..com"));
|
||||||
|
assertFalse(StringTools.isEmail("username@example.com-"));
|
||||||
|
assertFalse(StringTools.isEmail("username@example.com."));
|
||||||
|
assertFalse(StringTools.isEmail("username@example"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - EMAIL
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - isURL
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC1: 验证标准HTTP协议URL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_ValidHttpURL_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isURL("http://example.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC2: 验证带路径参数的HTTPS复杂URL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_ValidHttpsComplexURL_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isURL("https://test.com:8080/api/v1?param=value#anchor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC3: 验证FTP协议URL
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_ValidFtpURL_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isURL("ftp://files.example.com/directory/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC4: 验证非法协议处理
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_InvalidProtocol_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isURL("httpx://invalid.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC5: 验证null输入处理
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_NullInput_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isURL(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC6: 验证空字符串处理
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_EmptyString_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isURL(StringTools.EMPTY_STRING));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC7: 验证缺失协议头处理
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_MissingProtocol_ReturnsFalse() {
|
||||||
|
assertFalse(StringTools.isURL("www.example.com/path"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TC8: 验证未编码特殊字符处理
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void isURL_UnencodedSpecialChars_ReturnsTrue() {
|
||||||
|
assertTrue(StringTools.isURL("http://example.com/测试"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - isURL
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #region - repeat
|
||||||
|
// ================================
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void repeat_NullString_ThrowsException() {
|
void repeat_NullString_ThrowsException() {
|
||||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
@@ -89,6 +294,10 @@ class StringToolsTests {
|
|||||||
assertEquals("", StringTools.repeat("Hello", 0));
|
assertEquals("", StringTools.repeat("Hello", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// #endregion - repeat
|
||||||
|
// ================================
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
|
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
|
||||||
Constructor<?>[] constructors = StringTools.class.getDeclaredConstructors();
|
Constructor<?>[] constructors = StringTools.class.getDeclaredConstructors();
|
||||||
|
@@ -39,6 +39,7 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
class TreeBuilderTests {
|
class TreeBuilderTests {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(TreeBuilderTests.class);
|
private static final Logger log = LoggerFactory.getLogger(TreeBuilderTests.class);
|
||||||
|
Reference in New Issue
Block a user