forked from plusone/plusone-commons
Compare commits
1 Commits
d2d824462b
...
feature/ne
Author | SHA1 | Date | |
---|---|---|---|
ddc08da33e |
@@ -1,14 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
# 缩进
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
# 行尾
|
||||
end_of_line = lf
|
||||
# 字符集
|
||||
charset = utf-8
|
||||
# 删除行尾空格
|
||||
trim_trailing_whitespace = true
|
||||
# 文件最后插入空行
|
||||
insert_final_newline = true
|
@@ -1,100 +0,0 @@
|
||||
[x] 无需测试
|
||||
[ ] 未开始测试
|
||||
[-] 测试未完成
|
||||
[Y] 测试完成
|
||||
|
||||
xyz.zhouxy.plusone.commons
|
||||
├───annotation
|
||||
│ ReaderMethod.java [x]
|
||||
│ StaticFactoryMethod.java [x]
|
||||
│ UnsupportedOperation.java [x]
|
||||
│ ValueObject.java [x]
|
||||
│ Virtual.java [x]
|
||||
│ WriterMethod.java [x]
|
||||
│
|
||||
├───base
|
||||
│ BoolRef.java [Y]
|
||||
│ CharRef.java [Y]
|
||||
│ DoubleRef.java [Y]
|
||||
│ IntRef.java [Y]
|
||||
│ IWithCode.java [ ]
|
||||
│ IWithIntCode.java [ ]
|
||||
│ IWithLongCode.java [ ]
|
||||
│ JRE.java [ ]
|
||||
│ LongRef.java [Y]
|
||||
│ Ref.java [Y]
|
||||
│
|
||||
├───collection
|
||||
│ AbstractMapWrapper.java [ ]
|
||||
│ CollectionTools.java [ ]
|
||||
│ MapWrapper.java [ ]
|
||||
│ ReadWriteLockedTable.java [ ]
|
||||
│ SafeConcurrentHashMap.java [ ]
|
||||
│
|
||||
├───constant
|
||||
│ PatternConsts.java [ ]
|
||||
│ RegexConsts.java [ ]
|
||||
│
|
||||
├───exception
|
||||
│ │ ParsingFailureException.java [ ]
|
||||
│ │
|
||||
│ ├───business
|
||||
│ │ BizException.java [ ]
|
||||
│ │ InvalidInputException.java [ ]
|
||||
│ │ RequestParamsException.java [ ]
|
||||
│ │
|
||||
│ └───system
|
||||
│ DataOperationResultException.java [ ]
|
||||
│ NoAvailableMacFoundException.java [ ]
|
||||
│ SysException.java [ ]
|
||||
│
|
||||
├───function
|
||||
│ BoolUnaryOperator.java [ ]
|
||||
│ CharUnaryOperator.java [ ]
|
||||
│ Executable.java [ ]
|
||||
│ OptionalSupplier.java [ ]
|
||||
│ PredicateTools.java [ ]
|
||||
│ ThrowingConsumer.java [ ]
|
||||
│ ThrowingPredicate.java [ ]
|
||||
│ ThrowingSupplier.java [ ]
|
||||
│ ToOptionalBiFunction.java [ ]
|
||||
│ ToOptionalFunction.java [ ]
|
||||
│
|
||||
├───model
|
||||
│ │ Chinese2ndGenIDCardNumber.java [-]
|
||||
│ │ Gender.java [ ]
|
||||
│ │ IDCardNumber.java [ ]
|
||||
│ │ ValidatableStringRecord.java [-]
|
||||
│ │
|
||||
│ └───dto
|
||||
│ PageResult.java [-]
|
||||
│ PagingAndSortingQueryParams.java [-]
|
||||
│ PagingParams.java [-]
|
||||
│ UnifiedResponse.java [-]
|
||||
│
|
||||
├───sql
|
||||
│ JdbcSql.java [ ]
|
||||
│ MyBatisSql.java [-]
|
||||
│ SQL.java [ ]
|
||||
│
|
||||
├───time
|
||||
│ Quarter.java [-]
|
||||
│ YearQuarter.java [-]
|
||||
│
|
||||
└───util
|
||||
ArrayTools.java [-]
|
||||
AssertTools.java [-]
|
||||
BigDecimals.java [-]
|
||||
ConcurrentHashMapTools.java [-]
|
||||
DateTimeTools.java [-]
|
||||
Enumeration.java [Y]
|
||||
EnumTools.java [-]
|
||||
IdGenerator.java [ ]
|
||||
IdWorker.java [ ]
|
||||
Numbers.java [ ]
|
||||
OptionalTools.java [ ]
|
||||
RandomTools.java [ ]
|
||||
RegexTools.java [ ]
|
||||
SnowflakeIdGenerator.java [ ]
|
||||
StringTools.java [ ]
|
||||
TreeBuilder.java [-]
|
98
pom.xml
98
pom.xml
@@ -6,25 +6,44 @@
|
||||
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-commons</artifactId>
|
||||
<version>1.0.0-alpha</version>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<commons-lang3.version>3.17.0</commons-lang3.version>
|
||||
<guava.version>33.3.1-jre</guava.version>
|
||||
<joda-time.version>2.13.0</joda-time.version>
|
||||
<jackson.version>2.13.5</jackson.version>
|
||||
<commons-lang3.version>3.13.0</commons-lang3.version>
|
||||
<guava.version>32.0.1-jre</guava.version>
|
||||
<google-jsr305.version>3.0.2</google-jsr305.version>
|
||||
<joda-time.version>2.12.5</joda-time.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>${google-jsr305.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
@@ -32,15 +51,6 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
@@ -54,18 +64,6 @@
|
||||
<version>5.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
@@ -78,28 +76,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.25</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.13.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Gson -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<version>5.8.21</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -147,29 +124,4 @@
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>aliyun</id>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>aliyun-plugin</id>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -22,13 +22,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标识该方法是可虚方法。
|
||||
* 标识该方法是可覆写的。
|
||||
* <p>该注解用于提醒、强调父类虽然有默认实现,但子类可以根据自己的需要覆写。</p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Virtual {
|
||||
public @interface Overridable {
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -21,15 +5,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* ReaderMethod
|
||||
*
|
||||
* <p>
|
||||
* 标识方法是读方法,如 getter。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
// TODO 添加 Javadoc
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReaderMethod {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <p>标识方法为静态工厂方法
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -22,16 +6,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.Documented;
|
||||
|
||||
/**
|
||||
* UnsupportedOperation
|
||||
*
|
||||
* <p>标识方法为不支持的操作。该方法将抛出 {@link UnsupportedOperationException}。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
* @see UnsupportedOperationException
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package xyz.zhouxy.plusone.commons.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -25,10 +24,9 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* ValueObject - 值对象
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
@Inherited
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ValueObject {
|
||||
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -21,15 +5,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* WriterMethod
|
||||
*
|
||||
* <p>
|
||||
* 标识方法是写方法,如 setter。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
// TODO 添加 Javadoc
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WriterMethod {
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.function.BoolUnaryOperator;
|
||||
|
||||
@Beta
|
||||
public class BoolRef {
|
||||
|
||||
private boolean value;
|
||||
|
||||
public BoolRef(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(BoolUnaryOperator operator) {
|
||||
this.value = operator.applyAsBool(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("BoolRef[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (value ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return value == ((BoolRef) obj).value;
|
||||
}
|
||||
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.function.CharUnaryOperator;
|
||||
|
||||
@Beta
|
||||
public class CharRef {
|
||||
|
||||
private char value;
|
||||
|
||||
public CharRef(char value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public char getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(char value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(CharUnaryOperator operator) {
|
||||
this.value = operator.applyAsChar(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("CharRef[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + value;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return value == ((CharRef) obj).value;
|
||||
}
|
||||
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import java.util.function.DoubleUnaryOperator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class DoubleRef {
|
||||
|
||||
private double value;
|
||||
|
||||
public DoubleRef(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(DoubleUnaryOperator operator) {
|
||||
this.value = operator.applyAsDouble(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("DoubleRef[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(value);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final DoubleRef other = (DoubleRef) obj;
|
||||
return Double.doubleToLongBits(value) == Double.doubleToLongBits(other.value);
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
@@ -25,13 +23,9 @@ import javax.annotation.Nonnull;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IWithCode<T> {
|
||||
@Nonnull
|
||||
T getCode();
|
||||
|
||||
default boolean equalsCode(T code) {
|
||||
return Objects.equals(getCode(), code);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -21,12 +21,8 @@ package xyz.zhouxy.plusone.commons.base;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IWithIntCode {
|
||||
int getCode();
|
||||
|
||||
default boolean equalsCode(int code) {
|
||||
return getCode() == code;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -21,12 +21,8 @@ package xyz.zhouxy.plusone.commons.base;
|
||||
* 用于像自定义异常等需要带有 {@code code} 字段的类,
|
||||
* 方便其它地方的程序判断该类的是否实现了此接口,以此获取其实例的 {@code code} 字段的值。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IWithLongCode {
|
||||
long getCode();
|
||||
|
||||
default boolean equalsCode(long code) {
|
||||
return getCode() == code;
|
||||
}
|
||||
}
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import java.util.function.IntUnaryOperator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class IntRef {
|
||||
|
||||
private int value;
|
||||
|
||||
public IntRef(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(IntUnaryOperator operator) {
|
||||
this.value = operator.applyAsInt(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("IntRef[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + value;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return value == ((IntRef) obj).value;
|
||||
}
|
||||
|
||||
}
|
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
*
|
||||
* 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
|
||||
* http://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,
|
||||
@@ -16,7 +17,8 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
|
||||
/**
|
||||
* JRE version
|
||||
@@ -33,30 +35,23 @@ public class JRE {
|
||||
|
||||
private static int getJre() {
|
||||
String version = System.getProperty("java.version");
|
||||
boolean isNotBlank = StringTools.isNotBlank(version);
|
||||
if (isNotBlank && version.startsWith("1.8")) {
|
||||
boolean isBlank = StringUtils.isBlank(version);
|
||||
if (!isBlank && version.startsWith("1.8")) {
|
||||
return JAVA_8;
|
||||
}
|
||||
// if JRE version is 9 or above, we can get version from
|
||||
// java.lang.Runtime.version()
|
||||
try {
|
||||
return getMajorVersion(version);
|
||||
Object javaRunTimeVersion = MethodUtils.invokeMethod(Runtime.getRuntime(), "version");
|
||||
return (int) MethodUtils.invokeMethod(javaRunTimeVersion, "major");
|
||||
} catch (Exception e) {
|
||||
// Can't determine current JRE version (maybe java.version is null),
|
||||
// assuming that JRE version is 8.
|
||||
}
|
||||
// default java 8
|
||||
return JAVA_8;
|
||||
}
|
||||
|
||||
private static int getMajorVersion(String version) {
|
||||
if (version.startsWith("1.")) {
|
||||
return Integer.parseInt(version.substring(2, 3));
|
||||
} else {
|
||||
int dotIndex = version.indexOf(".");
|
||||
return (dotIndex != -1) ? Integer.parseInt(version.substring(0, dotIndex)) : Integer.parseInt(version);
|
||||
}
|
||||
}
|
||||
|
||||
private JRE() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import java.util.function.LongUnaryOperator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class LongRef {
|
||||
|
||||
private long value;
|
||||
|
||||
public LongRef(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(LongUnaryOperator operator) {
|
||||
this.value = operator.applyAsLong(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("LongRef[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (int) (value ^ (value >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return value == ((LongRef) obj).value;
|
||||
}
|
||||
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public final class Ref<T> {
|
||||
|
||||
private T value;
|
||||
|
||||
public Ref() {
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
public Ref(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void transform(UnaryOperator<T> operator) {
|
||||
this.value = operator.apply(this.value);
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return this.value == null;
|
||||
}
|
||||
|
||||
public boolean isNotNull() {
|
||||
return this.value != null;
|
||||
}
|
||||
|
||||
public void execute(Consumer<? super T> consumer) {
|
||||
consumer.accept(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Ref[%s]", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Ref<?> other = (Ref<?>) obj;
|
||||
return Objects.equals(this.value, other.value);
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -20,7 +20,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -31,7 +30,7 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapTools;
|
||||
import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapUtil;
|
||||
|
||||
@Beta
|
||||
public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V, T>> {
|
||||
@@ -58,7 +57,9 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
}
|
||||
|
||||
public final T putAll(Map<? extends K, ? extends V> m) {
|
||||
m.forEach(this::put);
|
||||
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return getSelf();
|
||||
}
|
||||
|
||||
@@ -78,6 +79,21 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
return Optional.ofNullable(this.map.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@code map} 中的值。如果 {@code key} 不存在,则抛出异常。
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
* @throws IllegalArgumentException key 不存在时抛出。
|
||||
*/
|
||||
@Nullable
|
||||
public V getOrNull(K key) {
|
||||
if (!this.map.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Key does not exist");
|
||||
}
|
||||
return this.map.get(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <R> Optional<R> getAndConvert(K key) {
|
||||
return get(key).map(v -> (R) v);
|
||||
@@ -124,31 +140,15 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
}
|
||||
|
||||
public final V putIfAbsent(K key, V value) {
|
||||
if (this.keyChecker != null) {
|
||||
this.keyChecker.accept(key);
|
||||
}
|
||||
if (this.valueChecker != null) {
|
||||
this.valueChecker.accept(value);
|
||||
}
|
||||
return this.map.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
public final V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
if (this.keyChecker != null) {
|
||||
this.keyChecker.accept(key);
|
||||
}
|
||||
Function<? super K, ? extends V> func = (K k) -> {
|
||||
V value = mappingFunction.apply(k);
|
||||
if (this.valueChecker != null) {
|
||||
this.valueChecker.accept(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
if (this.map instanceof ConcurrentHashMap) {
|
||||
return ConcurrentHashMapTools.computeIfAbsent(
|
||||
(ConcurrentHashMap<K, V>) this.map, key, func);
|
||||
return ConcurrentHashMapUtil.computeIfAbsent(
|
||||
(ConcurrentHashMap<K, V>) this.map, key, mappingFunction);
|
||||
} else {
|
||||
return this.map.computeIfAbsent(key, func);
|
||||
return this.map.computeIfAbsent(key, mappingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
return this.map;
|
||||
}
|
||||
|
||||
public final Map<K, V> exportUnmodifiableMap() {
|
||||
public final Map<K, V> exportUnmodifiableMapMap() {
|
||||
return Collections.unmodifiableMap(this.map);
|
||||
}
|
||||
|
||||
@@ -167,24 +167,6 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
return this.map.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
@SuppressWarnings("rawtypes")
|
||||
AbstractMapWrapper other = (AbstractMapWrapper) obj;
|
||||
return Objects.equals(map, other.map);
|
||||
}
|
||||
|
||||
public abstract static class Builder<K, V, T extends AbstractMapWrapper<K, V, T>> {
|
||||
protected final Map<K, V> map;
|
||||
protected Consumer<K> keyChecker;
|
||||
@@ -216,7 +198,9 @@ public abstract class AbstractMapWrapper<K, V, T extends AbstractMapWrapper<K, V
|
||||
}
|
||||
|
||||
public Builder<K, V, T> putAll(Map<? extends K, ? extends V> m) {
|
||||
m.forEach(this::put);
|
||||
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.collection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class CollectionTools {
|
||||
|
||||
// isEmpty
|
||||
|
||||
public static boolean isEmpty(@Nullable Collection<?> collection) {
|
||||
return collection == null || collection.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isEmpty(@Nullable Map<?, ?> map) {
|
||||
return map == null || map.isEmpty();
|
||||
}
|
||||
|
||||
// isNotEmpty
|
||||
|
||||
public static boolean isNotEmpty(@Nullable Collection<?> collection) {
|
||||
return collection != null && !collection.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isNotEmpty(@Nullable Map<?, ?> map) {
|
||||
return map != null && !map.isEmpty();
|
||||
}
|
||||
|
||||
private CollectionTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.collection;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
@@ -22,8 +6,6 @@ import com.google.common.collect.Table;
|
||||
import xyz.zhouxy.plusone.commons.annotation.ReaderMethod;
|
||||
import xyz.zhouxy.plusone.commons.annotation.WriterMethod;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -46,47 +28,46 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
* <b>NOTE: 如果 {@link Table} 不需要更改,请使用 {@link ImmutableTable}</b>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108/">ZhouXY</a>
|
||||
* @see Table
|
||||
* @see ImmutableTable
|
||||
* @see ReentrantReadWriteLock
|
||||
* @since 0.1.0-SNAPSHOT
|
||||
*/
|
||||
@Beta
|
||||
@ThreadSafe
|
||||
public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
public class LockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
private final Table<R, C, V> table;
|
||||
|
||||
private final ReentrantReadWriteLock.ReadLock readLock;
|
||||
private final ReentrantReadWriteLock.WriteLock writeLock;
|
||||
|
||||
private ReadWriteLockedTable(Table<R, C, V> table, boolean fair) {
|
||||
private LockedTable(Table<R, C, V> table, boolean fair) {
|
||||
this.table = Objects.requireNonNull(table);
|
||||
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(fair);
|
||||
this.readLock = rwl.readLock();
|
||||
this.writeLock = rwl.writeLock();
|
||||
}
|
||||
|
||||
public static <R, C, V> ReadWriteLockedTable<R, C, V> of(Table<R, C, V> table) {
|
||||
if (table instanceof ReadWriteLockedTable) {
|
||||
return (ReadWriteLockedTable<R, C, V>) table;
|
||||
public static <R, C, V> LockedTable<R, C, V> of(Table<R, C, V> table) {
|
||||
if (table instanceof LockedTable) {
|
||||
return (LockedTable<R, C, V>) table;
|
||||
} else {
|
||||
return new ReadWriteLockedTable<>(table, false);
|
||||
return new LockedTable<>(table, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static <R, C, V> ReadWriteLockedTable<R, C, V> of(Table<R, C, V> table, boolean fair) {
|
||||
if (table instanceof ReadWriteLockedTable) {
|
||||
return (ReadWriteLockedTable<R, C, V>) table;
|
||||
public static <R, C, V> LockedTable<R, C, V> of(Table<R, C, V> table, boolean fair) {
|
||||
if (table instanceof LockedTable) {
|
||||
return (LockedTable<R, C, V>) table;
|
||||
} else {
|
||||
return new ReadWriteLockedTable<>(table, fair);
|
||||
return new LockedTable<>(table, fair);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public boolean contains(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) {
|
||||
public boolean contains(Object rowKey, Object columnKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.contains(rowKey, columnKey);
|
||||
@@ -97,7 +78,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public boolean containsRow(@CheckForNull @Nonnull Object rowKey) {
|
||||
public boolean containsRow(Object rowKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.containsRow(rowKey);
|
||||
@@ -108,7 +89,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public boolean containsColumn(@CheckForNull @Nonnull Object columnKey) {
|
||||
public boolean containsColumn(Object columnKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.containsColumn(columnKey);
|
||||
@@ -119,7 +100,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public boolean containsValue(@CheckForNull @Nonnull Object value) {
|
||||
public boolean containsValue(Object value) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.containsValue(value);
|
||||
@@ -130,7 +111,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public V get(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) {
|
||||
public V get(Object rowKey, Object columnKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.get(rowKey, columnKey);
|
||||
@@ -174,9 +155,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@WriterMethod
|
||||
public V put(@CheckForNull @Nonnull R rowKey,
|
||||
@CheckForNull @Nonnull C columnKey,
|
||||
@CheckForNull @Nonnull V value) {
|
||||
public V put(R rowKey, C columnKey, V value) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return this.table.put(rowKey, columnKey, value);
|
||||
@@ -187,7 +166,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@WriterMethod
|
||||
public void putAll(@Nonnull Table<? extends R, ? extends C, ? extends V> table) {
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
this.table.putAll(table);
|
||||
@@ -198,7 +177,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@WriterMethod
|
||||
public V remove(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) {
|
||||
public V remove(Object rowKey, Object columnKey) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return this.table.remove(rowKey, columnKey);
|
||||
@@ -209,7 +188,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public Map<C, V> row(@CheckForNull @Nonnull R rowKey) {
|
||||
public Map<C, V> row(R rowKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.row(rowKey);
|
||||
@@ -220,7 +199,7 @@ public class ReadWriteLockedTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
@ReaderMethod
|
||||
public Map<R, V> column(@CheckForNull @Nonnull C columnKey) {
|
||||
public Map<R, V> column(C columnKey) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.table.column(columnKey);
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -22,21 +22,9 @@ import java.util.function.Function;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.JRE;
|
||||
import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapTools;
|
||||
import xyz.zhouxy.plusone.commons.util.ConcurrentHashMapUtil;
|
||||
|
||||
/**
|
||||
* SafeConcurrentHashMap
|
||||
*
|
||||
* <p>
|
||||
* Java 8 的 {@link ConcurrentHashMap#computeIfAbsent(Object, Function)} 方法有 bug,
|
||||
* 使用 Java 8 时,可使用这个类进行替换。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0
|
||||
* @see ConcurrentHashMap
|
||||
* @see ConcurrentHashMapTools#computeIfAbsentForJava8(ConcurrentHashMap, Object, Function)
|
||||
*/
|
||||
// TODO 添加文档注释
|
||||
@ThreadSafe
|
||||
public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
||||
|
||||
@@ -114,8 +102,6 @@ public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
return JRE.isJava8()
|
||||
? ConcurrentHashMapTools.computeIfAbsentForJava8(this, key, mappingFunction)
|
||||
: super.computeIfAbsent(key, mappingFunction);
|
||||
return ConcurrentHashMapUtil.computeIfAbsentForJava8(this, key, mappingFunction);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,205 @@
|
||||
package xyz.zhouxy.plusone.commons.collection;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
/**
|
||||
* 将 {@link Table} 包装为同步集合,线程安全。
|
||||
*
|
||||
* <p>
|
||||
* 可通过以下方式构建一个线程安全的 {@link Table}
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* SynchronizedTable.of(HashBasedTable.create())
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 如果 {@link Table} 不需要更改,请使用 {@link ImmutableTable}</b>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108/">ZhouXY</a>
|
||||
* @since 0.1.0-SNAPSHOT
|
||||
* @see Table
|
||||
* @see ImmutableTable
|
||||
*/
|
||||
@Beta
|
||||
@ThreadSafe
|
||||
public class SynchronizedTable<R, C, V> implements Table<R, C, V>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3716653837549439569L;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private final Table<R, C, V> table;
|
||||
@SuppressWarnings("serial")
|
||||
private final Object mutex;
|
||||
|
||||
private SynchronizedTable(Table<R, C, V> table) {
|
||||
this.table = Objects.requireNonNull(table);
|
||||
this.mutex = this;
|
||||
}
|
||||
|
||||
private SynchronizedTable(Table<R, C, V> table, Object mutex) {
|
||||
this.table = Objects.requireNonNull(table);
|
||||
this.mutex = mutex;
|
||||
}
|
||||
|
||||
public static <R, C, V> SynchronizedTable<R, C, V> of(Table<R, C, V> table) {
|
||||
if (table instanceof SynchronizedTable) {
|
||||
return (SynchronizedTable<R, C, V>) table;
|
||||
} else {
|
||||
return new SynchronizedTable<>(table);
|
||||
}
|
||||
}
|
||||
|
||||
public static <R, C, V> SynchronizedTable<R, C, V> of(Table<R, C, V> table, Object mutex) {
|
||||
if (table instanceof SynchronizedTable) {
|
||||
SynchronizedTable<R, C, V> srcTable = (SynchronizedTable<R, C, V>) table;
|
||||
return new SynchronizedTable<>(srcTable.table, mutex);
|
||||
} else {
|
||||
return new SynchronizedTable<>(table);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object rowKey, Object columnKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.contains(rowKey, columnKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRow(Object rowKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.containsRow(rowKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsColumn(Object columnKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.containsColumn(columnKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
synchronized (mutex) {
|
||||
return this.table.containsValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object rowKey, Object columnKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.get(rowKey, columnKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
synchronized (mutex) {
|
||||
return this.table.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
synchronized (mutex) {
|
||||
return this.table.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (mutex) {
|
||||
this.table.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(R rowKey, C columnKey, V value) {
|
||||
synchronized (mutex) {
|
||||
return this.table.put(rowKey, columnKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
synchronized (mutex) {
|
||||
this.table.putAll(table);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object rowKey, Object columnKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.remove(rowKey, columnKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, V> row(R rowKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.row(rowKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<R, V> column(C columnKey) {
|
||||
synchronized (mutex) {
|
||||
return this.table.column(columnKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Cell<R, C, V>> cellSet() {
|
||||
synchronized (mutex) {
|
||||
return this.table.cellSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<R> rowKeySet() {
|
||||
synchronized (mutex) {
|
||||
return this.table.rowKeySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<C> columnKeySet() {
|
||||
synchronized (mutex) {
|
||||
return this.table.columnKeySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
synchronized (mutex) {
|
||||
return this.table.values();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<R, Map<C, V>> rowMap() {
|
||||
synchronized (mutex) {
|
||||
return this.table.rowMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, Map<R, V>> columnMap() {
|
||||
synchronized (mutex) {
|
||||
return this.table.columnMap();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -21,13 +21,11 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* 正则表达式常量
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public final class PatternConsts {
|
||||
|
||||
// TODO 【添加】 新增身份证等正则常量
|
||||
|
||||
public static final Pattern DATE = Pattern.compile(RegexConsts.DATE); // TODO 【优化】 修改为对应的日期格式名称
|
||||
public static final Pattern DATE = Pattern.compile(RegexConsts.DATE);
|
||||
|
||||
public static final Pattern PASSWORD = Pattern.compile(RegexConsts.PASSWORD);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -19,15 +19,11 @@ package xyz.zhouxy.plusone.commons.constant;
|
||||
/**
|
||||
* 正则表达式常量
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public final class RegexConsts {
|
||||
|
||||
// TODO 【优化】 根据需要添加 group
|
||||
|
||||
// TODO 【添加】 新增身份证等正则常量
|
||||
|
||||
public static final String DATE = "^\\d{4}-\\d{2}-\\d{2}"; // TODO 【优化】 修改为对应的日期格式名称
|
||||
public static final String DATE = "^\\d{4}-\\d{2}-\\d{2}";
|
||||
|
||||
public static final String PASSWORD = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[\\w\\\\!#$%&'*\\+\\-/=?^`{|}~@\\(\\)\\[\\]\",\\.;':><]{8,32}$";
|
||||
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.domain;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.RegexUtil;
|
||||
|
||||
/**
|
||||
* 带校验的字符串值对象
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class ValidatableStringRecord {
|
||||
private final String value;
|
||||
|
||||
protected ValidatableStringRecord(String value, Pattern pattern) {
|
||||
Preconditions.checkNotNull(pattern, "The pattern must not be null.");
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(value), "The value must be has text.");
|
||||
Preconditions.checkArgument(RegexUtil.matches(value, pattern));
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 值对象的字符串值。
|
||||
*
|
||||
* @return 字符串(不为空)
|
||||
*/
|
||||
@JsonValue
|
||||
public final String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value();
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 带错误码的异常。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public abstract class BaseException
|
||||
extends RuntimeException
|
||||
implements IWithCode<String> {
|
||||
|
||||
private static final long serialVersionUID = -2546365325001947203L;
|
||||
|
||||
@Nonnull
|
||||
private final String code;
|
||||
|
||||
protected BaseException(String code, String msg) {
|
||||
super(msg);
|
||||
this.code = Objects.requireNonNull(code);
|
||||
}
|
||||
|
||||
protected BaseException(String code, Throwable cause) {
|
||||
super(cause);
|
||||
this.code = Objects.requireNonNull(code);
|
||||
}
|
||||
|
||||
protected BaseException(String code, String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.code = Objects.requireNonNull(code);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public final String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
}
|
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception;
|
||||
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
/**
|
||||
* 解析失败异常
|
||||
*
|
||||
* <p>
|
||||
* 解析失败的不一定是客户传的参数,也可能是其它来源的数据解析失败
|
||||
* 如果表示用户传参造成的解析失败,可使用 RequestParamsException(Throwable cause),
|
||||
* 将 ParsingFailureException 包装成 {@link RequestParamsException} 再抛出
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class ParsingFailureException extends RuntimeException {
|
||||
|
||||
private final Type type;
|
||||
|
||||
private ParsingFailureException(Type type) {
|
||||
super(type.getDefaultMsg());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private ParsingFailureException(Type type, String msg) {
|
||||
super(msg);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private ParsingFailureException(Type type, Throwable cause) {
|
||||
super(cause);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private ParsingFailureException(Type type, String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(Type type) {
|
||||
return new ParsingFailureException(type);
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(Type type, String msg) {
|
||||
return new ParsingFailureException(type, msg);
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(Type type, Throwable e) {
|
||||
return new ParsingFailureException(type, e);
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(Type type, String msg, Throwable e) {
|
||||
return new ParsingFailureException(type, msg, e);
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(DateTimeParseException e) {
|
||||
return new ParsingFailureException(Type.DATE_TIME_PARSING_FAILURE, e.getMessage(), e);
|
||||
}
|
||||
|
||||
public static ParsingFailureException of(String msg, DateTimeParseException e) {
|
||||
return new ParsingFailureException(Type.DATE_TIME_PARSING_FAILURE, msg, e);
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
DEFAULT("4010500", "解析失败"),
|
||||
NUMBER_PARSING_FAILURE("4010501", "数字转换失败"),
|
||||
DATE_TIME_PARSING_FAILURE("4010502", "时间解析失败"),
|
||||
JSON_PARSING_FAILURE("4010503", "JSON 解析失败"),
|
||||
XML_PARSING_FAILURE("4010504", "XML 解析失败"),
|
||||
;
|
||||
|
||||
final String code;
|
||||
final String defaultMsg;
|
||||
|
||||
Type(String code, String defaultMsg) {
|
||||
this.code = code;
|
||||
this.defaultMsg = defaultMsg;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDefaultMsg() {
|
||||
return defaultMsg;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.business;
|
||||
|
||||
/**
|
||||
* BizException
|
||||
*
|
||||
* <p>
|
||||
* 业务异常
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 通常表示业务中的意外情况。如:用户错误输入、缺失必填字段、用户余额不足等。</b>
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public class BizException extends RuntimeException {
|
||||
|
||||
private static final String DEFAULT_MSG = "业务异常";
|
||||
|
||||
public BizException() {
|
||||
super(DEFAULT_MSG);
|
||||
}
|
||||
|
||||
public BizException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public BizException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public BizException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.business;
|
||||
|
||||
/**
|
||||
* InvalidInputException
|
||||
*
|
||||
* <p>
|
||||
* 用户输入内容非法
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 属业务异常</b>
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class InvalidInputException extends RequestParamsException {
|
||||
|
||||
private final Type type;
|
||||
|
||||
private InvalidInputException(Type type) {
|
||||
super(type.getDefaultMsg());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private InvalidInputException(Type type, String msg) {
|
||||
super(msg);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private InvalidInputException(Type type, Throwable cause) {
|
||||
super(cause);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private InvalidInputException(Type type, String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static InvalidInputException of(Type type) {
|
||||
return new InvalidInputException(type);
|
||||
}
|
||||
|
||||
public static InvalidInputException of(Type type, String msg) {
|
||||
return new InvalidInputException(type, msg);
|
||||
}
|
||||
|
||||
public static InvalidInputException of(Type type, Throwable e) {
|
||||
return new InvalidInputException(type, e);
|
||||
}
|
||||
|
||||
public static InvalidInputException of(Type type, String msg, Throwable e) {
|
||||
return new InvalidInputException(type, msg, e);
|
||||
}
|
||||
|
||||
public static InvalidInputException of(Throwable e) {
|
||||
return new InvalidInputException(Type.DEFAULT, e.getMessage(), e);
|
||||
}
|
||||
|
||||
public static InvalidInputException of(String msg, Throwable e) {
|
||||
return new InvalidInputException(Type.DEFAULT, msg, e);
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
DEFAULT("00", "用户输入内容非法"),
|
||||
CONTAINS_ILLEGAL_AND_MALICIOUS_LINKS("01", "包含非法恶意跳转链接"),
|
||||
CONTAINS_ILLEGAL_WORDS("02", "包含违禁敏感词"),
|
||||
PICTURE_CONTAINS_ILLEGAL_INFORMATION("03", "图片包含违禁信息"),
|
||||
INFRINGE_COPYRIGHT("04", "文件侵犯版权"),
|
||||
;
|
||||
|
||||
final String code;
|
||||
final String defaultMsg;
|
||||
|
||||
Type(String code, String defaultMsg) {
|
||||
this.code = code;
|
||||
this.defaultMsg = defaultMsg;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDefaultMsg() {
|
||||
return defaultMsg;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.business;
|
||||
|
||||
/**
|
||||
* RequestParamsException
|
||||
*
|
||||
* <p>
|
||||
* 用户请求参数错误
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public class RequestParamsException extends BizException {
|
||||
|
||||
private static final String DEFAULT_MSG = "用户请求参数错误";
|
||||
|
||||
public RequestParamsException() {
|
||||
super(DEFAULT_MSG);
|
||||
}
|
||||
|
||||
public RequestParamsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public RequestParamsException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public RequestParamsException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.system;
|
||||
|
||||
/**
|
||||
* DataOperationResultException
|
||||
*
|
||||
* <p>
|
||||
* 当数据操作的结果不符合预期时抛出。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 比如当一个 insert 或 update 操作时,预计影响数据库中的一行数据,但结果却影响了零条数据或多条数据,
|
||||
* 当出现这种始料未及的诡异情况时,抛出 {@link DataOperationResultException} 并回滚事务。
|
||||
* 后续需要排查原因。
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public final class DataOperationResultException extends SysException {
|
||||
|
||||
private static final String DEFAULT_MSG = "数据操作的结果不符合预期";
|
||||
|
||||
public DataOperationResultException() {
|
||||
super(DEFAULT_MSG);
|
||||
}
|
||||
|
||||
public DataOperationResultException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public DataOperationResultException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DataOperationResultException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.system;
|
||||
|
||||
/**
|
||||
* NoAvailableMacFoundException
|
||||
*
|
||||
* <p>
|
||||
* 在无法找到可访问的 Mac 地址时抛出
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public class NoAvailableMacFoundException extends SysException {
|
||||
private static final long serialVersionUID = 152827098461071551L;
|
||||
|
||||
public NoAvailableMacFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NoAvailableMacFoundException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public NoAvailableMacFoundException(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public NoAvailableMacFoundException(String msg, Throwable e) {
|
||||
super(msg, e);
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.exception.system;
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*
|
||||
* <p>
|
||||
* 通常表示应用代码存在问题,或因环境问题,引发异常。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public class SysException extends RuntimeException {
|
||||
|
||||
private static final String DEFAULT_MSG = "系统异常";
|
||||
|
||||
protected SysException() {
|
||||
super(DEFAULT_MSG);
|
||||
}
|
||||
|
||||
public SysException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public SysException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public SysException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.DoubleFunction;
|
||||
|
||||
/**
|
||||
* DoubleToOptionalFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 double 的参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see DoubleFunction
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DoubleToOptionalFunction<R> extends DoubleFunction<Optional<R>> {
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
/**
|
||||
* IntToOptionalFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 int 的参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see IntFunction
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IntToOptionalFunction<R> extends IntFunction<Optional<R>> {
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
/**
|
||||
* LongToOptionalFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 long 的参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see LongFunction
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface LongToOptionalFunction<R> extends LongFunction<Optional<R>> {
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* OptionalDoubleSupplier
|
||||
*
|
||||
* <p>
|
||||
* 返回 {@link OptionalDouble} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalDouble
|
||||
* @see Supplier
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ThrowingConsumer<T, E extends Throwable> {
|
||||
|
||||
/**
|
||||
* Consume the supplied argument, potentially throwing an exception.
|
||||
*
|
||||
* @param t the argument to consume
|
||||
*/
|
||||
void accept(T t) throws E;
|
||||
|
||||
public interface OptionalDoubleSupplier extends Supplier<OptionalDouble> {
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,9 +16,20 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* OptionalIntSupplier
|
||||
*
|
||||
* <p>
|
||||
* 返回 {@link OptionalInt} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalInt
|
||||
* @see Supplier
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Executable<E extends Throwable> {
|
||||
|
||||
void execute() throws E;
|
||||
|
||||
public interface OptionalIntSupplier extends Supplier<OptionalInt> {
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,10 +16,20 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Beta
|
||||
/**
|
||||
* OptionalLongSupplier
|
||||
*
|
||||
* <p>
|
||||
* 返回 {@link OptionalLong} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalLong
|
||||
* @see Supplier
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CharUnaryOperator {
|
||||
char applyAsChar(char operand);
|
||||
public interface OptionalLongSupplier extends Supplier<OptionalLong> {
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -25,7 +25,7 @@ import java.util.function.Supplier;
|
||||
* <p>
|
||||
* 返回 {@code Optional<T>} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see Supplier
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -25,11 +25,11 @@ import java.util.function.Predicate;
|
||||
* {@link Predicate} 相关操作。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Predicate
|
||||
*/
|
||||
public class PredicateTools {
|
||||
public class Predicates {
|
||||
|
||||
/**
|
||||
* 将 lambda 表达式或者方法引用指明为对应类型的 {@link Predicate} 对象。
|
||||
@@ -38,19 +38,19 @@ public class PredicateTools {
|
||||
* 等方法,连接其它 {@code Predicate<? super T>} 对象。
|
||||
*
|
||||
* <pre>
|
||||
* Predicate<String> predicate = PredicateTools.<String>from(Objects::nonNull)
|
||||
* Predicate<String> predicate = Predicates.<String>of(Objects::nonNull)
|
||||
* .and(StringUtils::isNotEmpty);
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> 目标类型
|
||||
* @param predicate Lambda 表达式
|
||||
* @return 传入的表达式自动成为 {@link Predicate} 实例
|
||||
* @param predicate 原 {@link Predicate} 实例
|
||||
* @return 包装的 {@link Predicate} 实例
|
||||
*/
|
||||
public static <T> Predicate<T> from(Predicate<T> predicate) {
|
||||
return predicate;
|
||||
public static <T> Predicate<T> of(Predicate<? super T> predicate) {
|
||||
return predicate::test;
|
||||
}
|
||||
|
||||
private PredicateTools() {
|
||||
private Predicates() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
public interface ThrowingPredicate<T, E extends Throwable> {
|
||||
|
||||
/**
|
||||
* Evaluates this predicate on the given argument.
|
||||
*
|
||||
* @param t the input argument
|
||||
* @return {@code true} if the input argument matches the predicate,
|
||||
* otherwise {@code false}
|
||||
*/
|
||||
boolean test(T t) throws E;
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ThrowingSupplier<T, E extends Throwable> {
|
||||
|
||||
/**
|
||||
* Get a result, potentially throwing an exception.
|
||||
*
|
||||
* @return a result
|
||||
*/
|
||||
T get() throws E;
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -25,7 +25,7 @@ import java.util.function.BiFunction;
|
||||
* <p>
|
||||
* 接受类型为 T 和 U 的两个参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see BiFunction
|
||||
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* ToOptionalDoubleFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 T 的参数,返回 {@link OptionalDouble} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalDouble
|
||||
* @see Function
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ToOptionalDoubleFunction<T> extends Function<T, OptionalDouble> {
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -25,7 +25,7 @@ import java.util.function.Function;
|
||||
* <p>
|
||||
* 接受类型为 T 的参数,返回 {@code Optional<R>} 对象。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see Function
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Beta
|
||||
/**
|
||||
* ToOptionalIntFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 T 的参数,返回 {@link OptionalInt} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalInt
|
||||
* @see Function
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BoolUnaryOperator {
|
||||
boolean applyAsBool(boolean operand);
|
||||
|
||||
static BoolUnaryOperator not() {
|
||||
return b -> !b;
|
||||
}
|
||||
public interface ToOptionalIntFunction<T> extends Function<T, OptionalInt> {
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* ToOptionalLongFunction
|
||||
*
|
||||
* <p>
|
||||
* 接受类型为 T 的参数,返回 {@link OptionalLong} 对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see OptionalLong
|
||||
* @see Function
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ToOptionalLongFunction<T> extends Function<T, OptionalLong> {
|
||||
}
|
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* 中国第二代居民身份证号
|
||||
*/
|
||||
public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
||||
|
||||
/** 省份编码 */
|
||||
private final String provinceCode;
|
||||
/** 市级编码 */
|
||||
private final String cityCode;
|
||||
/** 县级编码 */
|
||||
private final String countyCode;
|
||||
/** 性别 */
|
||||
private final Gender gender;
|
||||
/** 出生日期 */
|
||||
private final LocalDate birthDate;
|
||||
|
||||
public static final Pattern PATTERN = Pattern.compile("^(((\\d{2})\\d{2})\\d{2})(\\d{8})\\d{2}(\\d)([\\dXx])$");
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private Chinese2ndGenIDCardNumber(String idNumber) {
|
||||
super(idNumber, PATTERN, "Invalid ID number");
|
||||
|
||||
try {
|
||||
final Matcher matcher = getMatcher();
|
||||
this.provinceCode = matcher.group(3);
|
||||
this.cityCode = matcher.group(2);
|
||||
this.countyCode = matcher.group(1);
|
||||
|
||||
// 性别
|
||||
final String genderStr = matcher.group(5);
|
||||
final int genderIndex = Integer.parseInt(genderStr);
|
||||
this.gender = genderIndex % 2 == 0 ? Gender.FEMALE : Gender.MALE;
|
||||
|
||||
// 出生日期
|
||||
final String birthDateStr = matcher.group(4);
|
||||
this.birthDate = LocalDate.parse(birthDateStr, DATE_FORMATTER);
|
||||
}
|
||||
catch (DateTimeParseException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chinese2ndGenIDCardNumber of(String idNumber) {
|
||||
return new Chinese2ndGenIDCardNumber(idNumber);
|
||||
}
|
||||
|
||||
public String getProvinceCode() {
|
||||
return provinceCode;
|
||||
}
|
||||
|
||||
public String getProvinceName() {
|
||||
return PROVINCE_CODES.get(this.provinceCode);
|
||||
}
|
||||
|
||||
public String getFullProvinceCode() {
|
||||
return Strings.padEnd(this.provinceCode, 12, '0');
|
||||
}
|
||||
|
||||
public String getCityCode() {
|
||||
return cityCode;
|
||||
}
|
||||
|
||||
public String getFullCityCode() {
|
||||
return Strings.padEnd(this.cityCode, 12, '0');
|
||||
}
|
||||
|
||||
public String getCountyCode() {
|
||||
return countyCode;
|
||||
}
|
||||
|
||||
public String getFullCountyCode() {
|
||||
return Strings.padEnd(this.countyCode, 12, '0');
|
||||
}
|
||||
|
||||
@Override
|
||||
public Gender getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getBirthDate() {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 省份代码表
|
||||
*/
|
||||
public static final Map<String, String> PROVINCE_CODES;
|
||||
|
||||
static {
|
||||
PROVINCE_CODES = ImmutableMap.<String, String>builder()
|
||||
.put("11", "北京")
|
||||
.put("12", "天津")
|
||||
.put("13", "河北")
|
||||
.put("14", "山西")
|
||||
.put("15", "内蒙古")
|
||||
.put("21", "辽宁")
|
||||
.put("22", "吉林")
|
||||
.put("23", "黑龙江")
|
||||
.put("31", "上海")
|
||||
.put("32", "江苏")
|
||||
.put("33", "浙江")
|
||||
.put("34", "安徽")
|
||||
.put("35", "福建")
|
||||
.put("36", "江西")
|
||||
.put("37", "山东")
|
||||
.put("41", "河南")
|
||||
.put("42", "湖北")
|
||||
.put("43", "湖南")
|
||||
.put("44", "广东")
|
||||
.put("45", "广西")
|
||||
.put("46", "海南")
|
||||
.put("50", "重庆")
|
||||
.put("51", "四川")
|
||||
.put("52", "贵州")
|
||||
.put("53", "云南")
|
||||
.put("54", "西藏")
|
||||
.put("61", "陕西")
|
||||
.put("62", "甘肃")
|
||||
.put("63", "青海")
|
||||
.put("64", "宁夏")
|
||||
.put("65", "新疆")
|
||||
.put("71", "台湾")
|
||||
.put("81", "香港")
|
||||
.put("82", "澳门")
|
||||
.put("83", "台湾") // 台湾身份证号码以83开头,但是行政区划为71
|
||||
.put("91", "国外")
|
||||
.build();
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public enum Gender {
|
||||
UNKNOWN(0, "Unknown", "未知"),
|
||||
MALE(1, "Male", "男"),
|
||||
FEMALE(2, "Female", "女"),
|
||||
|
||||
;
|
||||
|
||||
private static final Gender[] VALUES = new Gender[] { UNKNOWN, MALE, FEMALE };
|
||||
|
||||
private final int value;
|
||||
private final String displayName;
|
||||
private final String displayNameZh;
|
||||
|
||||
Gender(int value, String displayName, String displayNameZh) {
|
||||
this.value = value;
|
||||
this.displayName = displayName;
|
||||
this.displayNameZh = displayNameZh;
|
||||
}
|
||||
|
||||
public static Gender of(int value) {
|
||||
AssertTools.checkCondition(0 <= value && value < VALUES.length,
|
||||
() -> new EnumConstantNotPresentException(Gender.class, String.valueOf(value)));
|
||||
return VALUES[value];
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getDisplayNameZh() {
|
||||
return displayNameZh;
|
||||
}
|
||||
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Period;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
public abstract class IDCardNumber extends ValidatableStringRecord {
|
||||
|
||||
protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern)
|
||||
throws IllegalArgumentException{
|
||||
super(idNumber, pattern);
|
||||
}
|
||||
|
||||
protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern,
|
||||
@Nonnull String errorMessage) {
|
||||
super(idNumber, pattern, errorMessage);
|
||||
}
|
||||
|
||||
protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern,
|
||||
@Nonnull Supplier<String> errorMessage) {
|
||||
super(idNumber, pattern, errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份证号判断性别
|
||||
*/
|
||||
public abstract Gender getGender();
|
||||
|
||||
/**
|
||||
* 获取出生日期
|
||||
*/
|
||||
public abstract LocalDate getBirthDate();
|
||||
|
||||
/** 计算年龄 */
|
||||
public final int calculateAge() {
|
||||
LocalDate now = LocalDate.now();
|
||||
return Period.between(getBirthDate(), now).getYears();
|
||||
}
|
||||
}
|
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
|
||||
/**
|
||||
* 带校验的字符串值对象
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
*/
|
||||
public abstract class ValidatableStringRecord
|
||||
implements Comparable<ValidatableStringRecord> {
|
||||
|
||||
@Nonnull
|
||||
private final String value;
|
||||
|
||||
private final Matcher matcher;
|
||||
|
||||
protected ValidatableStringRecord(@Nonnull String value, @Nonnull Pattern pattern) {
|
||||
this(value, pattern, "Invalid value");
|
||||
}
|
||||
|
||||
protected ValidatableStringRecord(@Nonnull String value, @Nonnull Pattern pattern,
|
||||
@Nonnull Supplier<String> errorMessageSupplier) {
|
||||
this(value, pattern, errorMessageSupplier.get());
|
||||
}
|
||||
|
||||
protected ValidatableStringRecord(@Nonnull String value, @Nonnull Pattern pattern,
|
||||
@Nonnull String errorMessage) {
|
||||
AssertTools.checkArgumentNotNull(value, "The value cannot be null.");
|
||||
AssertTools.checkArgumentNotNull(pattern, "The pattern cannot be null.");
|
||||
this.matcher = pattern.matcher(value);
|
||||
AssertTools.checkArgument(this.matcher.matches(), errorMessage);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 值对象的字符串值。
|
||||
*
|
||||
* @return 字符串(不为空)
|
||||
*/
|
||||
public final String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ValidatableStringRecord o) {
|
||||
return this.value.compareTo(o.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ValidatableStringRecord other = (ValidatableStringRecord) obj;
|
||||
return Objects.equals(value, other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value();
|
||||
}
|
||||
|
||||
protected final Matcher getMatcher() {
|
||||
return matcher;
|
||||
}
|
||||
|
||||
}
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.Virtual;
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
|
||||
/**
|
||||
* 分页排序查询参数
|
||||
*
|
||||
* <p>
|
||||
* 根据传入的 {@code size} 和 {@code pageNum},
|
||||
* 提供 {@code getOffset} 方法计算 SQL 语句中 {@code offset} 的值。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @see PageResult
|
||||
*/
|
||||
public class PagingAndSortingQueryParams {
|
||||
|
||||
private static final int DEFAULT_PAGE_SIZE = 15;
|
||||
|
||||
private Integer size;
|
||||
private Long pageNum;
|
||||
private List<String> orderBy;
|
||||
|
||||
private static final Pattern sortStrPattern = Pattern.compile("^[a-zA-Z]\\w+-(desc|asc|DESC|ASC)$");
|
||||
|
||||
private final Map<String, String> sortableProperties;
|
||||
|
||||
public PagingAndSortingQueryParams(Map<String, String> sortableProperties) {
|
||||
Preconditions.checkArgument(sortableProperties != null && !sortableProperties.isEmpty(),
|
||||
"Sortable properties can not be empty.");
|
||||
sortableProperties.forEach((k, v) ->
|
||||
Preconditions.checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v),
|
||||
"Property name must not be blank."));
|
||||
this.sortableProperties = ImmutableMap.copyOf(sortableProperties);
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
public final void setOrderBy(@Nullable List<String> orderBy) {
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
|
||||
public final void setSize(@Nullable Integer size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public final void setPageNum(@Nullable Long pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
// Setters end
|
||||
|
||||
public final PagingParams buildPagingParams() {
|
||||
final int sizeValue = this.size != null ? this.size : defaultSizeInternal();
|
||||
final long pageNumValue = this.pageNum != null ? this.pageNum : 1L;
|
||||
final List<SortableProperty> propertiesToSort = this.orderBy.stream().map(this::generateSortableProperty)
|
||||
.collect(Collectors.toList());
|
||||
return new PagingParams(sizeValue, pageNumValue, propertiesToSort);
|
||||
}
|
||||
|
||||
@Virtual
|
||||
protected int defaultSizeInternal() {
|
||||
return DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PagingAndSortingQueryParams ["
|
||||
+ "size=" + size
|
||||
+ ", pageNum=" + pageNum
|
||||
+ ", orderBy=" + orderBy
|
||||
+ ", sortableProperties=" + sortableProperties
|
||||
+ "]";
|
||||
}
|
||||
|
||||
private SortableProperty generateSortableProperty(String orderByStr) {
|
||||
Preconditions.checkArgument(PagingAndSortingQueryParams.sortStrPattern.matcher(orderByStr).matches());
|
||||
String[] propertyNameAndOrderType = orderByStr.split("-");
|
||||
Preconditions.checkArgument(propertyNameAndOrderType.length == 2);
|
||||
|
||||
String propertyName = propertyNameAndOrderType[0];
|
||||
Preconditions.checkArgument(sortableProperties.containsKey(propertyName),
|
||||
"The property name must be in the set of sortable properties.");
|
||||
String columnName = sortableProperties.get(propertyName);
|
||||
String orderType = propertyNameAndOrderType[1];
|
||||
return new SortableProperty(propertyName, columnName, orderType);
|
||||
}
|
||||
|
||||
public static final class SortableProperty {
|
||||
private final String propertyName;
|
||||
private final String columnName;
|
||||
private final String orderType;
|
||||
|
||||
private final String sqlSnippet;
|
||||
|
||||
SortableProperty(String propertyName, String columnName, String orderType) {
|
||||
this.propertyName = propertyName;
|
||||
this.columnName = columnName;
|
||||
Preconditions.checkArgument("ASC".equalsIgnoreCase(orderType) || "DESC".equalsIgnoreCase(orderType));
|
||||
this.orderType = orderType.toUpperCase();
|
||||
|
||||
this.sqlSnippet = this.propertyName + " " + this.orderType;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public String getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
public String getSqlSnippet() {
|
||||
return sqlSnippet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SortableProperty ["
|
||||
+ "propertyName=" + propertyName
|
||||
+ ", columnName=" + columnName
|
||||
+ ", orderType=" + orderType
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.model.dto.PagingAndSortingQueryParams.SortableProperty;
|
||||
|
||||
public class PagingParams {
|
||||
|
||||
private final int size;
|
||||
private final long pageNum;
|
||||
private final long offset;
|
||||
private final List<SortableProperty> orderBy;
|
||||
|
||||
PagingParams(int size, long pageNum, List<SortableProperty> orderBy) {
|
||||
this.size = size;
|
||||
this.pageNum = pageNum;
|
||||
this.offset = (pageNum - 1) * size;
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
public final List<SortableProperty> getOrderBy() {
|
||||
return Collections.unmodifiableList(this.orderBy);
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public final long getPageNum() {
|
||||
return this.pageNum;
|
||||
}
|
||||
|
||||
public final long getOffset() {
|
||||
return this.offset;
|
||||
}
|
||||
|
||||
// Getters end
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PageInfo [size=" + size + ", pageNum=" + pageNum + ", orderBy=" + orderBy + ", offset="
|
||||
+ getOffset() + "]";
|
||||
}
|
||||
}
|
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* 统一结果,对返回给前端的数据进行封装。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public abstract class UnifiedResponse {
|
||||
|
||||
private Object status;
|
||||
private String message;
|
||||
|
||||
private @Nullable Object data;
|
||||
|
||||
public static UnifiedResponse success() {
|
||||
return new SuccessResult();
|
||||
}
|
||||
|
||||
public static UnifiedResponse success(@Nullable String message) {
|
||||
return new SuccessResult(message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse success(@Nullable String message, @Nullable Object data) {
|
||||
return new SuccessResult(message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(@Nullable String message) {
|
||||
return new ErrorResult(message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(@Nullable String message, @Nullable Object data) {
|
||||
return new ErrorResult(message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, @Nullable String message) {
|
||||
return new ErrorResult(status, message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, @Nullable String message, @Nullable Object data) {
|
||||
return new ErrorResult(status, message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, Throwable e) {
|
||||
return new ErrorResult(status, e);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(Object status, @Nullable String message) {
|
||||
return new CustomResult(status, message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(Object status, @Nullable String message, @Nullable Object data) {
|
||||
return new CustomResult(status, message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(final boolean isSuccess,
|
||||
final Supplier<SuccessResult> successResult, final Supplier<ErrorResult> errorResult) {
|
||||
Preconditions.checkNotNull(successResult, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(errorResult, "Error supplier must not be null.");
|
||||
return isSuccess ? successResult.get() : errorResult.get();
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(final BooleanSupplier isSuccess,
|
||||
final Supplier<SuccessResult> successResult, final Supplier<ErrorResult> errorResult) {
|
||||
Preconditions.checkNotNull(isSuccess, "Conditions for success must not be null.");
|
||||
Preconditions.checkNotNull(successResult, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(errorResult, "Error supplier must not be null.");
|
||||
return isSuccess.getAsBoolean() ? successResult.get() : errorResult.get();
|
||||
}
|
||||
|
||||
protected UnifiedResponse(Object status, @Nullable String message) {
|
||||
setStatus(status);
|
||||
setMessage(message);
|
||||
}
|
||||
|
||||
protected UnifiedResponse(Object status, @Nullable String message, @Nullable Object data) {
|
||||
setStatus(status);
|
||||
setMessage(message);
|
||||
setData(data);
|
||||
}
|
||||
|
||||
private void setStatus(Object status) {
|
||||
this.status = Objects.requireNonNull(status);
|
||||
}
|
||||
|
||||
private void setMessage(@Nullable String message) {
|
||||
this.message = message == null ? "" : message;
|
||||
}
|
||||
|
||||
private void setData(@Nullable Object data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Constructors end
|
||||
|
||||
// Getters
|
||||
|
||||
public Object getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Getters end
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{status: %s, message: \"%s\", data: %s}",
|
||||
transValue(this.status), this.message, transValue(this.data));
|
||||
}
|
||||
|
||||
private static String transValue(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
protected static class SuccessResult extends UnifiedResponse {
|
||||
public static final String SUCCESS_STATUS = "2000000";
|
||||
|
||||
private static final String DEFAULT_SUCCESS_MSG = "SUCCESS";
|
||||
|
||||
SuccessResult() {
|
||||
super(SUCCESS_STATUS, DEFAULT_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
SuccessResult(@Nullable String message) {
|
||||
super(SUCCESS_STATUS, message);
|
||||
}
|
||||
|
||||
SuccessResult(@Nullable String message, @Nullable Object data) {
|
||||
super(SUCCESS_STATUS, message, data);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ErrorResult extends UnifiedResponse {
|
||||
public static final String DEFAULT_ERROR_STATUS = "9999999";
|
||||
|
||||
ErrorResult(@Nullable String message) {
|
||||
super(DEFAULT_ERROR_STATUS, message);
|
||||
}
|
||||
|
||||
ErrorResult(@Nullable String message, @Nullable Object data) {
|
||||
super(DEFAULT_ERROR_STATUS, message, data);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, @Nullable String message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, @Nullable String message, @Nullable Object data) {
|
||||
super(status, message, data);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, Throwable e) {
|
||||
super(status, Objects.requireNonNull(e).getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义结果
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
protected static class CustomResult extends UnifiedResponse {
|
||||
|
||||
CustomResult(Object status, @Nullable String message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
CustomResult(Object status, @Nullable String message, @Nullable Object data) {
|
||||
super(status, message, data);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package xyz.zhouxy.plusone.commons.net;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class MoreInetAddresses {
|
||||
|
||||
public static NetworkInterfaceInfo getNetworkInterfaceInfo() throws SocketException {
|
||||
final Enumeration<NetworkInterface> all = NetworkInterface.getNetworkInterfaces();
|
||||
NetworkInterface networkInterface;
|
||||
while (all.hasMoreElements()) {
|
||||
networkInterface = all.nextElement();
|
||||
if (networkInterface.isLoopback() || networkInterface.isVirtual()) {
|
||||
continue;
|
||||
}
|
||||
final byte[] mac = networkInterface.getHardwareAddress();
|
||||
if (mac != null) {
|
||||
return new NetworkInterfaceInfo(networkInterface, mac);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("No available network interface found");
|
||||
}
|
||||
|
||||
public static Inet4Address getIpv4(NetworkInterface networkInterface) {
|
||||
final Enumeration<InetAddress> ips = networkInterface.getInetAddresses();
|
||||
InetAddress ip;
|
||||
while (ips.hasMoreElements()) {
|
||||
ip = ips.nextElement();
|
||||
if (!ip.isLoopbackAddress() && (ip instanceof Inet4Address)) {
|
||||
return (Inet4Address) ip;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("No available address found");
|
||||
}
|
||||
|
||||
public static Inet6Address getIpv6(NetworkInterface networkInterface) {
|
||||
final Enumeration<InetAddress> ips = networkInterface.getInetAddresses();
|
||||
InetAddress ip;
|
||||
while (ips.hasMoreElements()) {
|
||||
ip = ips.nextElement();
|
||||
if (!ip.isLoopbackAddress() && (ip instanceof Inet6Address)) {
|
||||
return (Inet6Address) ip;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("No available address found");
|
||||
}
|
||||
|
||||
private MoreInetAddresses() {
|
||||
throw new UnsupportedOperationException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package xyz.zhouxy.plusone.commons.net;
|
||||
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class NetworkInterfaceInfo {
|
||||
private final NetworkInterface networkInterface;
|
||||
private final byte[] mac;
|
||||
|
||||
NetworkInterfaceInfo(NetworkInterface networkInterface, byte[] mac) {
|
||||
this.networkInterface = Objects.requireNonNull(networkInterface);
|
||||
this.mac = Objects.requireNonNull(mac);
|
||||
}
|
||||
|
||||
public NetworkInterface getNetworkInterface() {
|
||||
return networkInterface;
|
||||
}
|
||||
|
||||
public byte[] getMac() {
|
||||
return Arrays.copyOf(this.mac, this.mac.length);
|
||||
}
|
||||
|
||||
public String getMacStr() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
String s;
|
||||
for (int i = 0; i < this.mac.length; i++) {
|
||||
if (i != 0) {
|
||||
result.append("-");
|
||||
}
|
||||
s = Integer.toHexString(this.mac[i] & 0xFF);
|
||||
if (s.length() == 1) {
|
||||
result.append("0");
|
||||
}
|
||||
result.append(s);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.sql;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -69,4 +53,4 @@ public class JdbcSql extends SQL<JdbcSql> {
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.sql;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
@@ -42,14 +26,14 @@ public class MyBatisSql extends SQL<MyBatisSql> {
|
||||
}
|
||||
|
||||
public static String IN(String col, String paramName) {
|
||||
return " " + col + " IN" + buildForeach(col, paramName);
|
||||
return " " + col + " IN" + buildQuestionsList(col, paramName);
|
||||
}
|
||||
|
||||
public static String NOT_IN(String col, String paramName) {
|
||||
return col + " NOT IN" + buildForeach(col, paramName);
|
||||
return col + " NOT IN" + buildQuestionsList(col, paramName);
|
||||
}
|
||||
|
||||
private static String buildForeach(String col, String paramName) {
|
||||
private static String buildQuestionsList(String col, String paramName) {
|
||||
final String format = "<foreach" +
|
||||
" item=\"%s\"" +
|
||||
" index=\"index\"" +
|
||||
@@ -70,4 +54,4 @@ public class MyBatisSql extends SQL<MyBatisSql> {
|
||||
}
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -21,7 +21,7 @@ import org.apache.ibatis.jdbc.AbstractSQL;
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author ZhouXY
|
||||
*/
|
||||
@Beta
|
||||
public abstract class SQL<T> extends AbstractSQL<T> {
|
||||
@@ -44,4 +44,4 @@ public abstract class SQL<T> extends AbstractSQL<T> {
|
||||
public T WHERE(boolean condition, String ifSqlCondition, String elseSqlCondition) {
|
||||
return WHERE(condition ? ifSqlCondition : elseSqlCondition);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.time;
|
||||
|
||||
import java.time.Month;
|
||||
import java.time.MonthDay;
|
||||
import java.time.temporal.ChronoField;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
|
||||
/**
|
||||
* 季度
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public enum Quarter {
|
||||
/** 第一季度 */
|
||||
Q1(1),
|
||||
/** 第二季度 */
|
||||
Q2(2),
|
||||
/** 第三季度 */
|
||||
Q3(3),
|
||||
/** 第四季度 */
|
||||
Q4(4),
|
||||
;
|
||||
|
||||
/** 季度值 (1/2/3/4) */
|
||||
private final int value;
|
||||
|
||||
private final Range<Integer> monthRange;
|
||||
|
||||
/** 常量值 */
|
||||
private static final Quarter[] ENUMS = Quarter.values();
|
||||
|
||||
/**
|
||||
* @param value 季度值 (1/2/3/4)
|
||||
*/
|
||||
Quarter(int value) {
|
||||
this.value = value;
|
||||
|
||||
final int lastMonth = value * 3;
|
||||
final int firstMonth = lastMonth - 2;
|
||||
|
||||
this.monthRange = Range.closed(firstMonth, lastMonth);
|
||||
}
|
||||
|
||||
// StaticFactoryMethods
|
||||
|
||||
/**
|
||||
* 根据给定的月份值返回对应的季度
|
||||
*
|
||||
* @param monthValue 月份值,取值范围为1到12
|
||||
* @return 对应的季度
|
||||
* @throws IllegalArgumentException 如果月份值不在有效范围内(1到12),将抛出异常
|
||||
*/
|
||||
@StaticFactoryMethod(Quarter.class)
|
||||
public static Quarter fromMonth(int monthValue) {
|
||||
ChronoField.MONTH_OF_YEAR.checkValidValue(monthValue);
|
||||
return of(computeQuarterValueInternal(monthValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的月份返回对应的季度
|
||||
*
|
||||
* @param month 月份
|
||||
* @return 对应的季度
|
||||
*/
|
||||
@StaticFactoryMethod(Quarter.class)
|
||||
public static Quarter fromMonth(Month month) {
|
||||
final int monthValue = month.getValue();
|
||||
return of(computeQuarterValueInternal(monthValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的年份,获取一个新的 YearQuarter 实例
|
||||
* 此方法允许在保持当前季度信息不变的情况下,更改年份
|
||||
*
|
||||
* @param year 指定的年份
|
||||
* @return 返回一个新的 YearQuarter 实例,年份更新为指定的年份
|
||||
*/
|
||||
public final YearQuarter atYear(int year) {
|
||||
return YearQuarter.of(year, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的季度值返回对应的季度
|
||||
*
|
||||
* @param value 季度值 (1/2/3/4)
|
||||
* @return 对应的季度
|
||||
* @throws IllegalArgumentException 如果季度值不在有效范围内(1到4),将抛出异常
|
||||
*/
|
||||
@StaticFactoryMethod(Quarter.class)
|
||||
public static Quarter of(int value) {
|
||||
if (value < 1 || value > 4) {
|
||||
throw new IllegalArgumentException("Invalid value for Quarter: " + value);
|
||||
}
|
||||
return ENUMS[value - 1];
|
||||
}
|
||||
|
||||
// StaticFactoryMethods end
|
||||
|
||||
// computs
|
||||
|
||||
public Quarter plus(long quarters) { // TODO 单元测试
|
||||
final int amount = (int) ((quarters % 4) + 4);
|
||||
return ENUMS[(ordinal() + amount) % 4];
|
||||
}
|
||||
|
||||
public Quarter minus(long quarters) { // TODO 单元测试
|
||||
return plus(-(quarters % 4));
|
||||
}
|
||||
|
||||
// computs end
|
||||
|
||||
// Getters
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Month firstMonth() {
|
||||
return Month.of(firstMonthValue());
|
||||
}
|
||||
|
||||
public int firstMonthValue() {
|
||||
return this.monthRange.lowerEndpoint();
|
||||
}
|
||||
|
||||
public Month lastMonth() {
|
||||
return Month.of(lastMonthValue());
|
||||
}
|
||||
|
||||
public int lastMonthValue() {
|
||||
return this.monthRange.upperEndpoint();
|
||||
}
|
||||
|
||||
public MonthDay firstMonthDay() {
|
||||
return MonthDay.of(firstMonth(), 1);
|
||||
}
|
||||
|
||||
public MonthDay lastMonthDay() {
|
||||
// 季度的最后一个月不可能是 2 月
|
||||
final Month month = lastMonth();
|
||||
return MonthDay.of(month, month.maxLength());
|
||||
}
|
||||
|
||||
public int firstDayOfYear(boolean leapYear) {
|
||||
return firstMonth().firstDayOfYear(leapYear);
|
||||
}
|
||||
|
||||
// Getters end
|
||||
|
||||
// Internal
|
||||
|
||||
/**
|
||||
* 计算给定月份对应的季度值
|
||||
*
|
||||
* @param monthValue 月份值,取值范围为1到12
|
||||
* @return 对应的季度值
|
||||
*/
|
||||
private static int computeQuarterValueInternal(int monthValue) {
|
||||
return (monthValue - 1) / 3 + 1;
|
||||
}
|
||||
}
|
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.time;
|
||||
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.time.YearMonth;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
|
||||
/**
|
||||
* 表示年份与季度
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
@Immutable
|
||||
public final class YearQuarter implements Comparable<YearQuarter>, Serializable {
|
||||
private static final long serialVersionUID = 3804145964419489753L;
|
||||
|
||||
/** 年份 */
|
||||
private final int year;
|
||||
/** 季度 */
|
||||
private final Quarter quarter;
|
||||
/** 季度开始日期 */
|
||||
private final LocalDate firstDate;
|
||||
/** 季度结束日期 */
|
||||
private final LocalDate lastDate;
|
||||
|
||||
private YearQuarter(int year, @Nonnull Quarter quarter) {
|
||||
Preconditions.checkNotNull(quarter, "Quarter can not be null.");
|
||||
this.year = year;
|
||||
this.quarter = quarter;
|
||||
this.firstDate = quarter.firstMonthDay().atYear(year);
|
||||
this.lastDate = quarter.lastMonthDay().atYear(year);
|
||||
}
|
||||
|
||||
// #region - StaticFactoryMethod
|
||||
|
||||
/**
|
||||
* 根据指定年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param year 年份
|
||||
* @param quarter 季度
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(int year, int quarter) {
|
||||
return of(year, Quarter.of(quarter));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param year 年份
|
||||
* @param quarter 季度
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(int year, @Nonnull Quarter quarter) {
|
||||
return new YearQuarter(year, quarter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定日期,判断日期所在的年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param date 日期
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(@Nonnull LocalDate date) {
|
||||
return of(date.getYear(), Quarter.fromMonth(date.getMonth()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定日期,判断日期所在的年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param date 日期
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(@Nonnull Date date) {
|
||||
@SuppressWarnings("deprecation")
|
||||
final int year = date.getYear() + 1900;
|
||||
@SuppressWarnings("deprecation")
|
||||
final int month = date.getMonth() + 1;
|
||||
return of(year, Quarter.fromMonth(month));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定日期,判断日期所在的年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param date 日期
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(Calendar date) {
|
||||
return of(date.get(Calendar.YEAR), Quarter.fromMonth(date.get(Calendar.MONTH) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定年月,判断其所在的年份与季度,创建 {@link YearQuarter} 实例
|
||||
*
|
||||
* @param yearMonth 年月
|
||||
* @return {@link YearQuarter} 实例
|
||||
*/
|
||||
@StaticFactoryMethod(YearQuarter.class)
|
||||
public static YearQuarter of(YearMonth yearMonth) {
|
||||
return of(yearMonth.getYear(), Quarter.fromMonth(yearMonth.getMonth()));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - Getters
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public Quarter getQuarter() {
|
||||
return quarter;
|
||||
}
|
||||
|
||||
public YearMonth firstYearMonth() {
|
||||
return YearMonth.of(this.year, this.quarter.firstMonth());
|
||||
}
|
||||
|
||||
public Month firstMonth() {
|
||||
return this.quarter.firstMonth();
|
||||
}
|
||||
|
||||
public int firstMonthValue() {
|
||||
return this.quarter.firstMonthValue();
|
||||
}
|
||||
|
||||
public YearMonth lastYearMonth() {
|
||||
return YearMonth.of(this.year, this.quarter.lastMonth());
|
||||
}
|
||||
|
||||
public Month lastMonth() {
|
||||
return this.quarter.lastMonth();
|
||||
}
|
||||
|
||||
public int lastMonthValue() {
|
||||
return this.quarter.lastMonthValue();
|
||||
}
|
||||
|
||||
public LocalDate firstDate() {
|
||||
return firstDate;
|
||||
}
|
||||
|
||||
public LocalDate lastDate() {
|
||||
return lastDate;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - computes
|
||||
|
||||
public YearQuarter plusQuarters(long quartersToAdd) { // TODO 单元测试
|
||||
if (quartersToAdd == 0) {
|
||||
return this;
|
||||
}
|
||||
long quarterCount = this.year * 4L + (this.quarter.getValue() - 1);
|
||||
long calcQuarters = quarterCount + quartersToAdd; // safe overflow
|
||||
int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcQuarters, 4));
|
||||
int newQuarter = (int) Math.floorMod(calcQuarters, 4) + 1;
|
||||
return of(newYear, Quarter.of(newQuarter));
|
||||
}
|
||||
|
||||
public YearQuarter minusQuarters(long quartersToAdd) { // TODO 单元测试
|
||||
return plusQuarters(-quartersToAdd);
|
||||
}
|
||||
|
||||
public YearQuarter plusYears(long yearsToAdd) { // TODO 单元测试
|
||||
if (yearsToAdd == 0) {
|
||||
return this;
|
||||
}
|
||||
int newYear = YEAR.checkValidIntValue(this.year + yearsToAdd); // safe overflow
|
||||
return of(newYear, this.quarter);
|
||||
}
|
||||
|
||||
public YearQuarter minusYears(long yearsToAdd) {
|
||||
return plusYears(-yearsToAdd);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - hashCode & equals
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(year, quarter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
YearQuarter other = (YearQuarter) obj;
|
||||
return year == other.year && quarter == other.quarter;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - compareTo
|
||||
|
||||
@Override
|
||||
public int compareTo(YearQuarter other) {
|
||||
int cmp = (this.year - other.year);
|
||||
if (cmp == 0) {
|
||||
cmp = this.quarter.compareTo(other.quarter);
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
public boolean isBefore(YearQuarter other) {
|
||||
return this.compareTo(other) < 0;
|
||||
}
|
||||
|
||||
public boolean isAfter(YearQuarter other) {
|
||||
return this.compareTo(other) > 0;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toString
|
||||
|
||||
/**
|
||||
* 返回 {@link YearQuarter} 的字符串表示形式,如 "2024 Q3"
|
||||
*
|
||||
* @return {@link YearQuarter} 的字符串表示形式
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.year + " " + this.quarter.name();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* 断言工具
|
||||
*
|
||||
* <p>
|
||||
* 本工具类不封装过多判断逻辑,鼓励充分使用项目中的工具类进行逻辑判断。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* AssertTools.checkArgument(StringUtils.hasText(str), "The argument cannot be blank.");
|
||||
* AssertTools.checkState(ArrayUtils.isNotEmpty(result), "The result cannot be empty.");
|
||||
* AssertTools.checkCondition(!CollectionUtils.isEmpty(roles), () -> new InvalidInputException("The roles cannot be empty."));
|
||||
* AssertTools.checkCondition(RegexTools.matches(email, PatternConsts.EMAIL), "must be a well-formed email address");
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public class AssertTools {
|
||||
|
||||
// #region - checkArgument
|
||||
|
||||
public static <T> void checkArgumentNotNull(T argument) {
|
||||
checkCondition(argument != null, () -> new IllegalArgumentException("The argument cannot be null."));
|
||||
}
|
||||
|
||||
public static <T> void checkArgumentNotNull(T argument, String errMsg) {
|
||||
checkCondition(argument != null, () -> new IllegalArgumentException(errMsg));
|
||||
}
|
||||
|
||||
public static <T> void checkArgumentNotNull(T argument, Supplier<String> messageSupplier) {
|
||||
checkCondition(argument != null, () -> new IllegalArgumentException(messageSupplier.get()));
|
||||
}
|
||||
|
||||
public static <T> void checkArgumentNotNull(T argument, String format, Object... args) {
|
||||
checkCondition(argument != null, () -> new IllegalArgumentException(String.format(format, args)));
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition) {
|
||||
checkCondition(condition, IllegalArgumentException::new);
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition, String errMsg) {
|
||||
checkCondition(condition, () -> new IllegalArgumentException(errMsg));
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition, Supplier<String> messageSupplier) {
|
||||
checkCondition(condition, () -> new IllegalArgumentException(messageSupplier.get()));
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition, String format, Object... args) {
|
||||
checkCondition(condition, () -> new IllegalArgumentException(String.format(format, args)));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - checkState
|
||||
|
||||
public static void checkState(boolean condition) {
|
||||
checkCondition(condition, IllegalStateException::new);
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition, String errMsg) {
|
||||
checkCondition(condition, () -> new IllegalStateException(errMsg));
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition, Supplier<String> messageSupplier) {
|
||||
checkCondition(condition, () -> new IllegalStateException(messageSupplier.get()));
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition, String format, Object... args) {
|
||||
checkCondition(condition, () -> new IllegalStateException(String.format(format, args)));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - checkNotNull
|
||||
|
||||
public static <T> void checkNotNull(T obj) {
|
||||
checkCondition(obj != null, NullPointerException::new);
|
||||
}
|
||||
|
||||
public static <T> void checkNotNull(T obj, String errMsg) {
|
||||
checkCondition(obj != null, () -> new NullPointerException(errMsg));
|
||||
}
|
||||
|
||||
public static <T> void checkNotNull(T obj, Supplier<String> messageSupplier) {
|
||||
checkCondition(obj != null, () -> new NullPointerException(messageSupplier.get()));
|
||||
}
|
||||
|
||||
public static <T> void checkNotNull(T obj, String format, Object... args) {
|
||||
checkCondition(obj != null, () -> new NullPointerException(String.format(format, args)));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - checkCondition
|
||||
|
||||
public static <T extends Exception> void checkCondition(boolean condition, @Nonnull Supplier<T> e)
|
||||
throws T {
|
||||
if (!condition) {
|
||||
throw e.get();
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - private constructor
|
||||
|
||||
private AssertTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
@@ -1,78 +1,39 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public class BigDecimals {
|
||||
|
||||
public static boolean equalsValue(@Nullable BigDecimal a, @Nullable BigDecimal b) {
|
||||
public static final BigDecimal ZERO = new BigDecimal("0.00");
|
||||
|
||||
public static boolean equals(@Nullable BigDecimal a, @Nullable BigDecimal b) {
|
||||
return (a == b) || (a != null && a.compareTo(b) == 0);
|
||||
}
|
||||
|
||||
public static boolean gt(BigDecimal a, BigDecimal b) {
|
||||
@Beta
|
||||
public static boolean greaterThan(BigDecimal a, BigDecimal b) {
|
||||
Preconditions.checkNotNull(a, "Parameter could not be null.");
|
||||
Preconditions.checkNotNull(b, "Parameter could not be null.");
|
||||
return (a != b) && (a.compareTo(b) > 0);
|
||||
}
|
||||
|
||||
public static boolean ge(BigDecimal a, BigDecimal b) {
|
||||
return gt(a, b) || equalsValue(a, b);
|
||||
}
|
||||
|
||||
public static boolean lt(BigDecimal a, BigDecimal b) {
|
||||
@Beta
|
||||
public static boolean lessThan(BigDecimal a, BigDecimal b) {
|
||||
Preconditions.checkNotNull(a, "Parameter could not be null.");
|
||||
Preconditions.checkNotNull(b, "Parameter could not be null.");
|
||||
return (a != b) && (a.compareTo(b) < 0);
|
||||
}
|
||||
|
||||
public static boolean le(BigDecimal a, BigDecimal b) {
|
||||
return lt(a, b) || equalsValue(a, b);
|
||||
}
|
||||
|
||||
public static BigDecimal sum(final BigDecimal... numbers) {
|
||||
if (ArrayTools.isNullOrEmpty(numbers)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal result = BigDecimals.nullToZero(numbers[0]);
|
||||
for (int i = 1; i < numbers.length; i++) {
|
||||
BigDecimal value = numbers[i];
|
||||
if (value != null) {
|
||||
result = result.add(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static BigDecimal nullToZero(@Nullable final BigDecimal val) {
|
||||
return val != null ? val : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@StaticFactoryMethod(BigDecimal.class)
|
||||
@Beta
|
||||
public static BigDecimal of(final String val) {
|
||||
return (StringTools.isNotBlank(val)) ? new BigDecimal(val) : BigDecimal.ZERO;
|
||||
return (StringUtils.isBlank(val)) ? ZERO : new BigDecimal(val);
|
||||
}
|
||||
|
||||
private BigDecimals() {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -21,38 +21,19 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.JRE;
|
||||
import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* ConcurrentHashMapTools
|
||||
*
|
||||
* <p>
|
||||
* Java 8 的 {@link ConcurrentHashMap#computeIfAbsent(Object, Function)} 方法有 bug,
|
||||
* 可使用这个工具类的 {@link computeIfAbsentForJava8} 进行替换。
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 方法来自Dubbo,见:issues#2349</b>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0
|
||||
* @see ConcurrentHashMap
|
||||
* @see SafeConcurrentHashMap
|
||||
*/
|
||||
public class ConcurrentHashMapTools {
|
||||
public class ConcurrentHashMapUtil { // TODO 添加文档注释
|
||||
|
||||
public static <K, V> V computeIfAbsent(
|
||||
ConcurrentHashMap<K, V> map, final K key, // NOSONAR
|
||||
public static <K, V> V computeIfAbsent(ConcurrentHashMap<K, V> map, final K key,
|
||||
final Function<? super K, ? extends V> mappingFunction) {
|
||||
Objects.requireNonNull(map, "map");
|
||||
|
||||
return JRE.isJava8()
|
||||
? computeIfAbsentForJava8(map, key, mappingFunction)
|
||||
: map.computeIfAbsent(key, mappingFunction);
|
||||
}
|
||||
|
||||
public static <K, V> V computeIfAbsentForJava8(
|
||||
ConcurrentHashMap<K, V> map, final K key, // NOSONAR
|
||||
public static <K, V> V computeIfAbsentForJava8(ConcurrentHashMap<K, V> map, final K key,
|
||||
final Function<? super K, ? extends V> mappingFunction) {
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(mappingFunction);
|
||||
V v = map.get(key);
|
||||
if (null == v) {
|
||||
@@ -68,7 +49,7 @@ public class ConcurrentHashMapTools {
|
||||
return v;
|
||||
}
|
||||
|
||||
private ConcurrentHashMapTools() {
|
||||
private ConcurrentHashMapUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
/**
|
||||
* 自定义结果
|
||||
*
|
||||
* @author zhouxy
|
||||
*/
|
||||
final class CustomResult extends UnifiedResponse {
|
||||
|
||||
CustomResult(Object status, String message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
CustomResult(Object status, String message, Object data) {
|
||||
super(status, message, data);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5794887914598566589L;
|
||||
}
|
@@ -1,722 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Month;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.time.Quarter;
|
||||
import xyz.zhouxy.plusone.commons.time.YearQuarter;
|
||||
|
||||
/**
|
||||
* 日期时间工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public class DateTimeTools {
|
||||
|
||||
/**
|
||||
* 缓存时间格式化器
|
||||
*/
|
||||
private static final LoadingCache<String, DateTimeFormatter> DATE_TIME_FORMATTER_CACHE = CacheBuilder.newBuilder()
|
||||
.maximumSize(20)
|
||||
.build(new CacheLoader<String, DateTimeFormatter>() {
|
||||
@Override
|
||||
public DateTimeFormatter load(@Nonnull String pattern) throws Exception {
|
||||
return DateTimeFormatter.ofPattern(pattern);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取时间格式化器
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @return 时间格式化器
|
||||
*/
|
||||
public static DateTimeFormatter getDateTimeFormatter(String pattern) {
|
||||
return DATE_TIME_FORMATTER_CACHE.getUnchecked(pattern);
|
||||
}
|
||||
|
||||
// #region - toString
|
||||
|
||||
/**
|
||||
* 将日期时间转换为指定格式的字符串
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @param dateTime 日期时间
|
||||
* @return 格式化的字符串
|
||||
*/
|
||||
public static String toString(String pattern, ZonedDateTime dateTime) {
|
||||
return getDateTimeFormatter(pattern).format(dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳转换为指定格式的字符串,使用系统默认时区
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @param instant 时间戳
|
||||
* @return 格式化的字符串
|
||||
*/
|
||||
public static String toString(String pattern, Instant instant) {
|
||||
ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault());
|
||||
return toString(pattern, dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳转换为指定格式的字符串,使用指定时区
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @param instant 时间戳
|
||||
* @param zone 时区
|
||||
* @return 格式化的字符串
|
||||
*/
|
||||
public static String toString(String pattern, Instant instant, ZoneId zone) {
|
||||
ZonedDateTime dateTime = instant.atZone(zone);
|
||||
return toString(pattern, dateTime);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - nowStr
|
||||
|
||||
/**
|
||||
* 指定格式,返回当前时间戳对应的字符串
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @return 格式化的字符串
|
||||
*/
|
||||
public static String nowStr(String pattern) {
|
||||
return toString(pattern, ZonedDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定格式,返回当前时间戳对应的字符串,使用指定时区
|
||||
*
|
||||
* @param pattern 时间格式
|
||||
* @param zone 时区
|
||||
* @return 格式化的字符串
|
||||
*/
|
||||
public static String nowStr(String pattern, ZoneId zone) {
|
||||
return toString(pattern, Instant.now().atZone(zone));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toDate
|
||||
|
||||
/**
|
||||
* 将时间戳转换为 {@link Date} 对象
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(long timeMillis) {
|
||||
return Date.from(Instant.ofEpochMilli(timeMillis));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link Calendar} 对象转换为 {@link Date} 对象
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(Calendar calendar) {
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link Instant} 对象转换为 {@link Date} 对象
|
||||
*
|
||||
* @param instant {@link Instant} 对象
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(Instant instant) {
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link ZonedDateTime} 对象转换为 {@link Date} 对象
|
||||
*
|
||||
* @param zonedDateTime {@link ZonedDateTime} 对象
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(ZonedDateTime zonedDateTime) {
|
||||
return Date.from(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定时区,将 {@link LocalDateTime} 对象转换为 {@link Date} 对象
|
||||
*
|
||||
* @param localDateTime {@link LocalDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(LocalDateTime localDateTime, ZoneId zone) {
|
||||
return Date.from(ZonedDateTime.of(localDateTime, zone).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定时区,将 {@link LocalDate} 和 {@link LocalTime} 对象转换为 {@link Date} 对象
|
||||
*
|
||||
* @param localDate {@link LocalDate} 对象
|
||||
* @param localTime {@link LocalTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link Date} 对象
|
||||
*/
|
||||
public static Date toDate(LocalDate localDate, LocalTime localTime, ZoneId zone) {
|
||||
return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant());
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toInstant
|
||||
|
||||
/**
|
||||
* 将时间戳转换为 {@link Instant} 对象
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @return {@link Instant} 对象
|
||||
*/
|
||||
public static Instant toInstant(long timeMillis) {
|
||||
return Instant.ofEpochMilli(timeMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link Date} 对象转换为 {@link Instant} 对象
|
||||
*
|
||||
* @param date {@link Date} 对象
|
||||
* @return {@link Instant} 对象
|
||||
*/
|
||||
public static Instant toInstant(Date date) {
|
||||
return date.toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link Calendar} 对象转换为 {@link Instant} 对象
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @return {@link Instant} 对象
|
||||
*/
|
||||
public static Instant toInstant(Calendar calendar) {
|
||||
return calendar.toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link ZonedDateTime} 对象转换为 {@link Instant} 对象
|
||||
*
|
||||
* @param zonedDateTime {@link ZonedDateTime} 对象
|
||||
* @return {@link Instant} 对象
|
||||
* @deprecated 请使用 {@link ZonedDateTime#toInstant()} 方法
|
||||
*/
|
||||
@Deprecated
|
||||
public static Instant toInstant(ZonedDateTime zonedDateTime) { // NOSONAR
|
||||
return zonedDateTime.toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定时区,将 {@link LocalDateTime} 对象转换为 {@link Instant} 对象
|
||||
*
|
||||
* @param LocalDateTime {@link LocalDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link Instant} 对象
|
||||
*/
|
||||
public static Instant toInstant(LocalDateTime localDateTime, ZoneId zone) {
|
||||
return ZonedDateTime.of(localDateTime, zone).toInstant();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toZonedDateTime
|
||||
|
||||
/**
|
||||
* 获取时间戳在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @param zone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(long timeMillis, ZoneId zone) {
|
||||
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param zone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Date dateTime, ZoneId zone) {
|
||||
return ZonedDateTime.ofInstant(dateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上表示的还是还是同一时间戳的时间,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param timeZone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Date dateTime, TimeZone timeZone) {
|
||||
return ZonedDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 {@code calendar} 对象的时区信息,将 {@link Calendar} 对象转换为 {@link ZonedDateTime}
|
||||
* 对象。
|
||||
*
|
||||
* @param calendar{@link Calendar} 对象
|
||||
* @return {@link ZonedDateTime} 对象
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Calendar calendar) {
|
||||
return calendar.toInstant().atZone(calendar.getTimeZone().toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的时区,将 {@link Calendar} 对象转换为 {@link ZonedDateTime} 对象。
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link ZonedDateTime} 对象
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Calendar calendar, ZoneId zone) {
|
||||
return calendar.toInstant().atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的时区,将 {@link Calendar} 对象转换为 {@link ZonedDateTime} 对象。
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link ZonedDateTime} 对象
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Calendar calendar, TimeZone zone) {
|
||||
return calendar.toInstant().atZone(zone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带时区的地区时间
|
||||
*
|
||||
* @param localDateTime 地区时间
|
||||
* @param zone 时区
|
||||
* @return 带时区的地区时间
|
||||
*
|
||||
* @deprecated 使用 {@link ZonedDateTime#of(LocalDateTime, ZoneId)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, ZoneId zone) { // NOSONAR
|
||||
return ZonedDateTime.of(localDateTime, zone);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toLocalDateTime
|
||||
|
||||
/**
|
||||
* 获取时间戳在指定时区的地区时间。
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Date dateTime, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(dateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param timeZone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Date dateTime, TimeZone timeZone) {
|
||||
return LocalDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Calendar} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Calendar calendar, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(calendar.toInstant(), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Calendar} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param calendar {@link Calendar} 对象
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Calendar calendar, TimeZone zone) {
|
||||
return LocalDateTime.ofInstant(calendar.toInstant(), zone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link ZonedDateTime} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param zonedDateTime {@link ZonedDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// ====================
|
||||
|
||||
// #region - toJodaInstant
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.Instant} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param instant {@link java.time.Instant} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.Instant instant) {
|
||||
return new org.joda.time.Instant(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.ZonedDateTime} 转换为 {@link org.joda.time.Instant}
|
||||
*
|
||||
* @param zonedDateTime {@link java.time.ZonedDateTime} 对象
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.ZonedDateTime zonedDateTime) {
|
||||
return toJodaInstant(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定时区的地区时间,对应的时间戳。结果为 {@link org.joda.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime {@link java.time.LocalDateTime} 对象
|
||||
* @param zone 时区
|
||||
* @return {@link org.joda.time.Instant} 对象
|
||||
*/
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.LocalDateTime localDateTime, java.time.ZoneId zone) {
|
||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toJavaInstant
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.Instant} 对象转换为 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param instant {@link org.joda.time.Instant} 对象
|
||||
* @return {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.Instant instant) {
|
||||
return toInstant(instant.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.DateTime} 对象转换为 Java 的
|
||||
* {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param dateTime joda-time 中表示日期时间的 {@link org.joda.time.DateTime} 对象
|
||||
* @return Java 表示时间戳的 {@link java.time.Instant} 对象
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.DateTime dateTime) {
|
||||
return toInstant(dateTime.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 对象和
|
||||
* {@link org.joda.time.DateTimeZone} 对象
|
||||
* 转换为 Java 中的 {@link java.time.Instant} 对象
|
||||
*
|
||||
* @param localDateTime
|
||||
* @param zone
|
||||
* @return
|
||||
*/
|
||||
public static java.time.Instant toJavaInstant(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone zone) {
|
||||
return toJavaInstant(localDateTime.toDateTime(zone));
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toJodaDateTime
|
||||
|
||||
/**
|
||||
* 将 Java 中表示日期时间的 {@link java.time.ZonedDateTime} 对象
|
||||
* 转换为 joda-time 的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param zonedDateTime 日期时间
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(java.time.ZonedDateTime zonedDateTime) {
|
||||
org.joda.time.DateTimeZone zone = org.joda.time.DateTimeZone.forID(zonedDateTime.getZone().getId());
|
||||
return toJodaInstant(zonedDateTime.toInstant()).toDateTime(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 java.time 中表示日期时间的 {@link java.time.LocalDateTime} 对象和表示时区的
|
||||
* {@link java.time.ZoneId} 对象转换为 joda-time 中对应的 {@link org.joda.time.DateTime}
|
||||
* 对象
|
||||
* 转换为 joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*
|
||||
* @param localDateTime 日期时间
|
||||
* @param zone 时区
|
||||
* @return joda-time 中对应的 {@link org.joda.time.DateTime} 对象
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.LocalDateTime localDateTime,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(ZonedDateTime.of(localDateTime, zone).toInstant()).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算时间戳在指定时区对应的时间,结果使用 {@link org.joda.time.DateTime} 表示
|
||||
*
|
||||
* @param instant java.time 中的时间戳
|
||||
* @param zone java.time 中的时区
|
||||
* @return joda-time 中带时区的日期时间
|
||||
*/
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.Instant instant,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaZone(zone);
|
||||
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toZonedDateTime
|
||||
|
||||
/**
|
||||
* 将 joda-time 中带时区的日期时间,转换为 java.time 中带时区的日期时间
|
||||
*
|
||||
* @param dateTime joda-time 中带时区的日期时间
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(org.joda.time.DateTime dateTime) {
|
||||
java.time.ZoneId zone = dateTime.getZone().toTimeZone().toZoneId();
|
||||
return toJavaInstant(dateTime.toInstant()).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 joda-time 中的 {@link org.joda.time.LocalDateTime} 和
|
||||
* {@link org.joda.time.DateTimeZone}
|
||||
* 转换为 java.time 中的 {@link java.time.ZonedDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time 中的地区时间
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return java.time 中带时区的日期时间
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(localDateTime, dateTimeZone).atZone(zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 joda-time 中的 {@link org.joda.time.Instant} 在指定时区的时间,用 Java 8
|
||||
* {@link java.time.ZonedDateTime} 表示
|
||||
*
|
||||
* @param instant joda-time 中的时间戳
|
||||
* @param dateTimeZone joda-time 中的时区
|
||||
* @return
|
||||
*/
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.Instant instant,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(instant).atZone(zone);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toJodaLocalDateTime
|
||||
|
||||
/**
|
||||
* 将 {@link java.time.LocalDateTime} 转换为 {@link org.joda.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime Java 8 LocalDateTime
|
||||
* @return joda-time LocalDateTime
|
||||
*/
|
||||
public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) {
|
||||
java.time.ZoneId javaZone = java.time.ZoneId.systemDefault();
|
||||
org.joda.time.DateTimeZone jodaZone = toJodaZone(javaZone);
|
||||
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - toJavaLocalDateTime
|
||||
|
||||
/**
|
||||
* 将 {@link org.joda.time.LocalDateTime} 转换为 {@link java.time.LocalDateTime}
|
||||
*
|
||||
* @param localDateTime joda-time LocalDateTime
|
||||
* @return Java 8 LocalDateTime
|
||||
*/
|
||||
public static java.time.LocalDateTime toJavaLocalDateTime(org.joda.time.LocalDateTime localDateTime) {
|
||||
org.joda.time.DateTimeZone jodaZone = org.joda.time.DateTimeZone.getDefault();
|
||||
java.time.ZoneId javaZone = toJavaZone(jodaZone);
|
||||
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - ZoneId <--> DateTimeZone
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param jodaZone joda-time API 中表示时区的对象
|
||||
* @return Java API 中表示时区的对象
|
||||
*/
|
||||
public static java.time.ZoneId toJavaZone(org.joda.time.DateTimeZone jodaZone) {
|
||||
return jodaZone.toTimeZone().toZoneId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换 Java API 和 joda-time API 表示时区的对象
|
||||
*
|
||||
* @param zone Java API 中表示时区的对象
|
||||
* @return joda-time API 中表示时区的对象
|
||||
*/
|
||||
public static org.joda.time.DateTimeZone toJodaZone(java.time.ZoneId zone) {
|
||||
return org.joda.time.DateTimeZone.forID(zone.getId());
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - YearQuarter & Quarter
|
||||
|
||||
/**
|
||||
* 获取指定日期所在季度
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 日期所在的季度
|
||||
*/
|
||||
public static YearQuarter getQuarter(Date date) {
|
||||
return YearQuarter.of(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在季度
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 日期所在的季度
|
||||
*/
|
||||
public static YearQuarter getQuarter(Calendar date) {
|
||||
return YearQuarter.of(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定月份所在季度
|
||||
*
|
||||
* @param month 月份
|
||||
* @return 季度
|
||||
*/
|
||||
public static Quarter getQuarter(Month month) {
|
||||
return Quarter.fromMonth(month);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年月所在季度
|
||||
*
|
||||
* @param year 年
|
||||
* @param month 月
|
||||
* @return 季度
|
||||
*/
|
||||
public static YearQuarter getQuarter(int year, Month month) {
|
||||
return YearQuarter.of(YearMonth.of(year, month));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年月所在季度
|
||||
*
|
||||
* @param yearMonth 年月
|
||||
* @return 季度
|
||||
*/
|
||||
public static YearQuarter getQuarter(YearMonth yearMonth) {
|
||||
return YearQuarter.of(yearMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期所在季度
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 日期所在的季度
|
||||
*/
|
||||
public static YearQuarter getQuarter(LocalDate date) {
|
||||
return YearQuarter.of(date);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* 私有构造方法,明确标识该常量类的作用。
|
||||
*/
|
||||
private DateTimeTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
331
src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeUtil.java
Normal file
331
src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeUtil.java
Normal file
@@ -0,0 +1,331 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.MapWrapper;
|
||||
|
||||
public class DateTimeUtil {
|
||||
|
||||
private static final MapWrapper<String, DateTimeFormatter> DATE_TIME_FORMATTER_CACHE = MapWrapper
|
||||
.<String, DateTimeFormatter>wrap(new SafeConcurrentHashMap<>())
|
||||
.keyChecker(pattern -> Preconditions.checkArgument(StringUtils.isNotBlank(pattern), "The pattern could not be blank."))
|
||||
.valueChecker(formatter -> Preconditions.checkNotNull(formatter, "The formatter could not be null."))
|
||||
.build();
|
||||
|
||||
public static DateTimeFormatter getDateTimeFormatter(String pattern) {
|
||||
return DATE_TIME_FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
|
||||
}
|
||||
|
||||
public static String toString(String pattern, ZonedDateTime dateTime) {
|
||||
return getDateTimeFormatter(pattern).format(dateTime);
|
||||
}
|
||||
|
||||
public static String toString(String pattern, Instant instant) {
|
||||
ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault());
|
||||
return toString(pattern, dateTime);
|
||||
}
|
||||
|
||||
public static String toString(String pattern, Instant instant, ZoneId zone) {
|
||||
ZonedDateTime dateTime = instant.atZone(zone);
|
||||
return toString(pattern, dateTime);
|
||||
}
|
||||
|
||||
public static String nowStr(String pattern) {
|
||||
return toString(pattern, ZonedDateTime.now());
|
||||
}
|
||||
|
||||
public static String nowStr(String pattern, ZoneId zone) {
|
||||
return toString(pattern, Instant.now().atZone(zone));
|
||||
}
|
||||
|
||||
// toDate
|
||||
|
||||
public static Date toDate(long timeMillis) {
|
||||
return Date.from(Instant.ofEpochMilli(timeMillis));
|
||||
}
|
||||
|
||||
public static Date toDate(Calendar calendar) {
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static Date toDate(Instant instant) {
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
public static Date toDate(ZonedDateTime zonedDateTime) {
|
||||
return Date.from(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
public static Date toDate(LocalDateTime localDateTime, ZoneId zone) {
|
||||
return Date.from(ZonedDateTime.of(localDateTime, zone).toInstant());
|
||||
}
|
||||
|
||||
public static Date toDate(LocalDate localDate, LocalTime localTime, ZoneId zone) {
|
||||
return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant());
|
||||
}
|
||||
|
||||
// toInstant
|
||||
|
||||
public static Instant toInstant(long timeMillis) {
|
||||
return Instant.ofEpochMilli(timeMillis);
|
||||
}
|
||||
|
||||
public static Instant toInstant(Date date) {
|
||||
return date.toInstant();
|
||||
}
|
||||
|
||||
public static Instant toInstant(Calendar calendar) {
|
||||
return calendar.toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Instant} 对象
|
||||
*
|
||||
* @param zonedDateTime 带时区信息的地区时间
|
||||
* @return 时间点
|
||||
*
|
||||
* @deprecated 使用 {@link ZonedDateTime#toInstant()}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Instant toInstant(ZonedDateTime zonedDateTime) {
|
||||
return zonedDateTime.toInstant();
|
||||
}
|
||||
|
||||
public static Instant toInstant(LocalDateTime localDateTime, ZoneId zone) {
|
||||
return ZonedDateTime.of(localDateTime, zone).toInstant();
|
||||
}
|
||||
|
||||
// toZonedDateTime
|
||||
|
||||
/**
|
||||
* 获取时间戳在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @param zone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(long timeMillis, ZoneId zone) {
|
||||
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param zone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Date dateTime, ZoneId zone) {
|
||||
return ZonedDateTime.ofInstant(dateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
* <p>
|
||||
* 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上表示的还是还是同一时间戳的时间,
|
||||
* 只是不同时区的表示。
|
||||
* </p>
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param timeZone 时区
|
||||
* @return 带时区信息的地区时间
|
||||
*/
|
||||
public static ZonedDateTime toZonedDateTime(Date dateTime, TimeZone timeZone) {
|
||||
return ZonedDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId());
|
||||
}
|
||||
|
||||
public static ZonedDateTime toZonedDateTime(Calendar calendar, ZoneId zone) {
|
||||
return calendar.toInstant().atZone(zone);
|
||||
}
|
||||
|
||||
public static ZonedDateTime toZonedDateTime(Calendar calendar, TimeZone zone) {
|
||||
return calendar.toInstant().atZone(zone.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带时区的地区时间
|
||||
*
|
||||
* @param localDateTime 地区时间
|
||||
* @param zone 时区
|
||||
* @return 带时区的地区时间
|
||||
*
|
||||
* @deprecated 使用 {@link ZonedDateTime#of(LocalDateTime, ZoneId)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, ZoneId zone) {
|
||||
return ZonedDateTime.of(localDateTime, zone);
|
||||
}
|
||||
|
||||
// toLocalDateTime
|
||||
|
||||
/**
|
||||
* 获取时间戳在指定时区的地区时间。
|
||||
*
|
||||
* @param timeMillis 时间戳
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param zone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Date dateTime, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(dateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。
|
||||
*
|
||||
* @param dateTime {@link Date} 对象
|
||||
* @param timeZone 时区
|
||||
* @return 地区时间
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Date dateTime, TimeZone timeZone) {
|
||||
return LocalDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId());
|
||||
}
|
||||
|
||||
public static LocalDateTime toLocalDateTime(Calendar calendar, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(calendar.toInstant(), zone);
|
||||
}
|
||||
|
||||
public static LocalDateTime toLocalDateTime(Calendar calendar, TimeZone zone) {
|
||||
return LocalDateTime.ofInstant(calendar.toInstant(), zone.toZoneId());
|
||||
}
|
||||
|
||||
public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime, ZoneId zone) {
|
||||
return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone);
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// toJodaInstant
|
||||
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.Instant instant) {
|
||||
return new org.joda.time.Instant(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.ZonedDateTime zonedDateTime) {
|
||||
return toJodaInstant(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
public static org.joda.time.Instant toJodaInstant(java.time.LocalDateTime localDateTime, java.time.ZoneId zone) {
|
||||
return toJodaInstant(java.time.ZonedDateTime.of(localDateTime, zone));
|
||||
}
|
||||
|
||||
// toJavaInstant
|
||||
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.Instant instant) {
|
||||
return toInstant(instant.getMillis());
|
||||
}
|
||||
|
||||
public static java.time.Instant toJavaInstant(org.joda.time.DateTime dateTime) {
|
||||
return toInstant(dateTime.getMillis());
|
||||
}
|
||||
|
||||
public static java.time.Instant toJavaInstant(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone zone) {
|
||||
return toJavaInstant(localDateTime.toDateTime(zone));
|
||||
}
|
||||
|
||||
// toJodaDateTime
|
||||
|
||||
public static org.joda.time.DateTime toJodaDateTime(java.time.ZonedDateTime zonedDateTime) {
|
||||
org.joda.time.DateTimeZone zone = org.joda.time.DateTimeZone.forID(zonedDateTime.getZone().getId());
|
||||
return toJodaInstant(zonedDateTime.toInstant()).toDateTime(zone);
|
||||
}
|
||||
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.LocalDateTime localDateTime,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaTime(zone);
|
||||
return toJodaInstant(ZonedDateTime.of(localDateTime, zone).toInstant()).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
public static org.joda.time.DateTime toJodaDateTime(
|
||||
java.time.Instant instant,
|
||||
java.time.ZoneId zone) {
|
||||
org.joda.time.DateTimeZone dateTimeZone = toJodaTime(zone);
|
||||
return toJodaInstant(instant).toDateTime(dateTimeZone);
|
||||
}
|
||||
|
||||
// toZonedDateTime
|
||||
|
||||
public static java.time.ZonedDateTime toZonedDateTime(org.joda.time.DateTime dateTime) {
|
||||
java.time.ZoneId zone = dateTime.getZone().toTimeZone().toZoneId();
|
||||
return toJavaInstant(dateTime.toInstant()).atZone(zone);
|
||||
}
|
||||
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.LocalDateTime localDateTime,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(localDateTime, dateTimeZone).atZone(zone);
|
||||
}
|
||||
|
||||
public static java.time.ZonedDateTime toZonedDateTime(
|
||||
org.joda.time.Instant instant,
|
||||
org.joda.time.DateTimeZone dateTimeZone) {
|
||||
java.time.ZoneId zone = toJavaZone(dateTimeZone);
|
||||
return toJavaInstant(instant).atZone(zone);
|
||||
}
|
||||
|
||||
// toJodaLocalDateTime
|
||||
|
||||
public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) {
|
||||
java.time.ZoneId javaZone = java.time.ZoneId.systemDefault();
|
||||
org.joda.time.DateTimeZone jodaZone = toJodaTime(javaZone);
|
||||
return toJodaInstant(localDateTime, javaZone).toDateTime(jodaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
// toJavaLocalDateTime
|
||||
|
||||
public static java.time.LocalDateTime toJavaLocalDateTime(org.joda.time.LocalDateTime localDateTime) {
|
||||
org.joda.time.DateTimeZone jodaZone = org.joda.time.DateTimeZone.getDefault();
|
||||
java.time.ZoneId javaZone = toJavaZone(jodaZone);
|
||||
return toJavaInstant(localDateTime, jodaZone).atZone(javaZone).toLocalDateTime();
|
||||
}
|
||||
|
||||
public static java.time.ZoneId toJavaZone(org.joda.time.DateTimeZone jodaZone) {
|
||||
return jodaZone.toTimeZone().toZoneId();
|
||||
}
|
||||
|
||||
public static DateTimeZone toJodaTime(java.time.ZoneId zone) {
|
||||
return org.joda.time.DateTimeZone.forID(zone.getId());
|
||||
}
|
||||
|
||||
private DateTimeUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -25,11 +25,11 @@ import com.google.common.base.Preconditions;
|
||||
/**
|
||||
* 枚举工具类
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public final class EnumTools {
|
||||
public final class EnumUtil {
|
||||
|
||||
private EnumTools() {
|
||||
private EnumUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ public final class EnumTools {
|
||||
* @deprecated 不推荐使用枚举的 ordinal。
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> clazz, int ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> clazz, int ordinal) {
|
||||
Preconditions.checkNotNull(clazz, "Clazz must not be null.");
|
||||
E[] values = clazz.getEnumConstants();
|
||||
AssertTools.checkCondition((ordinal >= 0 && ordinal < values.length),
|
||||
PreconditionsExt.check((ordinal >= 0 && ordinal < values.length),
|
||||
() -> new EnumConstantNotPresentException(clazz, Integer.toString(ordinal)));
|
||||
return values[ordinal];
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public final class EnumTools {
|
||||
* @deprecated 不推荐使用枚举的 ordinal。
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> clazz, @Nullable Integer ordinal, E defaultValue) { // NOSONAR 该方法弃用,但不删掉
|
||||
public static <E extends Enum<?>> E valueOf(Class<E> clazz, @Nullable Integer ordinal, E defaultValue) {
|
||||
if (null == ordinal) {
|
||||
return defaultValue;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public final class EnumTools {
|
||||
* @deprecated 不推荐使用枚举的 ordinal。
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E getValueOrDefault( // NOSONAR 该方法弃用,但不删掉
|
||||
public static <E extends Enum<?>> E getValueOrDefault(
|
||||
Class<E> clazz,
|
||||
@Nullable Integer ordinal,
|
||||
Supplier<E> defaultValue) {
|
||||
@@ -100,7 +100,7 @@ public final class EnumTools {
|
||||
* @deprecated 不推荐使用枚举的 ordinal。
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E getValueOrDefault(Class<E> clazz, @Nullable Integer ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
public static <E extends Enum<?>> E getValueOrDefault(Class<E> clazz, @Nullable Integer ordinal) {
|
||||
return getValueOrDefault(clazz, ordinal, () -> {
|
||||
Preconditions.checkNotNull(clazz, "Clazz must not be null.");
|
||||
E[] values = clazz.getEnumConstants();
|
||||
@@ -118,7 +118,7 @@ public final class EnumTools {
|
||||
* @deprecated 不推荐使用枚举的 ordinal。
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends Enum<?>> E getValueNullable(Class<E> clazz, @Nullable Integer ordinal) { // NOSONAR 该方法弃用,但不删掉
|
||||
public static <E extends Enum<?>> E getValueNullable(Class<E> clazz, @Nullable Integer ordinal) {
|
||||
return valueOf(clazz, ordinal, null);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public final class EnumTools {
|
||||
|
||||
/**
|
||||
* 校验枚举的 ordinal。
|
||||
*
|
||||
*
|
||||
* @param <E> 枚举类型
|
||||
* @param clazz 枚举类型
|
||||
* @param ordinal The ordinal
|
||||
@@ -147,7 +147,7 @@ public final class EnumTools {
|
||||
|
||||
/**
|
||||
* 校验枚举的 ordinal,如果 ordinal 为 {@code null},则返回 {@code 0}。
|
||||
*
|
||||
*
|
||||
* @param <E> 枚举类型
|
||||
* @param clazz 枚举类型
|
||||
* @param ordinal The ordinal
|
||||
@@ -160,7 +160,7 @@ public final class EnumTools {
|
||||
|
||||
/**
|
||||
* 校验枚举的 ordinal,如果 ordinal 为 {@code null},则返回 {@code defaultValue}。
|
||||
*
|
||||
*
|
||||
* @param <E> 枚举类型
|
||||
* @param clazz 枚举类型
|
||||
* @param ordinal The ordinal
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -30,20 +30,13 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
|
||||
/**
|
||||
* 枚举类
|
||||
*
|
||||
* 参考 <a href="https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/">Enumeration classes</a>
|
||||
*
|
||||
* @deprecated 设计 Enumeration 的灵感来自于 .net 社区,因为 C# 的枚举不带行为。
|
||||
* 但 Java 的枚举可以带行为,故大多数情况下不需要这种设计。
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移除
|
||||
implements Comparable<T> {
|
||||
public abstract class Enumeration<T extends Enumeration<T>> implements Comparable<T> {
|
||||
protected final int id;
|
||||
protected final String name;
|
||||
|
||||
protected Enumeration(final int id, final String name) {
|
||||
Preconditions.checkArgument(StringTools.isNotBlank(name), "Name of enumeration must has text.");
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(name), "Name of enumeration must has text.");
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
@@ -90,15 +83,18 @@ public abstract class Enumeration<T extends Enumeration<T>> // NOSONAR 暂不移
|
||||
this.valueMap = valueMap;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@StaticFactoryMethod(ValueSet.class)
|
||||
public static <T extends Enumeration<T>> ValueSet<T> of(T[] values) {
|
||||
Map<Integer, T> temp = Arrays.stream(values)
|
||||
.collect(Collectors.toMap(Enumeration::getId, Function.identity()));
|
||||
public static <T extends Enumeration<T>> ValueSet<T> of(T... values) {
|
||||
Map<Integer, T> temp = new HashMap<>();
|
||||
for (T value : values) {
|
||||
temp.put(value.getId(), value);
|
||||
}
|
||||
return new ValueSet<>(Collections.unmodifiableMap(temp));
|
||||
}
|
||||
|
||||
public T get(int id) {
|
||||
Preconditions.checkArgument(this.valueMap.containsKey(id), "[%s] 对应的值不存在", id);
|
||||
Preconditions.checkArgument(this.valueMap.containsKey(id), "%s 对应的值不存在", id);
|
||||
return this.valueMap.get(id);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,40 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
|
||||
/**
|
||||
* 错误结果
|
||||
*
|
||||
* @author zhouxy
|
||||
*/
|
||||
final class ErrorResult extends UnifiedResponse {
|
||||
private static final String DEFAULT_ERR_STATUS = "9999999";
|
||||
|
||||
ErrorResult(String message) {
|
||||
super(DEFAULT_ERR_STATUS, message);
|
||||
}
|
||||
|
||||
ErrorResult(String message, Object data) {
|
||||
super(DEFAULT_ERR_STATUS, message, data);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, String message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, String message, Object data) {
|
||||
super(status, message, data);
|
||||
}
|
||||
|
||||
ErrorResult(Object status, Throwable e) {
|
||||
super(status, Strings.nullToEmpty(e.getMessage()));
|
||||
}
|
||||
|
||||
<E extends Throwable & IWithCode<?>> ErrorResult(E e) {
|
||||
super(e.getCode(), Strings.nullToEmpty(e.getMessage()));
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1680792957826923092L;
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -40,15 +24,15 @@ public class IdGenerator {
|
||||
}
|
||||
|
||||
public static String toSimpleString(UUID uuid) {
|
||||
return (uuidDigits(uuid.getMostSignificantBits() >> 32, 8) +
|
||||
uuidDigits(uuid.getMostSignificantBits() >> 16, 4) +
|
||||
uuidDigits(uuid.getMostSignificantBits(), 4) +
|
||||
uuidDigits(uuid.getLeastSignificantBits() >> 48, 4) +
|
||||
uuidDigits(uuid.getLeastSignificantBits(), 12));
|
||||
return (digits(uuid.getMostSignificantBits() >> 32, 8) +
|
||||
digits(uuid.getMostSignificantBits() >> 16, 4) +
|
||||
digits(uuid.getMostSignificantBits(), 4) +
|
||||
digits(uuid.getLeastSignificantBits() >> 48, 4) +
|
||||
digits(uuid.getLeastSignificantBits(), 12));
|
||||
}
|
||||
|
||||
/** Returns val represented by the specified number of hex digits. */
|
||||
private static String uuidDigits(long val, int digits) {
|
||||
private static String digits(long val, int digits) {
|
||||
long hi = 1L << (digits * 4);
|
||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
||||
}
|
||||
|
@@ -1,30 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
||||
|
||||
|
||||
/**
|
||||
* IdWorker from Seata.
|
||||
*
|
||||
* @author funkye
|
||||
* @author selfishlover
|
||||
*/
|
||||
public class IdWorker {
|
||||
|
||||
/**
|
||||
@@ -76,9 +74,8 @@ public class IdWorker {
|
||||
|
||||
/**
|
||||
* instantiate an IdWorker using given workerId
|
||||
* @param workerId if null, then will auto assign one
|
||||
*/
|
||||
public IdWorker(Long workerId) {
|
||||
public IdWorker(long workerId) {
|
||||
initTimestampAndSequence();
|
||||
initWorkerId(workerId);
|
||||
}
|
||||
@@ -96,10 +93,7 @@ public class IdWorker {
|
||||
* init workerId
|
||||
* @param workerId if null, then auto generate one
|
||||
*/
|
||||
private void initWorkerId(Long workerId) {
|
||||
if (workerId == null) {
|
||||
workerId = generateWorkerId();
|
||||
}
|
||||
private void initWorkerId(long workerId) {
|
||||
if (workerId > MAX_WORKER_ID || workerId < 0) {
|
||||
String message = String.format("worker Id can't be greater than %d or less than 0", MAX_WORKER_ID);
|
||||
throw new IllegalArgumentException(message);
|
||||
@@ -133,7 +127,8 @@ public class IdWorker {
|
||||
if (current >= newest) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException ignore) { // NOSONAR don't care
|
||||
} catch (InterruptedException ignore) {
|
||||
// don't care
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,45 +139,4 @@ public class IdWorker {
|
||||
private long getNewestTimestamp() {
|
||||
return System.currentTimeMillis() - TWEPOCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* auto generate workerId, try using mac first, if failed, then randomly generate one
|
||||
* @return workerId
|
||||
*/
|
||||
private static long generateWorkerId() {
|
||||
try {
|
||||
return generateWorkerIdBaseOnMac();
|
||||
} catch (Exception e) {
|
||||
return generateRandomWorkerId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* use lowest 10 bit of available MAC as workerId
|
||||
* @return workerId
|
||||
* @throws SocketException
|
||||
* @throws NoAvailableMacFoundException when there is no available mac found
|
||||
*/
|
||||
private static long generateWorkerIdBaseOnMac() throws SocketException, NoAvailableMacFoundException {
|
||||
Enumeration<NetworkInterface> all = NetworkInterface.getNetworkInterfaces();
|
||||
while (all.hasMoreElements()) {
|
||||
NetworkInterface networkInterface = all.nextElement();
|
||||
boolean isLoopback = networkInterface.isLoopback();
|
||||
boolean isVirtual = networkInterface.isVirtual();
|
||||
byte[] mac = networkInterface.getHardwareAddress();
|
||||
if (isLoopback || isVirtual || mac == null) {
|
||||
continue;
|
||||
}
|
||||
return ((mac[4] & 0B11) << 8) | (mac[5] & 0xFF);
|
||||
}
|
||||
throw new NoAvailableMacFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* randomly generate one as workerId
|
||||
* @return workerId
|
||||
*/
|
||||
private static long generateRandomWorkerId() {
|
||||
return ThreadLocalRandom.current().nextInt(MAX_WORKER_ID + 1);
|
||||
}
|
||||
}
|
||||
}
|
119
src/main/java/xyz/zhouxy/plusone/commons/util/MoreArrays.java
Normal file
119
src/main/java/xyz/zhouxy/plusone/commons/util/MoreArrays.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class MoreArrays {
|
||||
|
||||
public static float[] concatFloatArray(Collection<float[]> arrays) {
|
||||
int length = 0;
|
||||
for (float[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
float[] result = new float[length];
|
||||
int i = 0;
|
||||
for (float[] arr : arrays) {
|
||||
System.arraycopy(arr, 0, result, i, arr.length);
|
||||
i = arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static double[] concatDoubleArray(Collection<double[]> arrays) {
|
||||
int length = 0;
|
||||
for (double[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
double[] result = new double[length];
|
||||
int i = 0;
|
||||
for (double[] arr : arrays) {
|
||||
System.arraycopy(arr, 0, result, i, arr.length);
|
||||
i = arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] concatByteArray(Collection<byte[]> arrays) {
|
||||
int length = 0;
|
||||
for (byte[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
byte[] result = new byte[length];
|
||||
int i = 0;
|
||||
for (byte[] arr : arrays) {
|
||||
System.arraycopy(arr, 0, result, i, arr.length);
|
||||
i = arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long[] concatLongArray(Collection<long[]> arrays) {
|
||||
int length = 0;
|
||||
for (long[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
long[] result = new long[length];
|
||||
int i = 0;
|
||||
for (long[] arr : arrays) {
|
||||
System.arraycopy(arr, 0, result, i, arr.length);
|
||||
i = arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] concatIntArray(Collection<int[]> arrays) {
|
||||
int length = 0;
|
||||
for (int[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
int[] result = new int[length];
|
||||
int i = 0;
|
||||
for (int[] arr : arrays) {
|
||||
System.arraycopy(arr, 0, result, i, arr.length);
|
||||
i = arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> List<T> concatToList(@Nullable Collection<T[]> arrays) {
|
||||
if (arrays == null || arrays.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
int length = 0;
|
||||
for (T[] arr : arrays) {
|
||||
length += arr.length;
|
||||
}
|
||||
final List<T> result = new ArrayList<>(length);
|
||||
for (T[] arr : arrays) {
|
||||
Collections.addAll(result, arr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private MoreArrays() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,169 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap;
|
||||
import xyz.zhouxy.plusone.commons.collection.SynchronizedTable;
|
||||
|
||||
public class MoreCollections {
|
||||
|
||||
// isEmpty
|
||||
|
||||
public static boolean isEmpty(@Nullable Collection<?> collection) {
|
||||
return collection == null || collection.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isEmpty(@Nullable Map<?, ?> map) {
|
||||
return map == null || map.isEmpty();
|
||||
}
|
||||
|
||||
// isNotEmpty
|
||||
|
||||
public static boolean isNotEmpty(@Nullable Collection<?> collection) {
|
||||
return collection != null && !collection.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isNotEmpty(@Nullable Map<?, ?> map) {
|
||||
return map != null && !map.isEmpty();
|
||||
}
|
||||
|
||||
// Collection -> Map
|
||||
|
||||
public static <K, V> HashMap<K, V> toHashMap(
|
||||
Iterable<V> c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
int initialCapacity) {
|
||||
HashMap<K, V> map = new HashMap<>(initialCapacity);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> HashMap<K, V> toHashMap(
|
||||
Collection<V> c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
return toHashMap(c, keyGenerator, c.size());
|
||||
}
|
||||
|
||||
public static <K, V> SafeConcurrentHashMap<K, V> toConcurrentHashMap(
|
||||
Iterable<V> c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
int initialCapacity) {
|
||||
SafeConcurrentHashMap<K, V> map = new SafeConcurrentHashMap<>(initialCapacity);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> SafeConcurrentHashMap<K, V> toConcurrentHashMap(
|
||||
Collection<V> c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
return toConcurrentHashMap(c, keyGenerator, c.size());
|
||||
}
|
||||
|
||||
public static <K extends Comparable<? super K>, V> TreeMap<K, V> toTreeMap(
|
||||
Iterable<V> c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
TreeMap<K, V> map = new TreeMap<>();
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> TreeMap<K, V> toTreeMap(
|
||||
Iterable<V> c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
Comparator<? super K> keycComparator) {
|
||||
TreeMap<K, V> map = new TreeMap<>(keycComparator);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> void fillIntoEmptyMap(
|
||||
Map<K, ? super V> map,
|
||||
Iterable<V> c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
Preconditions.checkNotNull(map);
|
||||
Preconditions.checkNotNull(c);
|
||||
Preconditions.checkNotNull(keyGenerator);
|
||||
Preconditions.checkArgument(map.isEmpty(), "The map should be empty.");
|
||||
for (V v : c) {
|
||||
map.put(keyGenerator.apply(v), v);
|
||||
}
|
||||
}
|
||||
|
||||
// array -> map
|
||||
|
||||
public static <K, V> HashMap<K, V> toHashMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
int initialCapacity) {
|
||||
HashMap<K, V> map = new HashMap<>(initialCapacity);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> HashMap<K, V> toHashMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
return toHashMap(c, keyGenerator, c.length);
|
||||
}
|
||||
|
||||
public static <K, V> SafeConcurrentHashMap<K, V> toConcurrentHashMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
int initialCapacity) {
|
||||
SafeConcurrentHashMap<K, V> map = new SafeConcurrentHashMap<>(initialCapacity);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> SafeConcurrentHashMap<K, V> toConcurrentHashMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
return toConcurrentHashMap(c, keyGenerator, c.length);
|
||||
}
|
||||
|
||||
public static <K extends Comparable<? super K>, V> TreeMap<K, V> toTreeMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
TreeMap<K, V> map = new TreeMap<>();
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> TreeMap<K, V> toTreeMap(
|
||||
V[] c,
|
||||
Function<? super V, K> keyGenerator,
|
||||
Comparator<? super K> keyComparator) {
|
||||
TreeMap<K, V> map = new TreeMap<>(keyComparator);
|
||||
fillIntoEmptyMap(map, c, keyGenerator);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> void fillIntoEmptyMap(
|
||||
Map<K, ? super V> map, V[] c,
|
||||
Function<? super V, K> keyGenerator) {
|
||||
fillIntoEmptyMap(map, Arrays.asList(c), keyGenerator);
|
||||
}
|
||||
|
||||
public static <R, C, V> Table<R, C, V> synchronizedTable(Table<R, C, V> t) {
|
||||
if (t instanceof SynchronizedTable) {
|
||||
return t;
|
||||
} else {
|
||||
return SynchronizedTable.of(t);
|
||||
}
|
||||
}
|
||||
|
||||
private MoreCollections() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -16,20 +16,18 @@
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Numbers
|
||||
* NumberUtil
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public class Numbers {
|
||||
|
||||
// #region - sum
|
||||
private Numbers() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// sum
|
||||
|
||||
public static int sum(final short... numbers) {
|
||||
int result = 0;
|
||||
@@ -71,61 +69,25 @@ public class Numbers {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BigInteger sum(final BigInteger... numbers) {
|
||||
if (ArrayTools.isNullOrEmpty(numbers)) {
|
||||
return BigInteger.ZERO;
|
||||
}
|
||||
BigInteger result = Numbers.nullToZero(numbers[0]);
|
||||
for (int i = 1; i < numbers.length; i++) {
|
||||
BigInteger value = numbers[i];
|
||||
if (value != null) {
|
||||
result = result.add(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
// between
|
||||
|
||||
public static boolean between(short value, short min, short max) {
|
||||
return value >= min && value < max;
|
||||
}
|
||||
|
||||
public static BigDecimal sum(final BigDecimal... numbers) {
|
||||
return BigDecimals.sum(numbers);
|
||||
public static boolean between(int value, int min, int max) {
|
||||
return value >= min && value < max;
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region - nullToZero
|
||||
|
||||
public static short nullToZero(@Nullable final Short val) {
|
||||
return val != null ? val : 0;
|
||||
public static boolean between(long value, long min, long max) {
|
||||
return value >= min && value < max;
|
||||
}
|
||||
|
||||
public static int nullToZero(@Nullable final Integer val) {
|
||||
return val != null ? val : 0;
|
||||
public static boolean between(float value, float min, float max) {
|
||||
return value >= min && value < max;
|
||||
}
|
||||
|
||||
public static long nullToZero(@Nullable final Long val) {
|
||||
return val != null ? val : 0L;
|
||||
}
|
||||
|
||||
public static float nullToZero(@Nullable final Float val) {
|
||||
return val != null ? val : 0.0F;
|
||||
}
|
||||
|
||||
public static double nullToZero(@Nullable final Double val) {
|
||||
return val != null ? val : 0.0;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static BigInteger nullToZero(@Nullable final BigInteger val) {
|
||||
return val != null ? val : BigInteger.ZERO;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static BigDecimal nullToZero(@Nullable final BigDecimal val) {
|
||||
return BigDecimals.nullToZero(val);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
private Numbers() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
public static boolean between(double value, double min, double max) {
|
||||
return value >= min && value < max;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -31,14 +31,14 @@ import com.google.common.annotations.Beta;
|
||||
* <p>
|
||||
* 提供一些 Optional 相关的方法
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @since 0.1.0
|
||||
* @see Optional
|
||||
* @see OptionalInt
|
||||
* @see OptionalLong
|
||||
* @see OptionalDouble
|
||||
*/
|
||||
public class OptionalTools {
|
||||
public class OptionalUtil {
|
||||
|
||||
/**
|
||||
* 将包装类 {@link Integer} 转为 {@link OptionalInt}(not null)。
|
||||
@@ -46,7 +46,7 @@ public class OptionalTools {
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalInt} 后,由
|
||||
* {@link OptionalInt#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalInt} 实例
|
||||
*/
|
||||
@@ -59,12 +59,12 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* {@code Optional<Integer>} 将整数包装了两次,改为使用 {@link OptionalInt} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param optionalObj {@code Optional<Integer>} 对象
|
||||
* @return {@link OptionalInt} 实例
|
||||
*/
|
||||
public static OptionalInt toOptionalInt(Optional<Integer> optionalObj) {
|
||||
return optionalObj.isPresent() ? OptionalInt.of(optionalObj.get()) : OptionalInt.empty();
|
||||
return optionalOf(optionalObj.orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +73,7 @@ public class OptionalTools {
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalLong} 后,由
|
||||
* {@link OptionalLong#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalLong} 实例
|
||||
*/
|
||||
@@ -86,12 +86,12 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* {@code Optional<Long>} 将整数包装了两次,改为使用 {@link OptionalLong} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param optionalObj 包装对象
|
||||
* @return {@link OptionalLong} 实例
|
||||
*/
|
||||
public static OptionalLong toOptionalLong(Optional<Long> optionalObj) {
|
||||
return optionalObj.isPresent() ? OptionalLong.of(optionalObj.get()) : OptionalLong.empty();
|
||||
return optionalOf(optionalObj.orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +100,7 @@ public class OptionalTools {
|
||||
* 包装类为 {@code null} 表示值的缺失,转为 {@link OptionalDouble} 后,由
|
||||
* {@link OptionalDouble#empty()} 表示值的缺失。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param value 包装对象
|
||||
* @return {@link OptionalDouble} 实例
|
||||
*/
|
||||
@@ -113,18 +113,18 @@ public class OptionalTools {
|
||||
* <p>
|
||||
* {@code Optional<Double>} 将整数包装了两次,改为使用 {@link OptionalDouble} 包装其中的整数数据。
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param optionalObj 包装对象
|
||||
* @return {@link OptionalDouble} 实例
|
||||
*/
|
||||
public static OptionalDouble toOptionalDouble(Optional<Double> optionalObj) {
|
||||
return optionalObj.isPresent() ? OptionalDouble.of(optionalObj.get()) : OptionalDouble.empty();
|
||||
return optionalOf(optionalObj.orElse(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* return the value of the optional object if present,
|
||||
* otherwise {@code null}.
|
||||
*
|
||||
*
|
||||
* @param <T> the class of the value
|
||||
* @param optionalObj {@link Optional} object, which must be non-null.
|
||||
* @return the value of the optional object if present, otherwise {@code null}.
|
||||
@@ -149,7 +149,7 @@ public class OptionalTools {
|
||||
return optionalObj.isPresent() ? optionalObj.getAsDouble() : null;
|
||||
}
|
||||
|
||||
private OptionalTools() {
|
||||
private OptionalUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model.dto;
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,24 +27,24 @@ import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
*
|
||||
* @param <T> 内容列表的元素类型
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see PagingAndSortingQueryParams
|
||||
*/
|
||||
public class PageResult<T> {
|
||||
public class PageDTO<T> {
|
||||
|
||||
private final long total;
|
||||
|
||||
private final List<T> content;
|
||||
|
||||
private PageResult(List<T> content, long total) {
|
||||
private PageDTO(List<T> content, long total) {
|
||||
Preconditions.checkNotNull(content, "Content must not be null.");
|
||||
this.content = content;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
@StaticFactoryMethod(PageResult.class)
|
||||
public static <T> PageResult<T> of(List<T> content, long total) {
|
||||
return new PageResult<>(content, total);
|
||||
@StaticFactoryMethod(PageDTO.class)
|
||||
public static <T> PageDTO<T> of(List<T> content, long total) {
|
||||
return new PageDTO<>(content, total);
|
||||
}
|
||||
|
||||
public long getTotal() {
|
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.Overridable;
|
||||
|
||||
/**
|
||||
* 分页排序查询参数
|
||||
*
|
||||
* <p>
|
||||
* 根据传入的 {@code size} 和 {@code pageNum},
|
||||
* 提供 {@code getOffset} 方法计算 SQL 语句中 {@code offset} 的值。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see PageDTO
|
||||
*/
|
||||
public class PagingAndSortingQueryParams {
|
||||
|
||||
private static final int DEFAULT_PAGE_SIZE = 15;
|
||||
|
||||
private int size;
|
||||
private long pageNum;
|
||||
private final List<String> orderBy = new LinkedList<>();
|
||||
|
||||
private final Set<String> sortableProperties;
|
||||
|
||||
public PagingAndSortingQueryParams() {
|
||||
this.sortableProperties = Collections.emptySet();
|
||||
}
|
||||
|
||||
public PagingAndSortingQueryParams(String... sortableProperties) {
|
||||
for (String p : sortableProperties) {
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(p), "Property name must not be blank.");
|
||||
}
|
||||
this.sortableProperties = ImmutableSet.<String>builder().add(sortableProperties).build();
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
public final List<String> getOrderBy() {
|
||||
return Collections.unmodifiableList(this.orderBy);
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public final long getPageNum() {
|
||||
return this.pageNum;
|
||||
}
|
||||
|
||||
public final long getOffset() {
|
||||
return (this.pageNum - 1) * this.size;
|
||||
}
|
||||
|
||||
// Getters end
|
||||
|
||||
// Setters
|
||||
|
||||
public final void setOrderBy(@Nullable List<String> properties) {
|
||||
this.orderBy.clear();
|
||||
if (properties != null && !properties.isEmpty()) {
|
||||
for (String colName : properties) {
|
||||
Preconditions.checkArgument(this.sortableProperties.contains(colName),
|
||||
"The property name must be in the set of sortable properties.");
|
||||
}
|
||||
this.orderBy.addAll(properties);
|
||||
}
|
||||
}
|
||||
|
||||
public final void setSize(@Nullable Integer size) {
|
||||
this.size = size != null ? size : getDefaultSize();
|
||||
}
|
||||
|
||||
public final void setPageNum(@Nullable Long pageNum) {
|
||||
this.pageNum = pageNum != null ? pageNum : 1L;
|
||||
}
|
||||
|
||||
// Setters end
|
||||
|
||||
@Overridable
|
||||
protected int getDefaultSize() {
|
||||
return DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PagingAndSortingQueryParams [size=" + size + ", pageNum=" + pageNum + ", orderBy=" + orderBy
|
||||
+ ", sortableProperties=" + sortableProperties + "]";
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Guava Preconditions 的扩展。
|
||||
*
|
||||
* @author ZhouXY
|
||||
*
|
||||
* @see com.google.common.base.Preconditions
|
||||
*/
|
||||
public class PreconditionsExt {
|
||||
|
||||
public static <E extends Throwable> void check(boolean condition, Supplier<E> e) throws E {
|
||||
if (!condition) {
|
||||
throw e.get();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, E extends Throwable> void checkAllNotNull(Iterable<T> values) throws E {
|
||||
Preconditions.checkNotNull(values);
|
||||
for (T item : values) {
|
||||
Preconditions.checkNotNull(item);
|
||||
}
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T, E extends Throwable> void checkAllNotNull(T... values) throws E {
|
||||
Preconditions.checkNotNull(values);
|
||||
for (T item : values) {
|
||||
Preconditions.checkNotNull(item);
|
||||
}
|
||||
}
|
||||
|
||||
private PreconditionsExt() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public final class RandomTools {
|
||||
|
||||
public static final SecureRandom DEFAULT_SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
public static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
public static final String LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz";
|
||||
public static final String NUMBERS = "0123456789";
|
||||
|
||||
/**
|
||||
* 使用传入的随机数生成器,生成指定长度的字符串
|
||||
*
|
||||
* @param random 随机数生成器。根据需要可以传入
|
||||
* {@link java.util.concurrent.ThreadLocalRandom}、{@link java.security.SecureRandom}
|
||||
* 等,不为空
|
||||
* @param sourceCharacters 字符池。字符串的字符将在数组中选,不为空
|
||||
* @param length 字符串长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomStr(@Nonnull Random random, @Nonnull char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(random, "Random cannot be null.");
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(random, sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String randomStr(@Nonnull char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String secureRandomStr(@Nonnull char[] sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用传入的随机数生成器,生成指定长度的字符串
|
||||
*
|
||||
* @param random 随机数生成器。根据需要可以传入
|
||||
* {@link java.util.concurrent.ThreadLocalRandom}、{@link java.security.SecureRandom}
|
||||
* 等,不为空
|
||||
* @param sourceCharacters 字符池。字符串的字符将在数组中选,不为空
|
||||
* @param length 字符串长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomStr(@Nonnull Random random, @Nonnull String sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(random, "Random cannot be null.");
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(random, sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String randomStr(@Nonnull String sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(ThreadLocalRandom.current(), sourceCharacters, length);
|
||||
}
|
||||
|
||||
public static String secureRandomStr(@Nonnull String sourceCharacters, int length) {
|
||||
AssertTools.checkArgumentNotNull(sourceCharacters, "Source characters cannot be null.");
|
||||
AssertTools.checkArgument(length >= 0, "The length should be greater than or equal to zero.");
|
||||
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用传入的随机数生成器,生成指定长度的字符串
|
||||
*
|
||||
* @param random 随机数生成器。根据需要可以传入
|
||||
* {@link java.util.concurrent.ThreadLocalRandom}、{@link java.security.SecureRandom}
|
||||
* 等,不为空
|
||||
* @param sourceCharacters 字符池。字符串的字符将在数组中选,不为空
|
||||
* @param length 字符串长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
private static String randomStrInternal(@Nonnull Random random, @Nonnull char[] sourceCharacters, int length) {
|
||||
if (length == 0) {
|
||||
return StringTools.EMPTY_STRING;
|
||||
}
|
||||
final char[] result = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = sourceCharacters[random.nextInt(sourceCharacters.length)];
|
||||
}
|
||||
return String.valueOf(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用传入的随机数生成器,生成指定长度的字符串
|
||||
*
|
||||
* @param random 随机数生成器。根据需要可以传入
|
||||
* {@link java.util.concurrent.ThreadLocalRandom}、{@link java.security.SecureRandom}
|
||||
* 等,不为空
|
||||
* @param sourceCharacters 字符池。字符串的字符将在数组中选,不为空
|
||||
* @param length 字符串长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
private static String randomStrInternal(@Nonnull Random random, @Nonnull String sourceCharacters, int length) {
|
||||
if (length == 0) {
|
||||
return StringTools.EMPTY_STRING;
|
||||
}
|
||||
final char[] result = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = sourceCharacters.charAt(random.nextInt(sourceCharacters.length()));
|
||||
}
|
||||
return String.valueOf(result);
|
||||
}
|
||||
|
||||
private RandomTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public final class RandomUtil {
|
||||
private RandomUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static String secureRandomStr(char[] sourceCharacters, int length) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
char[] result = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = sourceCharacters[random.nextInt(sourceCharacters.length)];
|
||||
}
|
||||
return String.valueOf(result);
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
* Copyright 2022-2023 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.
|
||||
@@ -19,7 +19,6 @@ package xyz.zhouxy.plusone.commons.util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -28,72 +27,74 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存大概 256 个)。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*
|
||||
* @author ZhouXY
|
||||
*
|
||||
*/
|
||||
public final class RegexTools {
|
||||
public final class RegexUtil {
|
||||
|
||||
private static final int DEFAULT_CACHE_INITIAL_CAPACITY = 64;
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
private static final Map<String, Pattern> PATTERN_CACHE
|
||||
= new ConcurrentHashMap<>(DEFAULT_CACHE_INITIAL_CAPACITY);
|
||||
= new SafeConcurrentHashMap<>(DEFAULT_CACHE_INITIAL_CAPACITY);
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern getPattern(final String pattern, final boolean cachePattern) {
|
||||
Preconditions.checkNotNull(pattern);
|
||||
return cachePattern ? cacheAndGetPatternInternal(pattern) : getPatternInternal(pattern);
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return cachePattern ? getAndCachePatternInternal(pattern) : getPatternInternal(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
public static Pattern getPattern(final String pattern) {
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return getPatternInternal(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
public static Pattern[] getPatterns(final String[] patterns, final boolean cachePattern) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
return cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
? getAndCachePatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
public static Pattern[] getPatterns(final String[] patterns) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
return getPatternsInternal(patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动缓存 Pattern 实例。
|
||||
*
|
||||
*
|
||||
* @param pattern 要缓存的 {@link Pattern} 实例
|
||||
* @return 缓存的 Pattern 实例。如果缓存已满,则返回 {@code null}。
|
||||
*/
|
||||
@@ -109,45 +110,45 @@ public final class RegexTools {
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final Pattern pattern) {
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return matchesInternal(input, pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code patterns} 中的一个。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
return matchesOneInternal(input, patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配全部正则。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final Pattern[] patterns) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
return matchesAllInternal(input, patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
@@ -155,28 +156,28 @@ public final class RegexTools {
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final String pattern,
|
||||
final boolean cachePattern) {
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
Pattern p = cachePattern
|
||||
? cacheAndGetPatternInternal(pattern)
|
||||
? getAndCachePatternInternal(pattern)
|
||||
: getPatternInternal(pattern);
|
||||
return matchesInternal(input, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matches(@Nullable final CharSequence input, final String pattern) {
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return matchesInternal(input, getPatternInternal(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code patterns} 中的一个。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
@@ -184,31 +185,31 @@ public final class RegexTools {
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns,
|
||||
final boolean cachePattern) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
final Pattern[] patternSet = cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
? getAndCachePatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
return matchesOneInternal(input, patternSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code patterns} 中的一个。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
final Pattern[] patternSet = getPatternsInternal(patterns);
|
||||
return matchesOneInternal(input, patternSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配全部正则。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
@@ -216,68 +217,68 @@ public final class RegexTools {
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns,
|
||||
final boolean cachePattern) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
final Pattern[] patternSet = cachePattern
|
||||
? cacheAndGetPatternsInternal(patterns)
|
||||
? getAndCachePatternsInternal(patterns)
|
||||
: getPatternsInternal(patterns);
|
||||
return matchesAllInternal(input, patternSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配全部正则。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param patterns 正则表达式
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns) {
|
||||
Preconditions.checkNotNull(patterns);
|
||||
Preconditions.checkArgument(allNotNull(patterns));
|
||||
Preconditions.checkNotNull(patterns, "Patterns can not be null.");
|
||||
Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null.");
|
||||
final Pattern[] patternSet = getPatternsInternal(patterns);
|
||||
return matchesAllInternal(input, patternSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Matcher。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final Pattern pattern) {
|
||||
Preconditions.checkNotNull(input);
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(input, "The input can not be null.");
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return pattern.matcher(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Matcher。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final String pattern, boolean cachePattern) {
|
||||
Preconditions.checkNotNull(input);
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(input, "The input can not be null.");
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
final Pattern p = cachePattern
|
||||
? cacheAndGetPatternInternal(pattern)
|
||||
? getAndCachePatternInternal(pattern)
|
||||
: getPatternInternal(pattern);
|
||||
return p.matcher(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Matcher。不缓存 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则表达式
|
||||
* @return 结果
|
||||
*/
|
||||
public static Matcher getMatcher(final CharSequence input, final String pattern) {
|
||||
Preconditions.checkNotNull(input);
|
||||
Preconditions.checkNotNull(pattern);
|
||||
Preconditions.checkNotNull(input, "The input can not be null.");
|
||||
Preconditions.checkNotNull(pattern, "The pattern can not be null.");
|
||||
return getPatternInternal(pattern).matcher(input);
|
||||
}
|
||||
|
||||
@@ -285,13 +286,14 @@ public final class RegexTools {
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @param cachePattern 是否缓存 {@link Pattern} 实例
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
@Nonnull
|
||||
private static Pattern cacheAndGetPatternInternal(@Nonnull final String pattern) {
|
||||
private static Pattern getAndCachePatternInternal(@Nonnull final String pattern) {
|
||||
if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) {
|
||||
return PATTERN_CACHE.computeIfAbsent(pattern, Pattern::compile);
|
||||
}
|
||||
@@ -304,10 +306,11 @@ public final class RegexTools {
|
||||
|
||||
/**
|
||||
* 获取 {@link Pattern} 实例,不缓存。
|
||||
*
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
* @return {@link Pattern} 实例
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
@Nonnull
|
||||
private static Pattern getPatternInternal(@Nonnull final String pattern) {
|
||||
Pattern result = PATTERN_CACHE.get(pattern);
|
||||
@@ -319,33 +322,35 @@ public final class RegexTools {
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
@Nonnull
|
||||
private static Pattern[] cacheAndGetPatternsInternal(@Nonnull final String[] patterns) {
|
||||
private static Pattern[] getAndCachePatternsInternal(@Nonnull final String[] patterns) {
|
||||
return Arrays.stream(patterns)
|
||||
.map(RegexTools::cacheAndGetPatternInternal)
|
||||
.map(RegexUtil::getAndCachePatternInternal)
|
||||
.toArray(Pattern[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各个正则表达式转为 {@link Pattern} 实例。
|
||||
*
|
||||
*
|
||||
* @param patterns 正则表达式
|
||||
* @return {@link Pattern} 实例数组
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
@Nonnull
|
||||
private static Pattern[] getPatternsInternal(@Nonnull final String[] patterns) {
|
||||
return Arrays.stream(patterns)
|
||||
.map(RegexTools::getPatternInternal)
|
||||
.map(RegexUtil::getPatternInternal)
|
||||
.toArray(Pattern[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 {@code input} 是否匹配 {@code pattern}。
|
||||
*
|
||||
*
|
||||
* @param input 输入
|
||||
* @param pattern 正则
|
||||
* @return 判断结果
|
||||
@@ -354,23 +359,37 @@ public final class RegexTools {
|
||||
return input != null && pattern.matcher(input).matches();
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private static boolean matchesOneInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) {
|
||||
return input != null
|
||||
&& Arrays.stream(patterns)
|
||||
.anyMatch(pattern -> pattern.matcher(input).matches());
|
||||
if (input == null) {
|
||||
return false;
|
||||
}
|
||||
for (Pattern pattern : patterns) {
|
||||
if (matchesInternal(input, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean matchesAllInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) {
|
||||
return input != null
|
||||
&& Arrays.stream(patterns)
|
||||
.allMatch(pattern -> pattern.matcher(input).matches());
|
||||
@SuppressWarnings("null")
|
||||
private static boolean matchesAllInternal(final CharSequence input, final Pattern[] patterns) {
|
||||
if (input == null) {
|
||||
return false;
|
||||
}
|
||||
for (Pattern pattern : patterns) {
|
||||
if (!matchesInternal(input, pattern)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static <T> boolean allNotNull(T[] array) {
|
||||
return Arrays.stream(array).allMatch(Objects::nonNull);
|
||||
}
|
||||
|
||||
private RegexTools() {
|
||||
private RegexUtil() {
|
||||
// 不允许实例化
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
135
src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java
Normal file
135
src/main/java/xyz/zhouxy/plusone/commons/util/RestfulResult.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* 对返回给前端的数据进行封装
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @deprecated 已被 {@link UnifiedResponse} 代替。
|
||||
*/
|
||||
@Deprecated
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class RestfulResult {
|
||||
|
||||
public static final int SUCCESS_STATUS = 2000000;
|
||||
public static final int DEFAULT_ERROR_STATUS = 9999999;
|
||||
|
||||
private final Object status;
|
||||
private final String message;
|
||||
|
||||
private final @Nullable Object data;
|
||||
|
||||
private RestfulResult(final Object status, final String message) {
|
||||
this(status, message, null);
|
||||
}
|
||||
|
||||
public static RestfulResult success() {
|
||||
return new RestfulResult(SUCCESS_STATUS, "操作成功");
|
||||
}
|
||||
|
||||
public static RestfulResult success(final String message) {
|
||||
Preconditions.checkNotNull(message, "Message must not be null.");
|
||||
return new RestfulResult(SUCCESS_STATUS, message);
|
||||
}
|
||||
|
||||
public static RestfulResult success(final String message, @Nullable final Object data) {
|
||||
Preconditions.checkNotNull(message, "Message must not be null.");
|
||||
return new RestfulResult(SUCCESS_STATUS, message, data);
|
||||
}
|
||||
|
||||
public static RestfulResult error() {
|
||||
return new RestfulResult(DEFAULT_ERROR_STATUS, "未知错误");
|
||||
}
|
||||
|
||||
public static RestfulResult error(final Object status, final String message) {
|
||||
Preconditions.checkNotNull(status, "Status must not be null.");
|
||||
Preconditions.checkNotNull(message, "Message must not be null.");
|
||||
return new RestfulResult(status, message);
|
||||
}
|
||||
|
||||
public static RestfulResult error(final Object status, final String message, @Nullable final Object data) {
|
||||
Preconditions.checkNotNull(status, "Status must not be null.");
|
||||
Preconditions.checkNotNull(message, "Message must not be null.");
|
||||
return new RestfulResult(status, message, data);
|
||||
}
|
||||
|
||||
public static RestfulResult error(final Object status, final Throwable e) {
|
||||
Preconditions.checkNotNull(status, "Status must not be null.");
|
||||
Preconditions.checkNotNull(e, "Exception must not be null.");
|
||||
String msg = e.getMessage();
|
||||
if (msg == null) {
|
||||
msg = "";
|
||||
}
|
||||
return new RestfulResult(status, msg);
|
||||
}
|
||||
|
||||
public static RestfulResult of(final boolean isSuccess,
|
||||
final Supplier<RestfulResult> success, final Supplier<RestfulResult> error) {
|
||||
Preconditions.checkNotNull(success, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(error, "Error supplier must not be null.");
|
||||
return isSuccess ? success.get() : error.get();
|
||||
}
|
||||
|
||||
public static RestfulResult of(final BooleanSupplier isSuccess,
|
||||
final Supplier<RestfulResult> success, final Supplier<RestfulResult> error) {
|
||||
Preconditions.checkNotNull(isSuccess, "Conditions for success must not be null.");
|
||||
Preconditions.checkNotNull(success, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(error, "Error supplier must not be null.");
|
||||
return isSuccess.getAsBoolean() ? success.get() : error.get();
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
||||
private RestfulResult(final Object status, final String message, @Nullable final Object data) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Constructors end
|
||||
|
||||
// Getters
|
||||
|
||||
public Object getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Getters end
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestfulResult [status=" + status + ", message=" + message + ", data=" + data + "]";
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -80,9 +64,9 @@ public class SnowflakeIdGenerator {
|
||||
* @param datacenterId 数据中心ID (0~31)
|
||||
*/
|
||||
public SnowflakeIdGenerator(final long workerId, final long datacenterId) {
|
||||
Preconditions.checkArgument((workerId <= MAX_WORKER_ID && workerId >= 0),
|
||||
Preconditions.checkArgument((workerId > MAX_WORKER_ID || workerId < 0),
|
||||
"WorkerId can't be greater than %s or less than 0.", MAX_WORKER_ID);
|
||||
Preconditions.checkArgument((datacenterId <= MAX_DATACENTER_ID && datacenterId >= 0),
|
||||
Preconditions.checkArgument((datacenterId > MAX_DATACENTER_ID || datacenterId < 0),
|
||||
"DatacenterId can't be greater than %s or less than 0.", MAX_DATACENTER_ID);
|
||||
this.datacenterIdAndWorkerId
|
||||
= (datacenterId << DATACENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT);
|
||||
|
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
@Beta
|
||||
public class StringTools {
|
||||
|
||||
public static final String EMPTY_STRING = "";
|
||||
|
||||
public static boolean isNotBlank(final String cs) {
|
||||
if (cs == null || cs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < cs.length(); i++) {
|
||||
if (!Character.isWhitespace(cs.charAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String repeat(String str, int times) {
|
||||
return repeat(str, times, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static String repeat(String str, int times, int maxLength) {
|
||||
AssertTools.checkArgumentNotNull(str);
|
||||
return String.valueOf(ArrayTools.repeat(str.toCharArray(), times, maxLength));
|
||||
}
|
||||
|
||||
private StringTools() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
/**
|
||||
* 成功结果
|
||||
*
|
||||
* @author zhouxy
|
||||
*/
|
||||
final class SuccessResult extends UnifiedResponse {
|
||||
private static final String SUCCESS_STATUS = "000000";
|
||||
private static final String DEFAULT_SUCCESS_MSG = "SUCCESS";
|
||||
|
||||
SuccessResult() {
|
||||
super(SUCCESS_STATUS, DEFAULT_SUCCESS_MSG);
|
||||
}
|
||||
|
||||
SuccessResult(String message) {
|
||||
super(SUCCESS_STATUS, message);
|
||||
}
|
||||
|
||||
SuccessResult(String message, Object data) {
|
||||
super(SUCCESS_STATUS, message, data);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -7509096647748429661L;
|
||||
}
|
@@ -1,23 +1,6 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -25,96 +8,33 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* TreeBuilder
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TreeBuilder<T, TSubTree extends T, TIdentity> {
|
||||
private final Collection<T> nodes;
|
||||
private final Function<T, TIdentity> identityGetter;
|
||||
private final Function<T, Optional<TIdentity>> parentIdentityGetter;
|
||||
private final BiConsumer<TSubTree, T> addChildMethod;
|
||||
private final Comparator<? super T> defaultComparator;
|
||||
private final BiConsumer<TSubTree, T> addChildrenMethod;
|
||||
|
||||
public TreeBuilder(Function<T, TIdentity> identityGetter, Function<T, Optional<TIdentity>> parentIdentityGetter,
|
||||
BiConsumer<TSubTree, T> addChild) {
|
||||
this(identityGetter, parentIdentityGetter, addChild, null);
|
||||
}
|
||||
|
||||
public TreeBuilder(Function<T, TIdentity> identityGetter, Function<T, Optional<TIdentity>> parentIdentityGetter,
|
||||
BiConsumer<TSubTree, T> addChild, Comparator<? super T> defaultComparator) {
|
||||
public TreeBuilder(Collection<T> nodes, Function<T, TIdentity> identityGetter,
|
||||
Function<T, Optional<TIdentity>> parentIdentityGetter, BiConsumer<TSubTree, T> addChildren) {
|
||||
this.nodes = nodes;
|
||||
this.identityGetter = identityGetter;
|
||||
this.parentIdentityGetter = parentIdentityGetter;
|
||||
this.addChildMethod = addChild;
|
||||
this.defaultComparator = defaultComparator;
|
||||
this.addChildrenMethod = addChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点构建成树。使用 {@link #defaultComparator} 进行排序。如果 {@link #defaultComparator}
|
||||
* <p>
|
||||
* <b>注意,该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
|
||||
* 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。</b>
|
||||
*
|
||||
* @param nodes 平铺的节点列表
|
||||
*/
|
||||
public List<T> buildTree(Collection<T> nodes) {
|
||||
Preconditions.checkNotNull(nodes);
|
||||
return buildTreeInternal(nodes, this.defaultComparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点构建成树。
|
||||
* <p>
|
||||
* <b>!!注意:该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
|
||||
* 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。</b>
|
||||
*
|
||||
* @param nodes 平铺的节点列表
|
||||
* @param comparator 用于节点的排序。
|
||||
* 若为 {@code null},则使用 {@link #defaultComparator};
|
||||
* 若 {@link #defaultComparator} 也为 {@code null},则不排序。
|
||||
* <b>仅影响调用 addChild 的顺序,如果操作对象本身对应的控制了子节点的顺序,无法影响其相关逻辑。</b>
|
||||
*/
|
||||
public List<T> buildTree(Collection<T> nodes, @Nullable Comparator<? super T> comparator) {
|
||||
Preconditions.checkNotNull(nodes);
|
||||
final Comparator<? super T> c = (comparator != null) ? comparator : this.defaultComparator;
|
||||
return buildTreeInternal(nodes, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点构建成树。
|
||||
* <p>
|
||||
* <b>注意,该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
|
||||
* 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。</b>
|
||||
*
|
||||
* @param nodes 平铺的节点列表
|
||||
* @param comparator 用于节点的排序。若为 {@code null},则不排序
|
||||
*/
|
||||
private List<T> buildTreeInternal(Collection<T> nodes, @Nullable Comparator<? super T> comparator) {
|
||||
final Collection<T> allNodes;
|
||||
if (comparator == null) {
|
||||
allNodes = nodes;
|
||||
} else {
|
||||
allNodes = nodes.stream().sorted(comparator).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
final Map<TIdentity, T> identityNodeMap = allNodes.stream()
|
||||
.collect(Collectors.toMap(identityGetter, Function.identity(), (n1, n2) -> n1));
|
||||
// 根节点
|
||||
final List<T> rootNodes = allNodes.stream()
|
||||
public List<T> buildTree() {
|
||||
Map<TIdentity, T> identityNodeMap = MoreCollections.toHashMap(nodes, identityGetter);
|
||||
List<T> result = this.nodes.stream()
|
||||
.filter(node -> !this.parentIdentityGetter.apply(node).isPresent())
|
||||
.collect(Collectors.toList());
|
||||
allNodes.forEach(node -> parentIdentityGetter.apply(node).ifPresent(parentIdentity -> {
|
||||
if (identityNodeMap.containsKey(parentIdentity)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
TSubTree parentNode = (TSubTree) identityNodeMap.get(parentIdentity);
|
||||
addChildMethod.accept(parentNode, node);
|
||||
for (T node : this.nodes) {
|
||||
Optional<TIdentity> parentIdentity = parentIdentityGetter.apply(node);
|
||||
if (parentIdentity.isPresent() && identityNodeMap.containsKey(parentIdentity.get())) {
|
||||
@SuppressWarnings("all")
|
||||
TSubTree parentNode = (TSubTree) identityNodeMap.get(parentIdentity.get());
|
||||
addChildrenMethod.accept(parentNode, node);
|
||||
}
|
||||
}));
|
||||
return rootNodes;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.util;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.UnsupportedOperation;
|
||||
import xyz.zhouxy.plusone.commons.base.IWithCode;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* 统一结果,对返回给前端的数据进行封装。
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
*/
|
||||
public abstract class UnifiedResponse extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = -6198220274571286031L;
|
||||
|
||||
private static final String STATUS_KEY = "status";
|
||||
private static final String MESSAGE_KEY = "message";
|
||||
private static final String DATA_KEY = "data";
|
||||
|
||||
public static UnifiedResponse success() {
|
||||
return new SuccessResult();
|
||||
}
|
||||
|
||||
public static UnifiedResponse success(String message) {
|
||||
return new SuccessResult(message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse success(String message, Object data) {
|
||||
return new SuccessResult(message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(String message) {
|
||||
return new ErrorResult(message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(String message, Object data) {
|
||||
return new ErrorResult(message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, String message) {
|
||||
return new ErrorResult(status, message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, String message, Object data) {
|
||||
return new ErrorResult(status, message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse error(Object status, Throwable e) {
|
||||
return new ErrorResult(status, e);
|
||||
}
|
||||
|
||||
public static <E extends Throwable & IWithCode<?>> UnifiedResponse error(E e) {
|
||||
return new ErrorResult(e);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(Object status, String message) {
|
||||
return new CustomResult(status, message);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(Object status, String message, Object data) {
|
||||
return new CustomResult(status, message, data);
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(final boolean isSuccess,
|
||||
final Supplier<UnifiedResponse> success, final Supplier<UnifiedResponse> error) {
|
||||
Preconditions.checkNotNull(success, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(error, "Error supplier must not be null.");
|
||||
return isSuccess ? success.get() : error.get();
|
||||
}
|
||||
|
||||
public static UnifiedResponse of(final BooleanSupplier isSuccess,
|
||||
final Supplier<UnifiedResponse> success, final Supplier<UnifiedResponse> error) {
|
||||
Preconditions.checkNotNull(isSuccess, "Conditions for success must not be null.");
|
||||
Preconditions.checkNotNull(success, "Success supplier must not be null.");
|
||||
Preconditions.checkNotNull(error, "Error supplier must not be null.");
|
||||
return isSuccess.getAsBoolean() ? success.get() : error.get();
|
||||
}
|
||||
|
||||
protected UnifiedResponse(Object status, String message) {
|
||||
setStatus(status);
|
||||
setMessage(message);
|
||||
}
|
||||
|
||||
protected UnifiedResponse(Object status, String message, Object data) {
|
||||
setStatus(status);
|
||||
setMessage(message);
|
||||
setData(data);
|
||||
}
|
||||
|
||||
private void setStatus(Object status) {
|
||||
Objects.requireNonNull(status);
|
||||
if (status instanceof String) {
|
||||
super.put(STATUS_KEY, status);
|
||||
} else {
|
||||
super.put(STATUS_KEY, status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void setData(Object data) {
|
||||
super.put(DATA_KEY, Objects.requireNonNull(data));
|
||||
}
|
||||
|
||||
private void setMessage(String message) {
|
||||
super.put(MESSAGE_KEY, Objects.requireNonNull(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ?> m) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object putIfAbsent(String key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean replace(String key, Object oldValue, Object newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object replace(String key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object computeIfAbsent(String key, Function<? super String, ?> mappingFunction) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object computeIfPresent(String key, BiFunction<? super String, ? super Object, ?> remappingFunction) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object compute(String key, BiFunction<? super String, ? super Object, ?> remappingFunction) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object merge(String key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@UnsupportedOperation
|
||||
@Deprecated
|
||||
@Override
|
||||
public void replaceAll(BiFunction<? super String, ? super Object, ?> function) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
@@ -27,7 +11,6 @@ import xyz.zhouxy.plusone.commons.util.Enumeration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
class EnumerationTests {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EnumerationTests.class);
|
||||
@@ -45,7 +28,6 @@ class EnumerationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
final class EntityStatus extends Enumeration<EntityStatus> {
|
||||
|
||||
private EntityStatus(int value, String name) {
|
||||
@@ -56,7 +38,7 @@ final class EntityStatus extends Enumeration<EntityStatus> {
|
||||
public static final EntityStatus AVAILABLE = new EntityStatus(0, "正常");
|
||||
public static final EntityStatus DISABLED = new EntityStatus(1, "禁用");
|
||||
|
||||
private static final ValueSet<EntityStatus> VALUE_SET = ValueSet.of(new EntityStatus[] { AVAILABLE, DISABLED });
|
||||
private static final ValueSet<EntityStatus> VALUE_SET = ValueSet.of(AVAILABLE, DISABLED);
|
||||
|
||||
public static EntityStatus of(int value) {
|
||||
return VALUE_SET.get(value);
|
||||
@@ -67,7 +49,6 @@ final class EntityStatus extends Enumeration<EntityStatus> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
final class Result extends Enumeration<Result> {
|
||||
private Result(int id, String name) {
|
||||
super(id, name);
|
||||
@@ -76,7 +57,7 @@ final class Result extends Enumeration<Result> {
|
||||
public static final Result SUCCESSFUL = new Result(1, "成功");
|
||||
public static final Result FAILURE = new Result(0, "失败");
|
||||
|
||||
private static final ValueSet<Result> VALUE_SET = ValueSet.of(new Result[] { SUCCESSFUL, FAILURE });
|
||||
private static final ValueSet<Result> VALUE_SET = ValueSet.of(SUCCESSFUL, FAILURE);
|
||||
|
||||
public static Result of(int id) {
|
||||
return VALUE_SET.get(id);
|
||||
|
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons;
|
||||
|
||||
import java.io.ObjectStreamClass;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.commons.exception.system.NoAvailableMacFoundException;
|
||||
|
||||
@Slf4j
|
||||
class SerialTests {
|
||||
|
||||
@Test
|
||||
void testSerialVersionUID() {
|
||||
long uid = getSerialVersionUID(NoAvailableMacFoundException.class);
|
||||
log.info("\n private static final long serialVersionUID = {}L;", uid);
|
||||
}
|
||||
|
||||
private long getSerialVersionUID(Class<?> cl) {
|
||||
ObjectStreamClass c = ObjectStreamClass.lookup(cl);
|
||||
return c.getSerialVersionUID();
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.base;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
class RefTests {
|
||||
|
||||
@Test
|
||||
void testRef() {
|
||||
Ref<String> strRef = new Ref<>("ZhouXY");
|
||||
apply(strRef);
|
||||
assertEquals("Hello ZhouXY", strRef.getValue());
|
||||
log.info("strRef: {}", strRef);
|
||||
}
|
||||
|
||||
void apply(Ref<String> strRef) {
|
||||
strRef.transform(str -> "Hello " + str);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBoolRef() {
|
||||
BoolRef boolRef = new BoolRef(false);
|
||||
apply(boolRef);
|
||||
assertTrue(boolRef.getValue());
|
||||
log.info("boolRef: {}", boolRef);
|
||||
}
|
||||
|
||||
void apply(BoolRef boolRef) {
|
||||
boolRef.setValue(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCharRef() {
|
||||
CharRef charRef = new CharRef('T');
|
||||
|
||||
apply(false, charRef);
|
||||
assertEquals('0', charRef.getValue());
|
||||
log.info("charRef: {}", charRef);
|
||||
|
||||
apply(true, charRef);
|
||||
assertEquals('1', charRef.getValue());
|
||||
log.info("charRef: {}", charRef);
|
||||
}
|
||||
|
||||
void apply(boolean condition, CharRef charRef) {
|
||||
charRef.apply(c -> condition ? '1' : '0');
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoubleRef() {
|
||||
DoubleRef doubleRef = new DoubleRef(2.33);
|
||||
apply(88.108, doubleRef);
|
||||
assertEquals(2.33 * 88.108, doubleRef.getValue());
|
||||
log.info("doubleRef: {}", doubleRef);
|
||||
}
|
||||
|
||||
void apply(double num, DoubleRef doubleRef) {
|
||||
doubleRef.apply(d -> d * num);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntRef() {
|
||||
IntRef intRef = new IntRef(108);
|
||||
apply(88, intRef);
|
||||
assertEquals(108 - 88, intRef.getValue());
|
||||
log.info("intRef: {}", intRef);
|
||||
}
|
||||
|
||||
void apply(int num, IntRef intRef) {
|
||||
intRef.apply(d -> d - num);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLongRef() {
|
||||
LongRef longRef = new LongRef(108L);
|
||||
apply(88L, longRef);
|
||||
assertEquals(108L + 88L, longRef.getValue());
|
||||
log.info("intRef: {}", longRef);
|
||||
}
|
||||
|
||||
void apply(long num, LongRef longRef) {
|
||||
longRef.apply(d -> d + num);
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package xyz.zhouxy.plusone.commons.domain;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
|
||||
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||
|
||||
class ValidatableStringRecordTests {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidatableStringRecordTests.class);
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
Username username = Username.of("ZhouXY");
|
||||
assertNotNull(username);
|
||||
String usernameStr = username.value();
|
||||
assertNotNull(usernameStr);
|
||||
log.info("usernameStr: {}", usernameStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ValueObject
|
||||
class Username extends ValidatableStringRecord {
|
||||
private Username(String username) {
|
||||
super(username, PatternConsts.USERNAME);
|
||||
}
|
||||
|
||||
@StaticFactoryMethod(Username.class)
|
||||
public static Username of(String username) {
|
||||
return new Username(username);
|
||||
}
|
||||
}
|
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.function;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
@@ -29,7 +13,7 @@ class FunctionTests {
|
||||
@Test
|
||||
void test() {
|
||||
String str = "";
|
||||
Predicate<String> predicate = PredicateTools.<String>from(Objects::nonNull)
|
||||
Predicate<String> predicate = Predicates.<String>of(Objects::nonNull)
|
||||
.and(StringUtils::isNotBlank);
|
||||
assertFalse(predicate.test(str), "校验应是不通过");
|
||||
}
|
||||
|
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.regex.Matcher;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Chinese2ndGenIDCardNumberTests {
|
||||
|
||||
@Test
|
||||
void testPattern() {
|
||||
Matcher matcher = Chinese2ndGenIDCardNumber.PATTERN.matcher("11010520000101111X");
|
||||
assertTrue(matcher.matches());
|
||||
for (int i = 0; i < matcher.groupCount(); i++) {
|
||||
log.info("{}: {}", i, matcher.group(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void test() throws CloneNotSupportedException {
|
||||
Chinese2ndGenIDCardNumber idCardNumber = Chinese2ndGenIDCardNumber.of("11010520000101111X");
|
||||
assertEquals("11010520000101111X", idCardNumber.value());
|
||||
assertEquals(LocalDate.of(2000, 1, 1), idCardNumber.getBirthDate());
|
||||
assertEquals(Gender.MALE, idCardNumber.getGender());
|
||||
assertEquals("110105", idCardNumber.getCountyCode());
|
||||
assertEquals("110105000000", idCardNumber.getFullCountyCode());
|
||||
|
||||
assertEquals("1101", idCardNumber.getCityCode());
|
||||
assertEquals("110100000000", idCardNumber.getFullCityCode());
|
||||
|
||||
assertEquals("11", idCardNumber.getProvinceCode());
|
||||
assertEquals("110000000000", idCardNumber.getFullProvinceCode());
|
||||
|
||||
assertEquals("北京", idCardNumber.getProvinceName());
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> Chinese2ndGenIDCardNumber.of("1101520000101111"));
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> Chinese2ndGenIDCardNumber.of("11010520002101111X"));
|
||||
|
||||
try {
|
||||
Chinese2ndGenIDCardNumber.of("11010520002101111X");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
assertTrue(e.getCause() instanceof DateTimeParseException);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.zhouxy.plusone.commons.model;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang3.builder.DiffBuilder;
|
||||
import org.apache.commons.lang3.builder.DiffResult;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
|
||||
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
class ValidatableStringRecordTests {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidatableStringRecordTests.class);
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
Username username = Username.of("ZhouXY");
|
||||
assertNotNull(username);
|
||||
String usernameStr = username.value();
|
||||
assertNotNull(usernameStr);
|
||||
log.info("usernameStr: {}", usernameStr);
|
||||
|
||||
List<Username> usernames = Arrays.asList(
|
||||
Username.of("ZhouXY108"),
|
||||
Username.of("code_108"),
|
||||
Username.of("Luquan"),
|
||||
Username.of("Code108"));
|
||||
log.info("{}", Collections.max(usernames));
|
||||
Function<Username, String> compare = o -> o.value().toLowerCase();
|
||||
log.info("{}", Collections.max(usernames, Comparator.comparing(compare)));
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
class User {
|
||||
Username username;
|
||||
Email email;
|
||||
|
||||
static class Diff {
|
||||
public static DiffResult<User> diff(User left, User right) {
|
||||
return DiffBuilder.<User>builder()
|
||||
.setLeft(left)
|
||||
.setRight(right)
|
||||
.setStyle(ToStringStyle.JSON_STYLE)
|
||||
.build()
|
||||
.append("username", left.username, right.username)
|
||||
.append("email", left.email, right.email)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ValueObject
|
||||
class Email extends ValidatableStringRecord {
|
||||
private Email(String value) {
|
||||
super(value, PatternConsts.EMAIL);
|
||||
}
|
||||
|
||||
@StaticFactoryMethod(Email.class)
|
||||
public static Email of(String value) {
|
||||
return new Email(value);
|
||||
}
|
||||
}
|
||||
|
||||
@ValueObject
|
||||
class Username extends ValidatableStringRecord {
|
||||
private Username(String username) {
|
||||
super(username, PatternConsts.USERNAME);
|
||||
}
|
||||
|
||||
@StaticFactoryMethod(Username.class)
|
||||
public static Username of(String username) {
|
||||
return new Username(username);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user