diff --git a/build.gradle.kts b/build.gradle.kts index 22830a5..42cdc30 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils * CurrentFile build.gradle.kts - * LastUpdate 2026-01-14 13:01:44 + * LastUpdate 2026-02-08 03:14:06 * UpdateUser MingLiPro */ @@ -31,6 +31,7 @@ plugins { `maven-publish` kotlin("jvm") version "2.2.20" id("org.jetbrains.dokka") version "2.0.0" + kotlin("kapt") version "2.2.20" } val GROUPSID = project.properties["GROUPSID"] as String val VERSIONS = project.properties["VERSIONS"] as String @@ -59,6 +60,10 @@ sourceSets { } } +tasks.test { + useJUnitPlatform() +} + java { withSourcesJar() toolchain.languageVersion.set(JavaLanguageVersion.of(8)) @@ -67,19 +72,28 @@ java { dependencies { implementation("org.slf4j:slf4j-api:2.0.17") - implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1") + implementation(kotlin("reflect")) + compileOnly("org.mindrot:jbcrypt:0.4") - compileOnly("org.springframework.boot:spring-boot-starter:2.7.14") - compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2") - compileOnly("com.google.code.gson:gson:2.13.1") + compileOnly("com.squareup.okhttp3:okhttp:5.3.2") + compileOnly("com.fasterxml.jackson.core:jackson-databind:2.21.0") + compileOnly("com.fasterxml.jackson.module:jackson-module-kotlin:2.21.0") + compileOnly("org.springframework.boot:spring-boot-starter-web:2.7.18") + compileOnly("com.google.code.gson:gson:2.13.2") compileOnly("org.mybatis:mybatis:3.5.19") - compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58") compileOnly("io.netty:netty-all:4.1.130.Final") - compileOnly("com.baomidou:mybatis-plus-core:3.5.15") compileOnly("net.java.dev.jna:jna:5.17.0") + compileOnly("com.baomidou:mybatis-plus-extension:3.5.15") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") +// testImplementation("com.squareup.okhttp3:okhttp:5.3.2") + testImplementation("com.mingliqiye.logger:logger-log4j2:1.0.5") + testImplementation("com.google.code.gson:gson:2.13.2") + testImplementation("com.fasterxml.jackson.core:jackson-databind:2.21.0") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.21.0") } @@ -94,6 +108,15 @@ tasks.withType().configureEach { ) } +kapt { + arguments { + arg( + "kapt.kotlin.generated", + project.layout.buildDirectory.dir("generated/source/kapt/main").get().asFile.absolutePath + ) + } +} + tasks.withType { duplicatesStrategy = DuplicatesStrategy.EXCLUDE from("LICENSE") { into("META-INF") } @@ -126,6 +149,8 @@ tasks.withType { } val isJdk8Build = project.findProperty("buildForJdk8") == "true" + + repositories { maven { url = uri("https://maven.aliyun.com/repository/public/") @@ -202,7 +227,7 @@ tasks.build { tasks.processResources { duplicatesStrategy = DuplicatesStrategy.EXCLUDE outputs.upToDateWhen { false } - filesMatching("META-INF/meta-data") { + filesMatching(listOf("META-INF/meta-data", "fabric.mod.json")) { expand( project.properties + mapOf( "buildTime" to LocalDateTime.now().format( diff --git a/gradle.properties b/gradle.properties index fdcb12e..2a0aab4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,13 +16,13 @@ # ProjectName mingli-utils # ModuleName mingli-utils # CurrentFile gradle.properties -# LastUpdate 2026-01-14 13:01:41 +# LastUpdate 2026-02-08 03:15:06 # UpdateUser MingLiPro # JDKVERSIONS=1.8 GROUPSID=com.mingliqiye.utils ARTIFACTID=mingli-utils -VERSIONS=4.3.5 +VERSIONS=4.6.4 signing.keyId=B22AA93B signing.password= signing.secretKeyRingFile=secret.gpg diff --git a/jdk8/build.gradle.kts b/jdk8/build.gradle.kts index 13cc797..4a603b0 100644 --- a/jdk8/build.gradle.kts +++ b/jdk8/build.gradle.kts @@ -24,8 +24,6 @@ plugins { id("java-library") id("maven-publish") signing - kotlin("jvm") version "2.2.20" - id("org.jetbrains.dokka") version "2.0.0" } val GROUPSID = project.properties["GROUPSID"] as String val VERSIONS = project.properties["VERSIONS"] as String @@ -84,6 +82,7 @@ publishing { } java.toolchain.languageVersion.set(JavaLanguageVersion.of(8)) + dependencies { api(rootProject) implementation("com.mingliqiye.utils.jna:WinKernel32Platform:1.0.1") diff --git a/settings.gradle.kts b/settings.gradle.kts index dd6cf72..5c2ad46 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils * CurrentFile settings.gradle.kts - * LastUpdate 2025-09-16 12:32:52 + * LastUpdate 2026-02-07 17:00:59 * UpdateUser MingLiPro */ diff --git a/src/main/java/com/mingliqiye/utils/stream/SuperStream.java b/src/main/java/com/mingliqiye/utils/stream/SuperStream.java index 1d71c41..3b440a5 100644 --- a/src/main/java/com/mingliqiye/utils/stream/SuperStream.java +++ b/src/main/java/com/mingliqiye/utils/stream/SuperStream.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile SuperStream.java - * LastUpdate 2025-09-21 14:22:13 + * LastUpdate 2026-01-20 13:27:09 * UpdateUser MingLiPro */ @@ -36,641 +36,735 @@ import java.util.stream.*; /** - * SuperStream 是对 Java 原生 Stream 的增强封装类,提供更便捷的流式操作接口。 - * 它支持链式调用,并扩展了部分原生 Stream 不支持的功能,例如带索引的 forEach 操作。 - * - * @param 流中元素的类型 + * SuperStream是一个增强版的Stream包装器,提供了更多的便捷方法和重载方法来处理各种数据类型的流操作。 + * 它继承了Stream接口并实现了所有Stream的方法,同时添加了一些额外的便利功能。 */ public class SuperStream implements Stream { private final Stream stream; + /** - * 构造方法,将传入的 Stream 包装为 SuperStream。 + * 构造一个新的SuperStream实例 * - * @param stream 要包装的原始 Stream + * @param stream 被包装的基础Stream对象 */ private SuperStream(Stream stream) { this.stream = stream; } /** - * 将指定的 Stream 包装为 SuperStream。 + * 创建一个包含指定整数元素的SuperStream * - * @param stream 原始 Stream + * @param args 可变参数的整数值数组 + * @return 包含指定整数的SuperStream实例 + */ + public static SuperStream of(int... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定字节元素的SuperStream + * + * @param args 可变参数的字节数组 + * @return 包含指定字节的SuperStream实例 + */ + public static SuperStream of(byte... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定短整数元素的SuperStream + * + * @param args 可变参数的短整数数组 + * @return 包含指定短整数的SuperStream实例 + */ + public static SuperStream of(short... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定字符元素的SuperStream + * + * @param args 可变参数的字符数组 + * @return 包含指定字符的SuperStream实例 + */ + public static SuperStream of(char... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定长整数元素的SuperStream + * + * @param args 可变参数的长整数数组 + * @return 包含指定长整数的SuperStream实例 + */ + public static SuperStream of(long... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定浮点数元素的SuperStream + * + * @param args 可变参数的浮点数数组 + * @return 包含指定浮点数的SuperStream实例 + */ + public static SuperStream of(float... args) { + return of(Collections.newArrayLists(args)); + } + + /** + * 创建一个包含指定双精度浮点数元素的SuperStream + * + * @param args 可变参数的双精度浮点数数组 + * @return 包含指定双精度浮点数的SuperStream实例 + */ + public static SuperStream of(double... args) { + return of(Collections.newArrayLists(args)); + } + + + /** + * 将现有的Stream包装成SuperStream + * + * @param stream 需要包装的Stream对象 * @param 流中元素的类型 - * @return 包装后的 SuperStream 实例 + * @return 包装后的SuperStream实例 */ public static SuperStream of(Stream stream) { return new SuperStream<>(stream); } + /** + * 创建一个包含指定数组元素的SuperStream,支持并行处理 + * + * @param ts 元素数组 + * @param parallel 是否使用并行流 + * @param 数组元素的类型 + * @return 包含指定数组元素的SuperStream实例 + */ public static SuperStream of(T[] ts, boolean parallel) { return of(Collections.newArrayLists(ts), parallel); } + /** + * 创建一个包含指定数组元素的SuperStream(默认串行) + * + * @param ts 元素数组 + * @param 数组元素的类型 + * @return 包含指定数组元素的SuperStream实例 + */ public static SuperStream of(T[] ts) { return of(ts, false); } + /** - * 将指定的 Collection 转换为 SuperStream,默认为顺序流。 + * 创建一个包含指定集合元素的SuperStream(默认串行) * - * @param collection 原始集合 - * @param 集合中元素的类型 - * @return 包装后的 SuperStream 实例 + * @param collection 包含元素的集合 + * @param 集合元素的类型 + * @return 包含指定集合元素的SuperStream实例 */ public static SuperStream of(Collection collection) { return of(collection, false); } + /** - * 将指定的 Map 转换为 SuperStream,默认为顺序流。 + * 创建一个包含指定Map键值对Entry的SuperStream(默认串行) * - * @param map 原始 Map - * @param Map 键的类型 - * @param Map 值的类型 - * @return 包含 Map.Entry 的 SuperStream 实例 + * @param map 源Map对象 + * @param Map的键类型 + * @param Map的值类型 + * @return 包含Map Entry的SuperStream实例 */ public static SuperStream> of(Map map) { return of(map.entrySet(), false); } + /** - * 将指定的 Map 转换为 SuperStream,可选择是否为并行流。 + * 创建一个包含指定Map键值对Entry的SuperStream,支持并行处理 * - * @param map 原始 Map + * @param map 源Map对象 * @param parallel 是否使用并行流 - * @param Map 键的类型 - * @param Map 值的类型 - * @return 包含 Map.Entry 的 SuperStream 实例 + * @param Map的键类型 + * @param Map的值类型 + * @return 包含Map Entry的SuperStream实例 */ public static SuperStream> of(Map map, boolean parallel) { return SuperStream.of(map.entrySet(), parallel); } + /** - * 将指定的 Collection 转换为 SuperStream,可选择是否为并行流。 + * 创建一个包含指定集合元素的SuperStream,支持并行处理 * - * @param stream 原始集合 + * @param stream 包含元素的集合 * @param parallel 是否使用并行流 - * @param 集合中元素的类型 - * @return 包装后的 SuperStream 实例 + * @param 集合元素的类型 + * @return 包含指定集合元素的SuperStream实例 */ public static SuperStream of(Collection stream, boolean parallel) { return parallel ? SuperStream.of(stream.parallelStream()) : SuperStream.of(stream.stream()); } + /** - * 返回一个用于收集 Double 类型统计信息的 Collector。 + * 返回一个收集器,该收集器产生一个DoubleSummaryStatistics,描述输入元素的统计信息 * - * @param mapper 映射函数,将元素转换为 double 值 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到double值的函数 + * @param 输入元素的类型 + * @return 产生DoubleSummaryStatistics的收集器 */ public static Collector summarizingDouble(@NotNull ToDoubleFunction mapper) { return Collectors.summarizingDouble(mapper); } + /** - * 返回一个用于收集 Long 类型统计信息的 Collector。 + * 返回一个收集器,该收集器产生一个LongSummaryStatistics,描述输入元素的统计信息 * - * @param mapper 映射函数,将元素转换为 long 值 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到long值的函数 + * @param 输入元素的类型 + * @return 产生LongSummaryStatistics的收集器 */ public static Collector summarizingLong(@NotNull ToLongFunction mapper) { return Collectors.summarizingLong(mapper); } + /** - * 返回一个用于收集 Integer 类型统计信息的 Collector。 + * 返回一个收集器,该收集器产生一个IntSummaryStatistics,描述输入元素的统计信息 * - * @param mapper 映射函数,将元素转换为 int 值 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到int值的函数 + * @param 输入元素的类型 + * @return 产生IntSummaryStatistics的收集器 */ public static Collector summarizingInt(@NotNull ToIntFunction mapper) { return Collectors.summarizingInt(mapper); } + /** - * 返回一个用于收集元素到 ConcurrentMap 的 Collector,支持自定义合并策略和 Map 工厂。 + * 返回一个收集器,该收集器将输入元素累积到ConcurrentMap中 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param mergeFunction 合并函数 - * @param mapSupplier Map 工厂 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @param Map 类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param mergeFunction 当键冲突时合并值的函数 + * @param mapSupplier 用于创建新Map的供应函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @param Map的具体类型 + * @return 产生ConcurrentMap的收集器 */ - public static > Collector toConcurrentMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper, - @NotNull BinaryOperator mergeFunction, - @NotNull Supplier mapSupplier) { + public static > Collector toConcurrentMap(@NotNull Function keyMapper, @NotNull Function valueMapper, @NotNull BinaryOperator mergeFunction, @NotNull Supplier mapSupplier) { return Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction, mapSupplier); } + /** - * 返回一个用于收集元素到 ConcurrentMap 的 Collector,支持自定义合并策略。 + * 返回一个收集器,该收集器将输入元素累积到ConcurrentMap中,使用BinaryOperator处理键冲突 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param mergeFunction 合并函数 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param mergeFunction 当键冲突时合并值的函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @return 产生ConcurrentMap的收集器 */ - public static Collector> toConcurrentMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper, - @NotNull BinaryOperator mergeFunction) { + public static Collector> toConcurrentMap(@NotNull Function keyMapper, @NotNull Function valueMapper, @NotNull BinaryOperator mergeFunction) { return Collectors.toConcurrentMap(keyMapper, valueMapper, mergeFunction); } + /** - * 返回一个用于收集元素到 ConcurrentMap 的 Collector。 + * 返回一个收集器,该收集器将输入元素累积到ConcurrentMap中,使用HashMap.merge处理键冲突 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @return 产生ConcurrentMap的收集器 */ - public static Collector> toConcurrentMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper) { + public static Collector> toConcurrentMap(@NotNull Function keyMapper, @NotNull Function valueMapper) { return Collectors.toConcurrentMap(keyMapper, valueMapper); } + /** - * 返回一个用于收集元素到 Map 的 Collector,支持自定义合并策略和 Map 工厂。 + * 返回一个收集器,该收集器将输入元素累积到Map中 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param mergeFunction 合并函数 - * @param mapSupplier Map 工厂 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @param Map 类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param mergeFunction 当键冲突时合并值的函数 + * @param mapSupplier 用于创建新Map的供应函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @param Map的具体类型 + * @return 产生Map的收集器 */ - public static > Collector toMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper, - @NotNull BinaryOperator mergeFunction, - @NotNull Supplier mapSupplier) { + public static > Collector toMap(@NotNull Function keyMapper, @NotNull Function valueMapper, @NotNull BinaryOperator mergeFunction, @NotNull Supplier mapSupplier) { return Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier); } + /** - * 返回一个用于收集元素到 Map 的 Collector,支持自定义合并策略。 + * 返回一个收集器,该收集器将输入元素累积到Map中,使用BinaryOperator处理键冲突 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param mergeFunction 合并函数 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param mergeFunction 当键冲突时合并值的函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @return 产生Map的收集器 */ - public static Collector> toMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper, - @NotNull BinaryOperator mergeFunction) { + public static Collector> toMap(@NotNull Function keyMapper, @NotNull Function valueMapper, @NotNull BinaryOperator mergeFunction) { return Collectors.toMap(keyMapper, valueMapper, mergeFunction); } + /** - * 返回一个用于收集元素到 Map 的 Collector。 + * 返回一个收集器,该收集器将输入元素累积到Map中,使用HashMap.merge处理键冲突 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param 元素类型 - * @param 键类型 - * @param 值类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param valueMapper 用于产生值的映射函数 + * @param 输入元素的类型 + * @param 键的类型 + * @param 值的类型 + * @return 产生Map的收集器 */ - public static Collector> toMap( - @NotNull Function keyMapper, - @NotNull Function valueMapper) { + public static Collector> toMap(@NotNull Function keyMapper, @NotNull Function valueMapper) { return Collectors.toMap(keyMapper, valueMapper); } + /** - * 返回一个用于根据条件将元素分组到两个列表中的 Collector。 + * 返回一个收集器,该收集器根据谓词将输入元素分区到Map中 * - * @param predicate 判断条件 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 下游结果类型 - * @return Collector 实例 + * @param predicate 用于确定元素分区的谓词 + * @param downstream 应用于分区结果的下游收集器 + * @param 输入元素的类型 + * @param 下游收集器的结果类型 + * @param 下游收集器的累加器类型 + * @return 产生分区Map的收集器 */ - public static Collector> partitioningBy( - @NotNull Predicate predicate, - @NotNull Collector downstream) { + public static Collector> partitioningBy(@NotNull Predicate predicate, @NotNull Collector downstream) { return Collectors.partitioningBy(predicate, downstream); } + /** - * 返回一个用于根据条件将元素分组到两个列表中的 Collector。 + * 返回一个收集器,该收集器根据谓词将输入元素分区到Map中 * - * @param predicate 判断条件 - * @param 元素类型 - * @return Collector 实例 + * @param predicate 用于确定元素分区的谓词 + * @param 输入元素的类型 + * @return 产生分区Map的收集器 */ public static Collector>> partitioningBy(@NotNull Predicate predicate) { return Collectors.partitioningBy(predicate); } + /** - * 返回一个用于并发分组的 Collector,支持自定义 Map 工厂和下游 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到ConcurrentMap中 * - * @param classifier 分类函数 - * @param mapFactory Map 工厂 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 键类型 - * @param 下游结果类型 - * @param 下游中间类型 - * @param Map 类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param mapFactory 用于创建Map的工厂函数 + * @param downstream 应用于分组结果的下游收集器 + * @param 输入元素的类型 + * @param 分类键的类型 + * @param 下游收集器的结果类型 + * @param 下游收集器的累加器类型 + * @param Map的具体类型 + * @return 产生ConcurrentMap的收集器 */ - public static > Collector groupingByConcurrent( - @NotNull Function classifier, - @NotNull Supplier mapFactory, - @NotNull Collector downstream) { + public static > Collector groupingByConcurrent(@NotNull Function classifier, @NotNull Supplier mapFactory, @NotNull Collector downstream) { return Collectors.groupingByConcurrent(classifier, mapFactory, downstream); } + /** - * 返回一个用于并发分组的 Collector,支持自定义下游 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到ConcurrentMap中 * - * @param classifier 分类函数 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 键类型 - * @param 下游中间类型 - * @param 下游结果类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param downstream 应用于分组结果的下游收集器 + * @param 输入元素的类型 + * @param 分类键的类型 + * @param 下游收集器的累加器类型 + * @param 下游收集器的结果类型 + * @return 产生ConcurrentMap的收集器 */ - public static Collector> groupingByConcurrent( - @NotNull Function classifier, - @NotNull Collector downstream) { + public static Collector> groupingByConcurrent(@NotNull Function classifier, @NotNull Collector downstream) { return Collectors.groupingByConcurrent(classifier, downstream); } + /** - * 返回一个用于并发分组的 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到ConcurrentMap中 * - * @param classifier 分类函数 - * @param 元素类型 - * @param 键类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param 输入元素的类型 + * @param 分类键的类型 + * @return 产生ConcurrentMap的收集器 */ - public static Collector>> groupingByConcurrent( - @NotNull Function classifier) { + public static Collector>> groupingByConcurrent(@NotNull Function classifier) { return Collectors.groupingByConcurrent(classifier); } + /** - * 返回一个用于分组的 Collector,支持自定义 Map 工厂和下游 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到Map中 * - * @param classifier 分类函数 - * @param mapFactory Map 工厂 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 键类型 - * @param 下游结果类型 - * @param 下游中间类型 - * @param Map 类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param mapFactory 用于创建Map的工厂函数 + * @param downstream 应用于分组结果的下游收集器 + * @param 输入元素的类型 + * @param 分类键的类型 + * @param 下游收集器的结果类型 + * @param 下游收集器的累加器类型 + * @param Map的具体类型 + * @return 产生Map的收集器 */ - public static > Collector groupingBy( - @NotNull Function classifier, - @NotNull Supplier mapFactory, - @NotNull Collector downstream) { + public static > Collector groupingBy(@NotNull Function classifier, @NotNull Supplier mapFactory, @NotNull Collector downstream) { return Collectors.groupingBy(classifier, mapFactory, downstream); } + /** - * 返回一个用于分组的 Collector,支持自定义下游 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到Map中 * - * @param classifier 分类函数 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 键类型 - * @param 下游中间类型 - * @param 下游结果类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param downstream 应用于分组结果的下游收集器 + * @param 输入元素的类型 + * @param 分类键的类型 + * @param 下游收集器的累加器类型 + * @param 下游收集器的结果类型 + * @return 产生Map的收集器 */ - public static Collector> groupingBy( - @NotNull Function classifier, - @NotNull Collector downstream) { + public static Collector> groupingBy(@NotNull Function classifier, @NotNull Collector downstream) { return Collectors.groupingBy(classifier, downstream); } + /** - * 返回一个用于分组的 Collector。 + * 返回一个收集器,该收集器将输入元素按分类器分组到Map中 * - * @param classifier 分类函数 - * @param 元素类型 - * @param 键类型 - * @return Collector 实例 + * @param classifier 用于分类元素的函数 + * @param 输入元素的类型 + * @param 分类键的类型 + * @return 产生Map的收集器 */ public static Collector>> groupingBy(@NotNull Function classifier) { return Collectors.groupingBy(classifier); } + /** - * 返回一个用于归约的 Collector,支持映射和合并操作。 + * 返回一个收集器,该收集器执行归约操作 * - * @param identity 初始值 - * @param mapper 映射函数 - * @param op 合并函数 - * @param 元素类型 - * @param 结果类型 - * @return Collector 实例 + * @param identity 归约操作的初始值 + * @param mapper 用于将输入元素映射到中间值的函数 + * @param op 用于组合中间值的二元操作符 + * @param 输入元素的类型 + * @param 中间值和结果的类型 + * @return 执行归约操作的收集器 */ public static Collector reducing(U identity, @NotNull Function mapper, @NotNull BinaryOperator op) { return Collectors.reducing(identity, mapper, op); } + /** - * 返回一个用于归约的 Collector。 + * 返回一个收集器,该收集器执行归约操作 * - * @param op 合并函数 - * @param 元素类型 - * @return Collector 实例 + * @param op 用于组合元素的二元操作符 + * @param 输入元素的类型 + * @return 执行归约操作的收集器 */ public static Collector> reducing(@NotNull BinaryOperator op) { return Collectors.reducing(op); } + /** - * 返回一个用于归约的 Collector,支持初始值。 + * 返回一个收集器,该收集器执行归约操作 * - * @param identity 初始值 - * @param op 合并函数 - * @param 元素类型 - * @return Collector 实例 + * @param identity 归约操作的初始值 + * @param op 用于组合元素的二元操作符 + * @param 输入元素的类型 + * @return 执行归约操作的收集器 */ public static Collector reducing(T identity, @NotNull BinaryOperator op) { return Collectors.reducing(identity, op); } + /** - * 返回一个用于计算平均值的 Collector,适用于 double 类型。 + * 返回一个收集器,该收集器计算输入元素的平均值 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到double值的函数 + * @param 输入元素的类型 + * @return 计算平均值的收集器 */ public static Collector averagingDouble(@NotNull ToDoubleFunction mapper) { return Collectors.averagingDouble(mapper); } + /** - * 返回一个用于计算平均值的 Collector,适用于 long 类型。 + * 返回一个收集器,该收集器计算输入元素的平均值 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到long值的函数 + * @param 输入元素的类型 + * @return 计算平均值的收集器 */ public static Collector averagingLong(@NotNull ToLongFunction mapper) { return Collectors.averagingLong(mapper); } + /** - * 返回一个用于计算平均值的 Collector,适用于 int 类型。 + * 返回一个收集器,该收集器计算输入元素的平均值 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到int值的函数 + * @param 输入元素的类型 + * @return 计算平均值的收集器 */ public static Collector averagingInt(@NotNull ToIntFunction mapper) { return Collectors.averagingInt(mapper); } + /** - * 返回一个用于求和的 Collector,适用于 double 类型。 + * 返回一个收集器,该收集器计算输入元素的总和 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到double值的函数 + * @param 输入元素的类型 + * @return 计算总和的收集器 */ public static Collector summingDouble(@NotNull ToDoubleFunction mapper) { return Collectors.summingDouble(mapper); } + /** - * 返回一个用于求和的 Collector,适用于 long 类型。 + * 返回一个收集器,该收集器计算输入元素的总和 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到long值的函数 + * @param 输入元素的类型 + * @return 计算总和的收集器 */ public static Collector summingLong(@NotNull ToLongFunction mapper) { return Collectors.summingLong(mapper); } + /** - * 返回一个用于求和的 Collector,适用于 int 类型。 + * 返回一个收集器,该收集器计算输入元素的总和 * - * @param mapper 映射函数 - * @param 元素类型 - * @return Collector 实例 + * @param mapper 用于将输入元素映射到int值的函数 + * @param 输入元素的类型 + * @return 计算总和的收集器 */ public static Collector summingInt(@NotNull ToIntFunction mapper) { return Collectors.summingInt(mapper); } + /** - * 返回一个用于查找最大值的 Collector。 + * 返回一个收集器,该收集器根据比较器找到最大元素 * - * @param comparator 比较器 - * @param 元素类型 - * @return Collector 实例 + * @param comparator 用于比较元素的比较器 + * @param 输入元素的类型 + * @return 找到最大元素的收集器 */ public static Collector> maxBy(@NotNull Comparator comparator) { return Collectors.maxBy(comparator); } + /** - * 返回一个用于查找最小值的 Collector。 + * 返回一个收集器,该收集器根据比较器找到最小元素 * - * @param comparator 比较器 - * @param 元素类型 - * @return Collector 实例 + * @param comparator 用于比较元素的比较器 + * @param 输入元素的类型 + * @return 找到最小元素的收集器 */ public static Collector> minBy(@NotNull Comparator comparator) { return Collectors.minBy(comparator); } + /** - * 返回一个用于计数的 Collector。 + * 返回一个收集器,该收集器计算输入元素的数量 * - * @param 元素类型 - * @return Collector 实例 + * @param 输入元素的类型 + * @return 计算元素数量的收集器 */ public static Collector counting() { return Collectors.counting(); } + /** - * 返回一个用于在下游收集后进行后续处理的 Collector。 + * 返回一个收集器,该收集器在应用下游收集器后执行finisher转换 * - * @param downstream 下游 Collector - * @param finisher 后续处理函数 - * @param 元素类型 - * @param 下游中间类型 - * @param 下游结果类型 + * @param downstream 下游收集器 + * @param finisher 在下游收集器完成后应用的finisher函数 + * @param 输入元素的类型 + * @param 下游收集器的累加器类型 + * @param 下游收集器的结果类型 * @param 最终结果类型 - * @return Collector 实例 + * @return 执行转换的收集器 */ - public static Collector collectingAndThen( - @NotNull Collector downstream, - @NotNull Function finisher) { + public static Collector collectingAndThen(@NotNull Collector downstream, @NotNull Function finisher) { return Collectors.collectingAndThen(downstream, finisher); } + /** - * 返回一个用于映射后收集的 Collector。 + * 返回一个收集器,该收集器将输入元素映射后应用下游收集器 * - * @param mapper 映射函数 - * @param downstream 下游 Collector - * @param 元素类型 - * @param 映射后的类型 - * @param 下游中间类型 - * @param 下游结果类型 - * @return Collector 实例 + * @param mapper 用于映射输入元素的函数 + * @param downstream 应用于映射后元素的下游收集器 + * @param 输入元素的类型 + * @param 映射后元素的类型 + * @param 下游收集器的累加器类型 + * @param 下游收集器的结果类型 + * @return 执行映射和收集的收集器 */ - public static Collector mapping( - @NotNull Function mapper, - @NotNull Collector downstream) { + public static Collector mapping(@NotNull Function mapper, @NotNull Collector downstream) { return Collectors.mapping(mapper, downstream); } + /** - * 返回一个用于连接字符串的 Collector,支持前缀、后缀和分隔符。 + * 返回一个收集器,该收集器连接输入的字符序列 * * @param delimiter 分隔符 * @param prefix 前缀 * @param suffix 后缀 - * @return Collector 实例 + * @return 连接字符序列的收集器 */ public static Collector joining(@NotNull CharSequence delimiter, @NotNull CharSequence prefix, @NotNull CharSequence suffix) { return Collectors.joining(delimiter, prefix, suffix); } + /** - * 返回一个用于连接字符串的 Collector,支持分隔符。 + * 返回一个收集器,该收集器连接输入的字符序列 * * @param delimiter 分隔符 - * @return Collector 实例 + * @return 连接字符序列的收集器 */ public static Collector joining(@NotNull CharSequence delimiter) { return Collectors.joining(delimiter); } + /** - * 返回一个用于连接字符串的 Collector。 + * 返回一个收集器,该收集器连接输入的字符序列 * - * @return Collector 实例 + * @return 连接字符序列的收集器 */ public static Collector joining() { return Collectors.joining(); } + /** - * 返回一个用于收集元素到 Set 的 Collector。 + * 返回一个收集器,该收集器将输入元素累积到Set中 * - * @param 元素类型 - * @return Collector 实例 + * @param 输入元素的类型 + * @return 产生Set的收集器 */ public static Collector> toSet() { return Collectors.toSet(); } + /** - * 返回一个用于收集元素到 List 的 Collector。 + * 返回一个收集器,该收集器将输入元素累积到List中 * - * @param 元素类型 - * @return Collector 实例 + * @param 输入元素的类型 + * @return 产生List的收集器 */ public static Collector> toList() { return Collectors.toList(); } + /** - * 返回一个用于收集元素到指定集合类型的 Collector。 + * 返回一个收集器,该收集器将输入元素累积到指定类型的集合中 * - * @param collectionFactory 集合工厂 - * @param 元素类型 - * @param 集合类型 - * @return Collector 实例 + * @param collectionFactory 用于创建集合的工厂函数 + * @param 输入元素的类型 + * @param 目标集合的具体类型 + * @return 产生指定类型集合的收集器 */ public static > Collector toCollection(@NotNull Supplier collectionFactory) { return Collectors.toCollection(collectionFactory); } + /** - * 返回一个用于收集元素到 Map 的 Collector,键由 keyMapper 提供,值为元素本身。 + * 返回一个收集器,该收集器将输入元素累积到Map中,键由keyMapper提供,值为元素本身 * - * @param keyMapper 键映射函数 - * @param 元素类型 - * @param 键类型 - * @return Collector 实例 + * @param keyMapper 用于产生键的映射函数 + * @param 输入元素的类型 + * @param 键的类型 + * @return 产生Map的收集器 */ public static Collector> toMap(Function keyMapper) { return toMap(keyMapper, Function.identity()); } + /** - * 返回一个用于收集 Map.Entry 到 Map 的 Collector。 + * 返回一个收集器,该收集器将Map.Entry类型的输入元素累积到Map中 * - * @param Map.Entry 类型 - * @param 键类型 - * @param 值类型 - * @return Collector 实例 + * @param 输入元素的类型(必须是Map.Entry) + * @param 键的类型 + * @param 值的类型 + * @return 产生Map的收集器 */ public static , K, V> Collector> toMap() { return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue); } /** - * 过滤流中的元素。 + * 对流中的每个元素应用过滤条件 * - * @param predicate 过滤条件 - * @return 过滤后的 SuperStream 实例 + * @param predicate 用于测试元素是否满足条件的谓词 + * @return 过滤后的SuperStream实例 */ public SuperStream filter(Predicate predicate) { return SuperStream.of(stream.filter(predicate)); } /** - * 使用指定的 Collector 收集流中的元素。 + * 使用指定的收集器对流进行收集操作 * - * @param collector Collector 实例 - * @param 结果类型 - * @param 中间类型 - * @return 收集结果 + * @param collector 用于收集元素的收集器 + * @param 收集结果的类型 + * @param 收集器累加器的类型 + * @return 收集操作的结果 */ public R collect(Collector collector) { return stream.collect(collector); } /** - * 返回此流的Spliterator对象 + * 获取流的Spliterator * - * @return 此流的Spliterator对象,用于并行处理流中的元素 + * @return 流的Spliterator实例 */ @NotNull public Spliterator spliterator() { @@ -678,48 +772,47 @@ public class SuperStream implements Stream { } /** - * 将此流中的每个元素转换为一个IntStream,然后将所有生成的IntStream连接成一个IntStream + * 将每个元素映射为IntStream并展平结果 * - * @param mapper 用于将流中每个元素转换为IntStream的函数 - * @return 由所有转换后的IntStream连接而成的新IntStream + * @param mapper 用于将元素映射为IntStream的函数 + * @return 展平后的IntStream */ public IntStream flatMapToInt(Function mapper) { return stream.flatMapToInt(mapper); } /** - * 判断此流是否为并行流 + * 检查流是否为并行流 * - * @return 如果此流是并行流则返回true,否则返回false + * @return 如果流是并行的则返回true,否则返回false */ public boolean isParallel() { return stream.isParallel(); } /** - * 返回此流的迭代器对象 + * 获取流的迭代器 * - * @return 此流的迭代器对象,用于顺序访问流中的元素 + * @return 流的Iterator实例 */ @NotNull public Iterator iterator() { return stream.iterator(); } - /** - * 对流中每个元素执行指定操作。 + * 对流中的每个元素执行指定的动作 * - * @param action 操作函数 + * @param action 要执行的动作函数 */ public void forEach(P1Function action) { stream.forEach(action::call); } /** - * 对流中每个元素执行指定操作,并传入元素索引。 + * 对流中的每个元素执行指定的动作,并传递索引 * - * @param action 操作函数,接受元素和索引 + * @param action 要执行的动作函数,接收元素和索引作为参数 */ public void forEach(P2Function action) { AtomicInteger i22 = new AtomicInteger(0); @@ -729,29 +822,29 @@ public class SuperStream implements Stream { } /** - * 对流中的每个元素执行给定的操作。 + * 对流中的每个元素执行指定的动作 * - * @param action 要对每个元素执行的操作,不能为 null + * @param action 要执行的动作函数 */ public void forEach(Consumer action) { stream.forEach(action); } /** - * 将流中的每个元素转换为一个流,并将这些流合并为一个流。 + * 将每个元素映射为Stream并展平结果 * - * @param mapper 用于将每个元素映射为流的函数,不能为 null - * @param 映射后流中元素的类型 - * @return 合并后的流 + * @param mapper 用于将元素映射为Stream的函数 + * @param 映射后元素的类型 + * @return 展平后的Stream实例 */ public Stream flatMap(Function> mapper) { return stream.flatMap(mapper); } /** - * 返回一个顺序执行的流。 + * 返回一个串行流 * - * @return 顺序执行的 SuperStream 实例 + * @return 串行的SuperStream实例 */ @NotNull public SuperStream sequential() { @@ -759,32 +852,32 @@ public class SuperStream implements Stream { } /** - * 跳过流中的前 n 个元素。 + * 跳过指定数量的元素 * * @param n 要跳过的元素数量 - * @return 跳过元素后的 SuperStream 实例 + * @return 跳过元素后的SuperStream实例 */ public SuperStream skip(long n) { return SuperStream.of(stream.skip(n)); } /** - * 使用提供的供应器、累加器和组合器对流进行归约操作。 + * 使用指定的收集器对流进行收集操作 * - * @param supplier 结果容器的供应器 - * @param accumulator 将元素累积到结果容器中的函数 - * @param combiner 合并两个结果容器的函数 - * @param 结果容器的类型 - * @return 归约后的结果 + * @param supplier 用于创建初始累加器的供应函数 + * @param accumulator 用于将元素添加到累加器的操作 + * @param combiner 用于合并两个累加器的操作 + * @param 收集结果的类型 + * @return 收集操作的结果 */ public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { return stream.collect(supplier, accumulator, combiner); } /** - * 返回一个并行执行的流。 + * 返回一个并行流 * - * @return 并行执行的 SuperStream 实例 + * @return 并行的SuperStream实例 */ @NotNull public SuperStream parallel() { @@ -792,17 +885,17 @@ public class SuperStream implements Stream { } /** - * 将流中的每个元素映射为 DoubleStream,并将这些流合并为一个 DoubleStream。 + * 将每个元素映射为DoubleStream并展平结果 * - * @param mapper 用于将每个元素映射为 DoubleStream 的函数,不能为 null - * @return 合并后的 DoubleStream + * @param mapper 用于将元素映射为DoubleStream的函数 + * @return 展平后的DoubleStream */ public DoubleStream flatMapToDouble(Function mapper) { return stream.flatMapToDouble(mapper); } /** - * 使用提供的生成器函数将流转换为数组。 + * 将流转换为指定类型的数组 * * @param generator 用于创建数组的函数 * @param 数组元素的类型 @@ -814,9 +907,9 @@ public class SuperStream implements Stream { } /** - * 返回流中的第一个元素(如果存在)。 + * 查找流中的第一个元素 * - * @return 包含第一个元素的 Optional,如果流为空则返回空 Optional + * @return 包含第一个元素的Optional,如果流为空则返回空Optional */ @NotNull public Optional findFirst() { @@ -824,9 +917,9 @@ public class SuperStream implements Stream { } /** - * 返回一个无序的流。 + * 返回一个无序流 * - * @return 无序的 SuperStream 实例 + * @return 无序的SuperStream实例 */ @NotNull public SuperStream unordered() { @@ -834,10 +927,10 @@ public class SuperStream implements Stream { } /** - * 根据提供的比较器返回流中的最小元素(如果存在)。 + * 根据比较器查找流中的最小元素 * - * @param comparator 用于比较元素的比较器,不能为 null - * @return 包含最小元素的 Optional,如果流为空则返回空 Optional + * @param comparator 用于比较元素的比较器 + * @return 包含最小元素的Optional,如果流为空则返回空Optional */ @NotNull public Optional min(Comparator comparator) { @@ -845,9 +938,9 @@ public class SuperStream implements Stream { } /** - * 返回流中的任意元素(如果存在)。 + * 查找流中的任意元素 * - * @return 包含任意元素的 Optional,如果流为空则返回空 Optional + * @return 包含任意元素的Optional,如果流为空则返回空Optional */ @NotNull public Optional findAny() { @@ -855,10 +948,10 @@ public class SuperStream implements Stream { } /** - * 注册一个关闭处理器,在流关闭时执行。 + * 注册一个关闭处理器,在流关闭时执行 * - * @param closeHandler 流关闭时要执行的处理器,不能为 null - * @return 注册了关闭处理器的 SuperStream 实例 + * @param closeHandler 关闭时要执行的Runnable + * @return 添加了关闭处理器的SuperStream实例 */ @NotNull public SuperStream onClose(@NotNull Runnable closeHandler) { @@ -866,23 +959,20 @@ public class SuperStream implements Stream { } /** - * 将流中的每个元素映射为 LongStream,并将这些流合并为一个 LongStream。 + * 将每个元素映射为LongStream并展平结果 * - * @param mapper 用于将每个元素映射为 LongStream 的函数,不能为 null - * @return 合并后的 LongStream + * @param mapper 用于将元素映射为LongStream的函数 + * @return 展平后的LongStream */ public LongStream flatMapToLong(Function mapper) { return stream.flatMapToLong(mapper); } /** - * 将流转换为数组。
- * 使用反射获取类型 是空的的话抛出 - * {@code StreamEmptyException } + * 将流转换为指定类型的数组 * + * @param clazz 数组元素的Class对象 * @return 转换后的数组 - * @throws StreamEmptyException 如果流为空 - * @see StreamEmptyException */ @NotNull @SuppressWarnings("unchecked") @@ -890,32 +980,37 @@ public class SuperStream implements Stream { return stream.toArray(i -> (T[]) Array.newInstance(clazz, i)); } + /** + * 将流转换为Object数组 + * + * @return 转换后的Object数组 + */ @NotNull public Object[] toArray() { return stream.toArray(); } /** - * 按照 encounter order 对流中的每个元素执行给定的操作。 + * 按顺序对流中的每个元素执行指定的动作 * - * @param action 要对每个元素执行的操作,不能为 null + * @param action 要执行的动作函数 */ public void forEachOrdered(Consumer action) { stream.forEachOrdered(action); } /** - * 关闭流并释放相关资源。 + * 关闭流并释放相关资源 */ public void close() { stream.close(); } /** - * 使用提供的累加器函数对流进行归约操作。 + * 对流执行归约操作 * - * @param accumulator 用于归约的累加器函数 - * @return 包含归约结果的 Optional,如果流为空则返回空 Optional + * @param accumulator 用于组合元素的二元操作符 + * @return 归约操作的结果,如果流为空则返回空Optional */ @NotNull public Optional reduce(BinaryOperator accumulator) { @@ -923,89 +1018,89 @@ public class SuperStream implements Stream { } /** - * 根据提供的比较器对流进行排序。 + * 返回一个根据指定比较器排序的流 * - * @param comparator 用于排序的比较器,不能为 null - * @return 排序后的 SuperStream 实例 + * @param comparator 用于比较元素的比较器 + * @return 排序后的SuperStream实例 */ public SuperStream sorted(Comparator comparator) { return SuperStream.of(stream.sorted(comparator)); } /** - * 检查流中的所有元素是否都满足给定的谓词。 + * 检查流中的所有元素是否都满足给定的谓词 * - * @param predicate 用于测试元素的谓词,不能为 null - * @return 如果所有元素都满足谓词则返回 true,否则返回 false + * @param predicate 用于测试元素的谓词 + * @return 如果所有元素都满足谓词或流为空则返回true,否则返回false */ public boolean allMatch(Predicate predicate) { return stream.allMatch(predicate); } /** - * 对流中的元素进行自然排序。 + * 返回一个自然排序的流 * - * @return 排序后的 SuperStream 实例 + * @return 排序后的SuperStream实例 */ public SuperStream sorted() { return SuperStream.of(stream.sorted()); } /** - * 返回流中元素的数量。 + * 计算流中元素的数量 * - * @return 元素的数量 + * @return 流中元素的数量 */ public long count() { return stream.count(); } /** - * 将流中的每个元素通过映射函数转换为另一种类型。 + * 将流中的每个元素通过映射函数转换 * - * @param mapper 用于映射元素的函数,不能为 null + * @param mapper 用于转换元素的映射函数 * @param 映射后元素的类型 - * @return 映射后的 SuperStream 实例 + * @return 转换后的SuperStream实例 */ public SuperStream map(Function mapper) { return SuperStream.of(stream.map(mapper)); } /** - * 使用提供的标识值和累加器函数对流进行归约操作。 + * 对流执行归约操作 * - * @param identity 归约的初始值 - * @param accumulator 用于归约的累加器函数 - * @return 归约后的结果 + * @param identity 归约操作的初始值 + * @param accumulator 用于组合元素的二元操作符 + * @return 归约操作的结果 */ public T reduce(T identity, BinaryOperator accumulator) { return stream.reduce(identity, accumulator); } /** - * 检查流中是否没有任何元素满足给定的谓词。 + * 检查流中的所有元素都不满足给定的谓词 * - * @param predicate 用于测试元素的谓词,不能为 null - * @return 如果没有任何元素满足谓词则返回 true,否则返回 false + * @param predicate 用于测试元素的谓词 + * @return 如果所有元素都不满足谓词则返回true,否则返回false */ public boolean noneMatch(Predicate predicate) { return stream.noneMatch(predicate); } /** - * 返回一个去除重复元素后的流。 + * 返回一个去重后的流 * - * @return 去重后的 SuperStream 实例 + * @return 去重后的SuperStream实例 */ public SuperStream distinct() { return SuperStream.of(stream.distinct()); } /** - * 根据提供的比较器返回流中的最大元素(如果存在)。 + * 根据比较器查找流中的最大元素 * - * @param comparator 用于比较元素的比较器,不能为 null - * @return 包含最大元素的 Optional,如果流为空则返回空 Optional + * @param comparator 用于比较元素的比较器 + * @return 包含最大元素的Optional,如果流为空则返回空Optional */ @NotNull public Optional max(Comparator comparator) { @@ -1013,116 +1108,115 @@ public class SuperStream implements Stream { } /** - * 将流中的每个元素映射为 double 值,并返回一个 DoubleStream。 + * 将流中的每个元素映射为double值 * - * @param mapper 用于将元素映射为 double 的函数,不能为 null - * @return 映射后的 DoubleStream + * @param mapper 用于映射元素为double值的函数 + * @return 映射后的DoubleStream */ public DoubleStream mapToDouble(ToDoubleFunction mapper) { return stream.mapToDouble(mapper); } /** - * 限制流中元素的数量。 + * 限制流中元素的数量 * * @param maxSize 最大元素数量 - * @return 限制后的 SuperStream 实例 + * @return 限制后的SuperStream实例 */ public SuperStream limit(long maxSize) { return SuperStream.of(stream.limit(maxSize)); } /** - * 将流中的每个元素映射为 long 值,并返回一个 LongStream。 + * 将流中的每个元素映射为long值 * - * @param mapper 用于将元素映射为 long 的函数,不能为 null - * @return 映射后的 LongStream + * @param mapper 用于映射元素为long值的函数 + * @return 映射后的LongStream */ public LongStream mapToLong(ToLongFunction mapper) { return stream.mapToLong(mapper); } /** - * 对流中的每个元素执行给定的操作,并返回相同的流。 + * 对流中的每个元素执行动作,然后返回原流 * - * @param action 要对每个元素执行的操作,不能为 null - * @return 相同的 SuperStream 实例 + * @param action 要执行的动作函数 + * @return 原始的SuperStream实例 */ public SuperStream peek(Consumer action) { return SuperStream.of(stream.peek(action)); } /** - * 使用提供的标识值、累加器函数和组合器对流进行归约操作。 + * 对流执行归约操作 * - * @param identity 归约的初始值 - * @param accumulator 用于归约的累加器函数 - * @param combiner 用于合并部分结果的组合器函数 - * @param 归约结果的类型 - * @return 归约后的结果 + * @param identity 归约操作的初始值 + * @param accumulator 用于组合元素的二元操作符 + * @param combiner 用于合并累加器的二元操作符 + * @param 累加器和结果的类型 + * @return 归约操作的结果 */ public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { return stream.reduce(identity, accumulator, combiner); } /** - * 将流中的每个元素映射为 int 值,并返回一个 IntStream。 + * 将流中的每个元素映射为int值 * - * @param mapper 用于将元素映射为 int 的函数,不能为 null - * @return 映射后的 IntStream + * @param mapper 用于映射元素为int值的函数 + * @return 映射后的IntStream */ public IntStream mapToInt(ToIntFunction mapper) { return stream.mapToInt(mapper); } /** - * 检查流中是否有任何元素满足给定的谓词。 + * 检查流中是否有任何元素满足给定的谓词 * - * @param predicate 用于测试元素的谓词,不能为 null - * @return 如果有任何元素满足谓词则返回 true,否则返回 false + * @param predicate 用于测试元素的谓词 + * @return 如果有任何元素满足谓词则返回true,否则返回false */ public boolean anyMatch(Predicate predicate) { return stream.anyMatch(predicate); } - /** - * 获取原始 Stream。 + * 获取被包装的基础Stream对象 * - * @return 原始 Stream 实例 + * @return 基础Stream对象 */ public Stream getStream() { return stream; } /** - * 将流中的元素收集到 Map 中。 + * 将流中的元素收集到Map中,使用指定的键和值映射函数 * - * @param keyMapper 键映射函数 - * @param valueMapper 值映射函数 - * @param 键类型 - * @param 值类型 - * @return 收集结果 Map + * @param keyMapper 用于生成键的映射函数 + * @param valueMapper 用于生成值的映射函数 + * @param 键的类型 + * @param 值的类型 + * @return 包含映射结果的Map */ public Map toAMap(Function keyMapper, Function valueMapper) { return collect(toMap(keyMapper, valueMapper)); } /** - * 将流中的元素收集到 Map 中,值为元素本身。 + * 将流中的元素收集到Map中,使用指定的键映射函数,值为元素本身 * - * @param keyMapper 键映射函数 - * @param 键类型 - * @return 收集结果 Map + * @param keyMapper 用于生成键的映射函数 + * @param 键的类型 + * @return 包含映射结果的Map */ public Map toAMap(Function keyMapper) { return collect(toMap(keyMapper)); } /** - * 将流中的元素收集到 List 中。 + * 将流中的元素收集到List中 * - * @return 收集结果 List + * @return 包含流中所有元素的List */ public List toAList() { return collect(toList()); diff --git a/src/main/kotlin/com/mingliqiye/utils/annotation/AutoService.kt b/src/main/kotlin/com/mingliqiye/utils/annotation/AutoService.kt new file mode 100644 index 0000000..1eee2b2 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/annotation/AutoService.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile AutoService.kt + * LastUpdate 2026-02-07 17:00:39 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.annotation + +import kotlin.reflect.KClass + +/** + * 标记一个类为其提供自动服务注册功能的注解。 + * + * 此注解用于标识那些需要被自动注册为服务的类。通过指定[value]参数, + * 可以声明该类实现的服务接口类型。注解的作用范围限定为类(CLASS), + * 并且仅在源码级别保留(SOURCE),不会编译到字节码中。 + * @since 4.6.3 + * + * @param value 需要注册的服务接口类型数组,默认为空数组。 + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.SOURCE) +annotation class AutoService( + val value: Array> = [] +) diff --git a/src/main/kotlin/com/mingliqiye/utils/annotation/DateTimeJsonFormat.kt b/src/main/kotlin/com/mingliqiye/utils/annotation/DateTimeJsonFormat.kt new file mode 100644 index 0000000..a2b0466 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/annotation/DateTimeJsonFormat.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile DateTimeJsonFormat.kt + * LastUpdate 2026-02-07 08:05:39 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.annotation + +import com.mingliqiye.utils.time.Formatter + +/** + * 日期时间JSON格式化注解,用于标注字段的日期时间格式化方式 + * + * @property value 格式化器类型,默认为NONE + * @property formatter 自定义格式化字符串,默认为空字符串 + * @property repcZero 是否替换零值,默认为true + */ +@Target(AnnotationTarget.FIELD) +annotation class DateTimeJsonFormat( + val value: Formatter = Formatter.NONE, + val formatter: String = "", + val repcZero: Boolean = true, +) diff --git a/src/main/kotlin/com/mingliqiye/utils/annotation/TestAnnotation.kt b/src/main/kotlin/com/mingliqiye/utils/annotation/TestAnnotation.kt new file mode 100644 index 0000000..75cfb13 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/annotation/TestAnnotation.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile TestAnnotation.kt + * LastUpdate 2026-02-07 08:44:25 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.annotation + +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +annotation class TestAnnotation(val value: String = "test") + +@Target(AnnotationTarget.FIELD) +@Retention(AnnotationRetention.SOURCE) +annotation class TestFieldAnnotation(val required: Boolean = true) diff --git a/src/main/kotlin/com/mingliqiye/utils/annotation/UUIDJsonFormat.kt b/src/main/kotlin/com/mingliqiye/utils/annotation/UUIDJsonFormat.kt new file mode 100644 index 0000000..7492fab --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/annotation/UUIDJsonFormat.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UUIDJsonFormat.kt + * LastUpdate 2026-02-07 08:05:58 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.annotation + +import com.mingliqiye.utils.base.BaseType +import com.mingliqiye.utils.uuid.UUIDFormatType + +/** + * UUID JSON格式化注解,用于指定UUID字段在JSON序列化/反序列化时的格式 + * + * @property value UUID格式类型,默认为 NO_UPPER_SPACE + * @property base 基数类型,默认为 BASE16 + */ +@Target(AnnotationTarget.FIELD) +annotation class UUIDJsonFormat( + val value: UUIDFormatType = UUIDFormatType.NO_UPPER_SPACE, + val base: BaseType = BaseType.BASE16 +) diff --git a/src/main/kotlin/com/mingliqiye/utils/annotation/processor/AutoServiceProcessor.kt b/src/main/kotlin/com/mingliqiye/utils/annotation/processor/AutoServiceProcessor.kt new file mode 100644 index 0000000..aa549a9 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/annotation/processor/AutoServiceProcessor.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile AutoServiceProcessor.kt + * LastUpdate 2026-02-08 01:24:16 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.annotation.processor + +import com.mingliqiye.utils.annotation.AutoService +import com.mingliqiye.utils.io.IO.println +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.RoundEnvironment +import javax.annotation.processing.SupportedAnnotationTypes +import javax.lang.model.element.TypeElement +import javax.lang.model.type.MirroredTypesException +import javax.lang.model.type.TypeMirror +import javax.tools.StandardLocation + + +@SupportedAnnotationTypes("com.mingliqiye.utils.annotation.AutoService") +class AutoServiceProcessor : AbstractProcessor() { + override fun init(processingEnv: ProcessingEnvironment) { + super.init(processingEnv) + } + + override fun process( + annotations: Set, + roundEnv: RoundEnvironment + ): Boolean { + + val service = mutableMapOf>() + val elements = roundEnv.getElementsAnnotatedWith(AutoService::class.java) + if (elements.isEmpty()) return false + for (element in elements) { + val autoServiceAnnotation = element.getAnnotation(AutoService::class.java) + var asd = (try { + autoServiceAnnotation!!.value.map { it.java.name } + } catch (e: MirroredTypesException) { + e.typeMirrors.map(TypeMirror::toString) + }) + + if (asd.isEmpty()) { + if (element is TypeElement) { + asd = element.interfaces.map { it.toString() } + } + } + for (data in asd) { + var ldata: MutableList? = service[data] + if (ldata == null) { + ldata = mutableListOf() + service[data] = ldata + } + ldata.add(element.toString()) + } + } + processClassAnnotation(service) + return true + } + + fun processClassAnnotation(map: Map>) { + map.forEach { (interfaceName, implementations) -> + if (implementations.isEmpty()) { + println("警告: $interfaceName 的实现列表为空!") + return@forEach + } + try { + val serviceFile = processingEnv.filer.createResource( + StandardLocation.CLASS_OUTPUT, + "", + "META-INF/services/$interfaceName" + ) + val content = StringBuilder() + serviceFile.openWriter().use { writer -> + implementations.forEach { impl -> + val line = "$impl\n" + content.append(line) + writer.write(line) + } + writer.flush() + } + + } catch (e: Exception) { + println("文件创建失败: ${e.javaClass.name} - ${e.message}") + e.printStackTrace() + } + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/array/ArrayUtils.kt b/src/main/kotlin/com/mingliqiye/utils/array/ArrayUtils.kt new file mode 100644 index 0000000..2aa5150 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/array/ArrayUtils.kt @@ -0,0 +1,342 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ArrayUtils.kt + * LastUpdate 2026-02-06 14:01:56 + * UpdateUser MingLiPro + */ + + +@file:JvmName("ArrayUtils") + +package com.mingliqiye.utils.array + +import com.mingliqiye.utils.base.BASE16 + + +/** + * 将字节数组转换为十六进制字符串 + * + * @return 大写的十六进制字符串,每两个字符表示一个字节 + * @since 4.6.0 + * @see toHexByteArray + */ +fun ByteArray.toHexString(): String = BASE16.encode(this).uppercase() + +/** + * 将十六进制字符串转换为字节数组 + * + * @return 对应的字节数组 + * @throws IllegalArgumentException 如果字符串包含非十六进制字符 + * @since 4.6.0 + * @see toHexString + */ +fun String.toHexByteArray(): ByteArray = BASE16.decode(this.lowercase()) + +/* ==================== 数组复制扩展函数 ==================== */ + +/** + * 将当前数组的指定范围复制到目标数组 + * + * @param dest 目标数组 + * @param srcPos 源数组起始位置(包含) + * @param distPos 目标数组起始位置(包含) + * @param len 要复制的元素数量 + * @return 源数组自身(支持链式调用) + * @throws IndexOutOfBoundsException 如果索引超出范围 + * @throws IllegalArgumentException 如果参数无效 + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun Array.copyTo(dest: Array, srcPos: Int, distPos: Int, len: Int): Array = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * 创建新数组并复制当前数组的指定范围 + * + * @param srcPos 源数组起始位置(包含) + * @param distPos 目标数组起始位置(包含) + * @param len 要复制的元素数量,也作为新数组的长度 + * @return 新创建的数组 + * @throws IndexOutOfBoundsException 如果索引超出范围 + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun Array.copyTo(srcPos: Int, distPos: Int, len: Int): Array = + java.lang.reflect.Array.newInstance(this.javaClass.componentType, len).also { + System.arraycopy(this, srcPos, it, distPos, len) + }.let { + @Suppress("UNCHECKED_CAST") + it as Array + } + +/** + * 将源数组的指定范围复制到当前数组 + * + * @param src 源数组 + * @param srcPos 源数组起始位置(包含) + * @param distPos 当前数组起始位置(包含) + * @param len 要复制的元素数量 + * @return 当前数组自身(支持链式调用) + * @throws IndexOutOfBoundsException 如果索引超出范围 + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun Array.copyFrom(src: Array, srcPos: Int, distPos: Int, len: Int): Array = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== BooleanArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun BooleanArray.copyTo(dest: BooleanArray, srcPos: Int, distPos: Int, len: Int): BooleanArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun BooleanArray.copyTo(srcPos: Int, distPos: Int, len: Int): BooleanArray = + BooleanArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun BooleanArray.copyFrom(src: BooleanArray, srcPos: Int, distPos: Int, len: Int): BooleanArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== ByteArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun ByteArray.copyTo(dest: ByteArray, srcPos: Int, distPos: Int, len: Int): ByteArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun ByteArray.copyTo(srcPos: Int, distPos: Int, len: Int): ByteArray = + ByteArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun ByteArray.copyFrom(src: ByteArray, srcPos: Int, distPos: Int, len: Int): ByteArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== CharArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun CharArray.copyTo(dest: CharArray, srcPos: Int, distPos: Int, len: Int): CharArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun CharArray.copyTo(srcPos: Int, distPos: Int, len: Int): CharArray = + CharArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun CharArray.copyFrom(src: CharArray, srcPos: Int, distPos: Int, len: Int): CharArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== DoubleArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun DoubleArray.copyTo(dest: DoubleArray, srcPos: Int, distPos: Int, len: Int): DoubleArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun DoubleArray.copyTo(srcPos: Int, distPos: Int, len: Int): DoubleArray = + DoubleArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun DoubleArray.copyFrom(src: DoubleArray, srcPos: Int, distPos: Int, len: Int): DoubleArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== FloatArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun FloatArray.copyTo(dest: FloatArray, srcPos: Int, distPos: Int, len: Int): FloatArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun FloatArray.copyTo(srcPos: Int, distPos: Int, len: Int): FloatArray = + FloatArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun FloatArray.copyFrom(src: FloatArray, srcPos: Int, distPos: Int, len: Int): FloatArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== IntArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun IntArray.copyTo(dest: IntArray, srcPos: Int, distPos: Int, len: Int): IntArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun IntArray.copyTo(srcPos: Int, distPos: Int, len: Int): IntArray = + IntArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun IntArray.copyFrom(src: IntArray, srcPos: Int, distPos: Int, len: Int): IntArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== LongArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun LongArray.copyTo(dest: LongArray, srcPos: Int, distPos: Int, len: Int): LongArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun LongArray.copyTo(srcPos: Int, distPos: Int, len: Int): LongArray = + LongArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun LongArray.copyFrom(src: LongArray, srcPos: Int, distPos: Int, len: Int): LongArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} + +/* ==================== ShortArray 扩展 ==================== */ + +/** + * @see Array.copyTo + * @since 4.6.0 + */ +@JvmName("arrayCopy") +fun ShortArray.copyTo(dest: ShortArray, srcPos: Int, distPos: Int, len: Int): ShortArray = this.also { + System.arraycopy(this, srcPos, dest, distPos, len) +} + +/** + * @see Array.copyTo + * @since 4.6.2 + */ +@JvmName("arrayCopy") +fun ShortArray.copyTo(srcPos: Int, distPos: Int, len: Int): ShortArray = + ShortArray(len).also { newArray -> + System.arraycopy(this, srcPos, newArray, distPos, len) + } + +/** + * @see Array.copyFrom + * @since 4.6.1 + */ +@JvmName("arrayCopyFrom") +fun ShortArray.copyFrom(src: ShortArray, srcPos: Int, distPos: Int, len: Int): ShortArray = this.also { + System.arraycopy(src, srcPos, this, distPos, len) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base10.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base10.kt new file mode 100644 index 0000000..8f3ff98 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base10.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Base10.kt + * LastUpdate 2026-02-08 03:08:10 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.base + +import java.math.BigInteger + +internal class Base10 : BaseCodec { + + /** + * 将字节数组编码为Base10字符串(十进制) + * + * @param bytes 需要编码的字节数组 + * @return 编码后的Base10字符串(十进制数字) + */ + override fun encode(bytes: ByteArray): String { + if (bytes.isEmpty()) return "0" + + // 将字节数组转换为正的大整数 + val bigInt = BigInteger(1, bytes) // 参数1表示正数 + return bigInt.toString(10) // 转换为10进制字符串 + } + + /** + * 将Base10字符串解码为字节数组 + * + * @param string 需要解码的Base10字符串(十进制数字) + * @return 解码后的字节数组 + */ + override fun decode(string: String): ByteArray { + // 验证输入是否为有效的十进制数字 + if (!string.matches(Regex("\\d+"))) { + throw IllegalArgumentException("Base10字符串只能包含数字0-9") + } + + val bigInt = BigInteger(string, 10) // 从10进制解析 + + // 转换为字节数组,并确保保留前导零 + var byteArray = bigInt.toByteArray() + + // BigInteger.toByteArray() 可能会添加一个符号字节 + // 对于正数,如果第一个字节是0,需要移除它 + if (byteArray.isNotEmpty() && byteArray[0] == 0.toByte()) { + byteArray = byteArray.copyOfRange(1, byteArray.size) + } + + return byteArray + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base16.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base16.kt index 1f0eb7b..f668711 100644 --- a/src/main/kotlin/com/mingliqiye/utils/base/Base16.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base16.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Base16.kt - * LastUpdate 2025-09-17 10:56:07 + * LastUpdate 2026-02-08 03:08:10 * UpdateUser MingLiPro */ @@ -26,7 +26,7 @@ package com.mingliqiye.utils.base * Base16编解码器实现类 * 提供字节数组与十六进制字符串之间的相互转换功能 */ -class Base16 : BaseCodec { +internal class Base16 : BaseCodec { /** * 将字节数组编码为十六进制字符串 * @param bytes 待编码的字节数组 diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base2.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base2.kt new file mode 100644 index 0000000..c5fc9e9 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base2.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Base2.kt + * LastUpdate 2026-02-08 03:06:23 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.base + +internal class Base2 : BaseCodec { + override fun encode(bytes: ByteArray): String { + if (bytes.isEmpty()) return "" + val result = StringBuilder() + for ((index, byte) in bytes.withIndex()) { + val unsignedByte = byte.toInt() and 0xFF + val binary = unsignedByte.toString(2).padStart(8, '0') + result.append(binary) + } + return result.toString() + } + + override fun decode(string: String): ByteArray { + if (string.length % 8 != 0) { + throw IllegalArgumentException( + "BASE1字符串长度必须是8的倍数,当前长度: ${string.length}" + ) + } + if (!string.matches(Regex("[01]+"))) { + throw IllegalArgumentException( + "BASE1字符串只能包含字符'0'和'1'" + ) + } + val byteCount = string.length / 8 + val result = ByteArray(byteCount) + for (i in 0 until byteCount) { + val startIndex = i * 8 + val endIndex = startIndex + 8 + val binaryStr = string.substring(startIndex, endIndex) + val byteValue = binaryStr.toInt(2) + result[i] = byteValue.toByte() + } + return result + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base256.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base256.kt index 77d9766..1c264ec 100644 --- a/src/main/kotlin/com/mingliqiye/utils/base/Base256.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base256.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Base256.kt - * LastUpdate 2025-09-20 14:01:29 + * LastUpdate 2026-02-08 03:08:10 * UpdateUser MingLiPro */ @@ -30,7 +30,7 @@ package com.mingliqiye.utils.base * !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~§±×÷←↑→↓⇒⇔∀∃∅∆∇∈∉∋∌∏∑−∓∕∗∘∙√∛∜∞∟∠∣∥∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷≈≠≡≤≥≦≧≪≫≺≻⊂⊃⊆⊇⊈⊉⊊⊋⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙ * */ -class Base256 : BaseCodec { +internal class Base256 : BaseCodec { companion object { val code = arrayOf( diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base64.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base64.kt index ca86f1c..6e3efcd 100644 --- a/src/main/kotlin/com/mingliqiye/utils/base/Base64.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base64.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Base64.kt - * LastUpdate 2025-09-17 10:56:32 + * LastUpdate 2026-02-08 03:08:10 * UpdateUser MingLiPro */ @@ -26,7 +26,7 @@ package com.mingliqiye.utils.base * Base64编解码工具类 * 提供Base64编码和解码功能的实现 */ -class Base64 : BaseCodec { +internal class Base64 : BaseCodec { /* * Base64编码器实例 diff --git a/src/main/kotlin/com/mingliqiye/utils/base/Base91.kt b/src/main/kotlin/com/mingliqiye/utils/base/Base91.kt index ba31a2b..ef40578 100644 --- a/src/main/kotlin/com/mingliqiye/utils/base/Base91.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/Base91.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Base91.kt - * LastUpdate 2025-09-19 20:08:46 + * LastUpdate 2026-02-08 03:08:10 * UpdateUser MingLiPro */ @@ -27,7 +27,7 @@ package com.mingliqiye.utils.base * * Base91 是一种高效的二进制到文本的编码方式,相较于 Base64,它使用更少的字符来表示相同的数据。 */ -class Base91 : BaseCodec { +internal class Base91 : BaseCodec { companion object { /** diff --git a/src/main/kotlin/com/mingliqiye/utils/json/JsonException.kt b/src/main/kotlin/com/mingliqiye/utils/base/BaseType.kt similarity index 64% rename from src/main/kotlin/com/mingliqiye/utils/json/JsonException.kt rename to src/main/kotlin/com/mingliqiye/utils/base/BaseType.kt index 86692d2..87882ec 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/JsonException.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/BaseType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,16 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile JsonException.kt - * LastUpdate 2025-09-15 22:32:50 + * CurrentFile BaseType.kt + * LastUpdate 2026-02-04 21:54:04 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.json +package com.mingliqiye.utils.base -class JsonException : RuntimeException { - - constructor(message: String) : super(message) - - constructor(message: String, cause: Throwable) : super(message, cause) - - constructor(cause: Throwable) : this(cause.message ?: "", cause) +enum class BaseType(val baseCodec: BaseCodec) { + BASE16(com.mingliqiye.utils.base.BASE16), + BASE64(com.mingliqiye.utils.base.BASE64), + BASE91(com.mingliqiye.utils.base.BASE91), + BASE256(com.mingliqiye.utils.base.BASE256), } diff --git a/src/main/kotlin/com/mingliqiye/utils/base/BaseUtils.kt b/src/main/kotlin/com/mingliqiye/utils/base/BaseUtils.kt index ac4d998..1960288 100644 --- a/src/main/kotlin/com/mingliqiye/utils/base/BaseUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/base/BaseUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile BaseUtils.kt - * LastUpdate 2025-09-19 20:18:09 + * LastUpdate 2026-02-08 03:00:37 * UpdateUser MingLiPro */ @@ -24,40 +24,49 @@ package com.mingliqiye.utils.base -/** - * Base64编解码器实例 - * 使用懒加载方式初始化Base64编解码器对象 - * 保证线程安全且只在首次访问时创建实例 - */ -val BASE64: BaseCodec by lazy { - Base64() -} - -/** - * Base91编解码器实例 - * 使用懒加载方式初始化Base91编解码器对象 - * 保证线程安全且只在首次访问时创建实例 - */ -val BASE91: BaseCodec by lazy { - Base91() -} - -/** - * Base91编解码器实例 - * 使用懒加载方式初始化Base91编解码器对象 - * 保证线程安全且只在首次访问时创建实例 - */ -val BASE16: BaseCodec by lazy { - Base16() -} - -/** - * Base256编解码器实例 - * 使用懒加载方式初始化Base256编解码器对象 - * 保证线程安全且只在首次访问时创建实例 - */ -val BASE256: BaseCodec by lazy { - Base256() -} +import com.mingliqiye.utils.base.code.Base10 +import com.mingliqiye.utils.base.code.Base16 +import com.mingliqiye.utils.base.code.Base256 +import com.mingliqiye.utils.base.code.Base64 +import com.mingliqiye.utils.base.code.Base91 +@Deprecated( + "重命名", replaceWith = ReplaceWith( + expression = "Base10", imports = ["com.mingliqiye.utils.base.code"] + ) +) +val BASE10: BaseCodec + get() = Base10 + +@Deprecated( + "重命名", replaceWith = ReplaceWith( + expression = "Base16", imports = ["com.mingliqiye.utils.base.code"] + ) +) +val BASE16: BaseCodec + get() = Base16 + +@Deprecated( + "重命名", replaceWith = ReplaceWith( + expression = "Base64", imports = ["com.mingliqiye.utils.base.code"] + ) +) +val BASE64: BaseCodec + get() = Base64 + +@Deprecated( + "重命名", replaceWith = ReplaceWith( + expression = "Base91", imports = ["com.mingliqiye.utils.base.code"] + ) +) +val BASE91: BaseCodec + get() = Base91 + +@Deprecated( + "重命名", replaceWith = ReplaceWith( + expression = "Base256", imports = ["com.mingliqiye.utils.base.code"] + ) +) +val BASE256: BaseCodec + get() = Base256 diff --git a/src/main/kotlin/com/mingliqiye/utils/base/code/BaseCodes.kt b/src/main/kotlin/com/mingliqiye/utils/base/code/BaseCodes.kt new file mode 100644 index 0000000..9e6e43e --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/base/code/BaseCodes.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseCodes.kt + * LastUpdate 2026-02-08 03:10:03 + * UpdateUser MingLiPro + */ + +@file:JvmName("BaseCodes") + +package com.mingliqiye.utils.base.code + +import com.mingliqiye.utils.base.* + +/** + * 提供Base2编码器的懒加载实例。 + * 该编码器用于将数据编码为二进制格式。 + */ +@get:JvmName("Base2") +val Base2: BaseCodec by lazy { + Base2() +} + +/** + * 提供Base10编码器的懒加载实例。 + * 该编码器用于将数据编码为十进制格式。 + */ +@get:JvmName("Base10") +val Base10: BaseCodec by lazy { + Base10() +} + +/** + * 提供Base16编码器的懒加载实例。 + * 该编码器用于将数据编码为十六进制格式。 + */ +@get:JvmName("Base16") +val Base16: BaseCodec by lazy { + Base16() +} + +/** + * 提供Base64编码器的懒加载实例。 + * 该编码器用于将数据编码为Base64格式,常用于URL安全传输或存储。 + */ +@get:JvmName("Base64") +val Base64: BaseCodec by lazy { + Base64() +} + +/** + * 提供Base91编码器的懒加载实例。 + * 该编码器用于将数据编码为Base91格式,具有较高的压缩效率。 + */ +@get:JvmName("Base91") +val Base91: BaseCodec by lazy { + Base91() +} + +/** + * 提供Base256编码器的懒加载实例。 + * 该编码器用于将数据编码为Base256格式,适用于字节级数据处理。 + */ +@get:JvmName("Base256") +val Base256: BaseCodec by lazy { + Base256() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/clone/CloneUtils.kt b/src/main/kotlin/com/mingliqiye/utils/clone/CloneUtils.kt index 5900668..bb69204 100644 --- a/src/main/kotlin/com/mingliqiye/utils/clone/CloneUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/clone/CloneUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile CloneUtils.kt - * LastUpdate 2025-09-20 14:01:29 + * LastUpdate 2026-02-05 14:41:27 * UpdateUser MingLiPro */ @file:JvmName("CloneUtils") package com.mingliqiye.utils.clone -import com.mingliqiye.utils.json.JsonApi -import com.mingliqiye.utils.json.JsonException +import com.mingliqiye.utils.exception.JsonException +import com.mingliqiye.utils.json.api.base.JsonApi import java.io.* @@ -34,8 +34,7 @@ inline fun Serializable.deepClone(): T { inline fun T.deepJsonClone(jsonApi: JsonApi): T { try { - return jsonApi.convert(this, this!!.javaClass) as T - + return jsonApi.convert(this as Any, this!!.javaClass) as T } catch (e: Exception) { throw JsonException( "Failed to deep clone object using JSON", e diff --git a/src/main/kotlin/com/mingliqiye/utils/concurrent/IsChanged.kt b/src/main/kotlin/com/mingliqiye/utils/concurrent/IsChanged.kt index fcad409..75f5175 100644 --- a/src/main/kotlin/com/mingliqiye/utils/concurrent/IsChanged.kt +++ b/src/main/kotlin/com/mingliqiye/utils/concurrent/IsChanged.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile IsChanged.kt - * LastUpdate 2025-09-19 20:17:07 + * LastUpdate 2026-01-31 21:13:45 * UpdateUser MingLiPro */ @@ -39,17 +39,14 @@ class IsChanged { */ private val atomicReferenceData: AtomicReference = AtomicReference() - /** - * 默认构造函数,初始化数据为 null - */ - constructor() : this(null) + constructor() /** * 带参数的构造函数,使用指定的初始值初始化 * * @param data 初始数据值 */ - constructor(data: T?) : super() { + constructor(data: T) : super() { atomicReferenceData.set(data) } @@ -67,7 +64,7 @@ class IsChanged { * * @return 当前数据值 */ - fun get(): T? { + fun get(): T { return atomicReferenceData.get() } @@ -77,7 +74,7 @@ class IsChanged { * @param data 要设置的新数据值 * @return 设置前的旧数据值 */ - fun setAndGet(data: T): T? { + fun setAndGet(data: T): T { return atomicReferenceData.getAndSet(data) } @@ -89,7 +86,7 @@ class IsChanged { * @return 如果值发生变化返回 true,否则返回 false */ fun setAndChanged(data: T): Boolean { - var currentData: T? + var currentData: T do { currentData = get() // 如果新值与当前值相等,则认为没有变化,直接返回 false diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/BadGatewayException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/BadGatewayException.kt new file mode 100644 index 0000000..12383fb --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/BadGatewayException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BadGatewayException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 502 Bad Gateway 异常。 + * + * @param message 异常信息,默认为 "Bad Gateway" + * @param cause 异常原因,默认为 null + */ +class BadGatewayException( + override val message: String? = "Bad Gateway", + override val cause: Throwable? = null, +) : HttpStatusException(502, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/BadRequestException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/BadRequestException.kt new file mode 100644 index 0000000..6740250 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/BadRequestException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BadRequestException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 400 Bad Request 异常。 + * + * @param message 异常信息,默认为 "Bad Request" + * @param cause 异常原因,默认为 null + */ +class BadRequestException( + override val message: String? = "Bad Request", + override val cause: Throwable? = null, +) : HttpStatusException(400, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/ConflictException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/ConflictException.kt new file mode 100644 index 0000000..8027621 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/ConflictException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ConflictException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 409 Conflict 异常。 + * + * @param message 异常信息,默认为 "Conflict" + * @param cause 异常原因,默认为 null + */ +class ConflictException( + override val message: String? = "Conflict", + override val cause: Throwable? = null, +) : HttpStatusException(409, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/EmptyJsonException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/EmptyJsonException.kt new file mode 100644 index 0000000..07a7bd7 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/EmptyJsonException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile EmptyJsonException.kt + * LastUpdate 2026-02-07 14:45:12 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +class EmptyJsonException : JsonException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/ForbiddenException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/ForbiddenException.kt new file mode 100644 index 0000000..e0700c8 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/ForbiddenException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ForbiddenException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 403 Forbidden 异常。 + * + * @param message 异常信息,默认为 "Forbidden" + * @param cause 异常原因,默认为 null + */ +class ForbiddenException( + override val message: String? = "Forbidden", + override val cause: Throwable? = null, +) : HttpStatusException(403, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/FoundException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/FoundException.kt new file mode 100644 index 0000000..5474ffc --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/FoundException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile FoundException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 302 Found 异常。 + * + * @param message 异常信息,默认为 "Found" + * @param cause 异常原因,默认为 null + */ +class FoundException( + override val message: String? = "Found", + override val cause: Throwable? = null, +) : HttpStatusException(302, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/GatewayTimeoutException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/GatewayTimeoutException.kt new file mode 100644 index 0000000..301411d --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/GatewayTimeoutException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile GatewayTimeoutException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 504 Gateway Timeout 异常。 + * + * @param message 异常信息,默认为 "Gateway Timeout" + * @param cause 异常原因,默认为 null + */ +class GatewayTimeoutException( + override val message: String? = "Gateway Timeout", + override val cause: Throwable? = null, +) : HttpStatusException(504, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/GoneException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/GoneException.kt new file mode 100644 index 0000000..bf40e6b --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/GoneException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile GoneException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 410 Gone 异常。 + * + * @param message 异常信息,默认为 "Gone" + * @param cause 异常原因,默认为 null + */ +class GoneException( + override val message: String? = "Gone", + override val cause: Throwable? = null, +) : HttpStatusException(410, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/HttpException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/HttpException.kt new file mode 100644 index 0000000..2e54cc8 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/HttpException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile HttpException.kt + * LastUpdate 2026-02-05 14:44:15 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +open class HttpException : MingLiUtilsBaseException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/HttpStatusException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/HttpStatusException.kt new file mode 100644 index 0000000..0c35236 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/HttpStatusException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile HttpStatusException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 异常的基类,继承自 [RuntimeException]。 + * + * @param statusCode HTTP 状态码 + * @param message 异常信息,默认为 null + * @param cause 异常原因,默认为 null + */ +sealed class HttpStatusException( + open val statusCode: Int, + override val message: String? = null, + override val cause: Throwable? = null +) : MingLiUtilsBaseException(message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/HttpUrlException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/HttpUrlException.kt new file mode 100644 index 0000000..e8d88d8 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/HttpUrlException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile HttpUrlException.kt + * LastUpdate 2026-02-05 15:21:48 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +open class HttpUrlException : HttpException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/HttpVersionNotSupportedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/HttpVersionNotSupportedException.kt new file mode 100644 index 0000000..3657716 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/HttpVersionNotSupportedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile HttpVersionNotSupportedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 505 HTTP Version Not Supported 异常。 + * + * @param message 异常信息,默认为 "HTTP Version Not Supported" + * @param cause 异常原因,默认为 null + */ +class HttpVersionNotSupportedException( + override val message: String? = "HTTP Version Not Supported", + override val cause: Throwable? = null, +) : HttpStatusException(505, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/InternalServerErrorException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/InternalServerErrorException.kt new file mode 100644 index 0000000..6b3e014 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/InternalServerErrorException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile InternalServerErrorException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 500 Internal Server Error 异常。 + * + * @param message 异常信息,默认为 "Internal Server Error" + * @param cause 异常原因,默认为 null + */ +class InternalServerErrorException( + override val message: String? = "Internal Server Error", + override val cause: Throwable? = null, +) : HttpStatusException(500, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/InvalidJsonException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/InvalidJsonException.kt new file mode 100644 index 0000000..b10c2aa --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/InvalidJsonException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile InvalidJsonException.kt + * LastUpdate 2026-02-07 13:18:32 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +class InvalidJsonException : JsonException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/JsonException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/JsonException.kt new file mode 100644 index 0000000..da1b6a6 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/JsonException.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonException.kt + * LastUpdate 2026-02-07 13:17:50 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 自定义异常类,用于处理 JSON 相关操作中出现的错误。 + * + * 该类继承自 [RuntimeException],提供了三种构造函数以支持不同的异常场景: + * 1. 仅包含错误信息的构造函数。 + * 2. 包含错误信息和原因(Throwable)的构造函数。 + * 3. 仅包含原因(Throwable)的构造函数。 + */ +open class JsonException : MingLiUtilsBaseException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/JsonObjectCastException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/JsonObjectCastException.kt new file mode 100644 index 0000000..848c187 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/JsonObjectCastException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonObjectCastException.kt + * LastUpdate 2026-02-07 15:11:42 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +class JsonObjectCastException : JsonException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/JsonParserException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/JsonParserException.kt new file mode 100644 index 0000000..641da0a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/JsonParserException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonParserException.kt + * LastUpdate 2026-02-07 14:45:12 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +class JsonParserException : JsonException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/JsonTypeException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/JsonTypeException.kt new file mode 100644 index 0000000..8d9a982 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/JsonTypeException.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonTypeException.kt + * LastUpdate 2026-02-07 13:28:02 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +class JsonTypeException : JsonException { + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/LengthRequiredException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/LengthRequiredException.kt new file mode 100644 index 0000000..7b00c53 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/LengthRequiredException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile LengthRequiredException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 411 Length Required 异常。 + * + * @param message 异常信息,默认为 "Length Required" + * @param cause 异常原因,默认为 null + */ +class LengthRequiredException( + override val message: String? = "Length Required", + override val cause: Throwable? = null, +) : HttpStatusException(411, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/MethodNotAllowedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/MethodNotAllowedException.kt new file mode 100644 index 0000000..9e49a0e --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/MethodNotAllowedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MethodNotAllowedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 405 Method Not Allowed 异常。 + * + * @param message 异常信息,默认为 "Method Not Allowed" + * @param cause 异常原因,默认为 null + */ +class MethodNotAllowedException( + override val message: String? = "Method Not Allowed", + override val cause: Throwable? = null, +) : HttpStatusException(405, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/MingLiUtilsBaseException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/MingLiUtilsBaseException.kt new file mode 100644 index 0000000..d6dc063 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/MingLiUtilsBaseException.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MingLiUtilsBaseException.kt + * LastUpdate 2026-02-05 14:41:27 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +open class MingLiUtilsBaseException : RuntimeException { + + constructor() + constructor(message: String) : super(message) + constructor(throwable: Throwable) : super(throwable) + constructor(message: String, throwable: Throwable) : super(message, throwable) + constructor( + message: String? = null, + throwable: Throwable? = null, + enableSuppression: Boolean = false, + writableStackTrace: Boolean = false + ) : super(message, throwable, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/MovedPermanentlyException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/MovedPermanentlyException.kt new file mode 100644 index 0000000..9e99733 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/MovedPermanentlyException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MovedPermanentlyException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 301 Moved Permanently 异常。 + * + * @param message 异常信息,默认为 "Moved Permanently" + * @param cause 异常原因,默认为 null + */ +class MovedPermanentlyException( + override val message: String? = "Moved Permanently", + override val cause: Throwable? = null, +) : HttpStatusException(301, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/MultipleChoicesException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/MultipleChoicesException.kt new file mode 100644 index 0000000..03417eb --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/MultipleChoicesException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MultipleChoicesException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 300 Multiple Choices 异常。 + * + * @param message 异常信息,默认为 "Multiple Choices" + * @param cause 异常原因,默认为 null + */ +class MultipleChoicesException( + override val message: String? = "Multiple Choices", + override val cause: Throwable? = null, +) : HttpStatusException(300, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/NotAcceptableException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/NotAcceptableException.kt new file mode 100644 index 0000000..0eab586 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/NotAcceptableException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NotAcceptableException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 406 Not Acceptable 异常。 + * + * @param message 异常信息,默认为 "Not Acceptable" + * @param cause 异常原因,默认为 null + */ +class NotAcceptableException( + override val message: String? = "Not Acceptable", + override val cause: Throwable? = null, +) : HttpStatusException(406, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/NotFoundException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/NotFoundException.kt new file mode 100644 index 0000000..9918860 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/NotFoundException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NotFoundException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 404 Not Found 异常。 + * + * @param message 异常信息,默认为 "Not Found" + * @param cause 异常原因,默认为 null + */ +class NotFoundException( + override val message: String? = "Not Found", + override val cause: Throwable? = null, +) : HttpStatusException(404, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/NotImplementedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/NotImplementedException.kt new file mode 100644 index 0000000..7cbed2d --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/NotImplementedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NotImplementedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 501 Not Implemented 异常。 + * + * @param message 异常信息,默认为 "Not Implemented" + * @param cause 异常原因,默认为 null + */ +class NotImplementedException( + override val message: String? = "Not Implemented", + override val cause: Throwable? = null, +) : HttpStatusException(501, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/NotModifiedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/NotModifiedException.kt new file mode 100644 index 0000000..6ab4f46 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/NotModifiedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NotModifiedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 304 Not Modified 异常。 + * + * @param message 异常信息,默认为 "Not Modified" + * @param cause 异常原因,默认为 null + */ +class NotModifiedException( + override val message: String? = "Not Modified", + override val cause: Throwable? = null, +) : HttpStatusException(304, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/PaymentRequiredException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/PaymentRequiredException.kt new file mode 100644 index 0000000..3c69664 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/PaymentRequiredException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile PaymentRequiredException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 402 Payment Required 异常。 + * + * @param message 异常信息,默认为 "Payment Required" + * @param cause 异常原因,默认为 null + */ +class PaymentRequiredException( + override val message: String? = "Payment Required", + override val cause: Throwable? = null, +) : HttpStatusException(402, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/PreconditionFailedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/PreconditionFailedException.kt new file mode 100644 index 0000000..ce05382 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/PreconditionFailedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile PreconditionFailedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 412 Precondition Failed 异常。 + * + * @param message 异常信息,默认为 "Precondition Failed" + * @param cause 异常原因,默认为 null + */ +class PreconditionFailedException( + override val message: String? = "Precondition Failed", + override val cause: Throwable? = null, +) : HttpStatusException(412, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/ProxyAuthenticationRequiredException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/ProxyAuthenticationRequiredException.kt new file mode 100644 index 0000000..2c784f1 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/ProxyAuthenticationRequiredException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ProxyAuthenticationRequiredException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 407 Proxy Authentication Required 异常。 + * + * @param message 异常信息,默认为 "Proxy Authentication Required" + * @param cause 异常原因,默认为 null + */ +class ProxyAuthenticationRequiredException( + override val message: String? = "Proxy Authentication Required", + override val cause: Throwable? = null, +) : HttpStatusException(407, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/RequestEntityTooLargeException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/RequestEntityTooLargeException.kt new file mode 100644 index 0000000..0ef8bc7 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/RequestEntityTooLargeException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile RequestEntityTooLargeException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 413 Request Entity Too Large 异常。 + * + * @param message 异常信息,默认为 "Request Entity Too Large" + * @param cause 异常原因,默认为 null + */ +class RequestEntityTooLargeException( + override val message: String? = "Request Entity Too Large", + override val cause: Throwable? = null, +) : HttpStatusException(413, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/RequestTimeoutException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/RequestTimeoutException.kt new file mode 100644 index 0000000..8c29bf1 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/RequestTimeoutException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile RequestTimeoutException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 408 Request Timeout 异常。 + * + * @param message 异常信息,默认为 "Request Timeout" + * @param cause 异常原因,默认为 null + */ +class RequestTimeoutException( + override val message: String? = "Request Timeout", + override val cause: Throwable? = null, +) : HttpStatusException(408, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/RequestUriTooLargeException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/RequestUriTooLargeException.kt new file mode 100644 index 0000000..d7c8bc6 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/RequestUriTooLargeException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile RequestUriTooLargeException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 414 Request URI Too Large 异常。 + * + * @param message 异常信息,默认为 "Request URI Too Large" + * @param cause 异常原因,默认为 null + */ +class RequestUriTooLargeException( + override val message: String? = "Request URI Too Large", + override val cause: Throwable? = null, +) : HttpStatusException(414, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/RequestedRangeNotSatisfiableException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/RequestedRangeNotSatisfiableException.kt new file mode 100644 index 0000000..64773a6 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/RequestedRangeNotSatisfiableException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile RequestedRangeNotSatisfiableException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 416 Requested Range Not Satisfiable 异常。 + * + * @param message 异常信息,默认为 "Requested Range Not Satisfiable" + * @param cause 异常原因,默认为 null + */ +class RequestedRangeNotSatisfiableException( + override val message: String? = "Requested Range Not Satisfiable", + override val cause: Throwable? = null, +) : HttpStatusException(416, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/SeeOtherException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/SeeOtherException.kt new file mode 100644 index 0000000..bcbe25e --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/SeeOtherException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile SeeOtherException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 303 See Other 异常。 + * + * @param message 异常信息,默认为 "See Other" + * @param cause 异常原因,默认为 null + */ +class SeeOtherException( + override val message: String? = "See Other", + override val cause: Throwable? = null, +) : HttpStatusException(303, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/ServiceUnavailableException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/ServiceUnavailableException.kt new file mode 100644 index 0000000..d231881 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/ServiceUnavailableException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ServiceUnavailableException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 503 Service Unavailable 异常。 + * + * @param message 异常信息,默认为 "Service Unavailable" + * @param cause 异常原因,默认为 null + */ +class ServiceUnavailableException( + override val message: String? = "Service Unavailable", + override val cause: Throwable? = null, +) : HttpStatusException(503, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/TemporaryRedirectException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/TemporaryRedirectException.kt new file mode 100644 index 0000000..eaccf2f --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/TemporaryRedirectException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile TemporaryRedirectException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 307 Temporary Redirect 异常。 + * + * @param message 异常信息,默认为 "Temporary Redirect" + * @param cause 异常原因,默认为 null + */ +class TemporaryRedirectException( + override val message: String? = "Temporary Redirect", + override val cause: Throwable? = null, +) : HttpStatusException(307, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/UnauthorizedException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/UnauthorizedException.kt new file mode 100644 index 0000000..c1d936e --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/UnauthorizedException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UnauthorizedException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 401 Unauthorized 异常。 + * + * @param message 异常信息,默认为 "Unauthorized" + * @param cause 异常原因,默认为 null + */ +class UnauthorizedException( + override val message: String? = "Unauthorized", + override val cause: Throwable? = null, +) : HttpStatusException(401, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/UnsupportedMediaTypeException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/UnsupportedMediaTypeException.kt new file mode 100644 index 0000000..c21f046 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/UnsupportedMediaTypeException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UnsupportedMediaTypeException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 415 Unsupported Media Type 异常。 + * + * @param message 异常信息,默认为 "Unsupported Media Type" + * @param cause 异常原因,默认为 null + */ +class UnsupportedMediaTypeException( + override val message: String? = "Unsupported Media Type", + override val cause: Throwable? = null, +) : HttpStatusException(415, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/exception/UseProxyException.kt b/src/main/kotlin/com/mingliqiye/utils/exception/UseProxyException.kt new file mode 100644 index 0000000..870a815 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/exception/UseProxyException.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UseProxyException.kt + * LastUpdate 2026-02-05 14:55:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.exception + +/** + * 表示 HTTP 305 Use Proxy 异常。 + * + * @param message 异常信息,默认为 "Use Proxy" + * @param cause 异常原因,默认为 null + */ +class UseProxyException( + override val message: String? = "Use Proxy", + override val cause: Throwable? = null, +) : HttpStatusException(305, message, cause) diff --git a/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt b/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt index 56d8375..f4be62d 100644 --- a/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/file/FileUtils.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile FileUtils.kt - * LastUpdate 2026-01-11 09:20:20 + * LastUpdate 2026-01-28 10:49:14 * UpdateUser MingLiPro */ @file:JvmName("FileUtils") @@ -642,27 +642,6 @@ fun File.copyTo(target: File) { target.parentFile?.mkdirs() this.copyTo(target, overwrite = true) } - -// 删除文件 -/** - * 删除文件 - * - * @return 删除操作是否成功 - */ -fun File.delete(): Boolean { - return this.delete() -} - -// 检查文件是否存在 -/** - * 检查文件是否存在 - * - * @return 文件是否存在 - */ -fun File.exists(): Boolean { - return this.exists() -} - // 获取文件大小 /** * 获取文件大小 diff --git a/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt b/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt index ece9ab7..ed87d46 100644 --- a/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt +++ b/src/main/kotlin/com/mingliqiye/utils/functions/Functions.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Functions.kt - * LastUpdate 2026-01-11 09:10:48 + * LastUpdate 2026-02-05 11:20:59 * UpdateUser MingLiPro */ @@ -24,6 +24,19 @@ package com.mingliqiye.utils.functions +fun T.with(function: Function): T = function.call().let { + this +} + +fun T.with(function: P1Function): T = function.call(this).let { + this +} + +@FunctionalInterface +fun interface Function { + fun call() +} + @FunctionalInterface fun interface P1Function

{ fun call(p: P) @@ -128,3 +141,597 @@ fun interface P10Function { fun interface P10RFunction { fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R } + +@FunctionalInterface +fun interface P11Function { + fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10) +} + +@FunctionalInterface +fun interface P11RFunction { + fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R +} + +@FunctionalInterface +fun interface P12Function { + fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11) +} + +@FunctionalInterface +fun interface P12RFunction { + fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11): R +} + +@FunctionalInterface +fun interface P13Function { + fun call(p: P, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12) +} + +@FunctionalInterface +fun interface P13RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12 + ): R +} + +@FunctionalInterface +fun interface P14Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13 + ) +} + +@FunctionalInterface +fun interface P14RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13 + ): R +} + +@FunctionalInterface +fun interface P15Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14 + ) +} + +@FunctionalInterface +fun interface P15RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14 + ): R +} + +@FunctionalInterface +fun interface P16Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15 + ) +} + +@FunctionalInterface +fun interface P16RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15 + ): R +} + +@FunctionalInterface +fun interface P17Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16 + ) +} + +@FunctionalInterface +fun interface P17RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16 + ): R +} + +@FunctionalInterface +fun interface P18Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17 + ) +} + +@FunctionalInterface +fun interface P18RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17 + ): R +} + +@FunctionalInterface +fun interface P19Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18 + ) +} + +@FunctionalInterface +fun interface P19RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18 + ): R +} + +@FunctionalInterface +fun interface P20Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19 + ) +} + +@FunctionalInterface +fun interface P20RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19 + ): R +} + +@FunctionalInterface +fun interface P21Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20 + ) +} + +@FunctionalInterface +fun interface P21RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20 + ): R +} + +@FunctionalInterface +fun interface P22Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21 + ) +} + +@FunctionalInterface +fun interface P22RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21 + ): R +} + +@FunctionalInterface +fun interface P23Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21, + p22: P22 + ) +} + +@FunctionalInterface +fun interface P23RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21, + p22: P22 + ): R +} + +@FunctionalInterface +fun interface P24Function { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21, + p22: P22, + p23: P23 + ) +} + +@FunctionalInterface +fun interface P24RFunction { + fun call( + p: P, + p1: P1, + p2: P2, + p3: P3, + p4: P4, + p5: P5, + p6: P6, + p7: P7, + p8: P8, + p9: P9, + p10: P10, + p11: P11, + p12: P12, + p13: P13, + p14: P14, + p15: P15, + p16: P16, + p17: P17, + p18: P18, + p19: P19, + p20: P20, + p21: P21, + p22: P22, + p23: P23 + ): R +} diff --git a/src/main/kotlin/com/mingliqiye/utils/functions/Pipeline.kt b/src/main/kotlin/com/mingliqiye/utils/functions/Pipeline.kt new file mode 100644 index 0000000..2b44ca9 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/functions/Pipeline.kt @@ -0,0 +1,272 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Pipeline.kt + * LastUpdate 2026-02-05 15:22:21 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.functions + +import com.mingliqiye.utils.require.Require +import java.util.* + +/** + * 流水线操作类,提供链式调用的操作方式来处理数据转换和操作 + * @param T 泛型类型,表示流水线中处理的数据类型 + */ +class Pipeline(private val value: T) { + + /** + * 对当前值进行转换操作,并返回新的Pipeline实例 + * @param transformer 转换函数,接收当前值并返回转换后的结果 + * @return 包含转换后结果的新Pipeline实例 + */ + fun transform(transformer: P1RFunction): Pipeline = Pipeline(transformer.call(value)) + + /** + * 对当前值进行转换操作,功能与transform相同,提供不同的方法名选择 + * @param transformer 转换函数,接收当前值并返回转换后的结果 + * @return 包含转换后结果的新Pipeline实例 + */ + fun then(transformer: P1RFunction): Pipeline = transform(transformer) + + + /** + * 消费当前值但不改变流水线状态,用于执行副作用操作 + * @param consumer 消费函数,接收当前值进行消费操作 + * @return 当前Pipeline实例,支持链式调用 + */ + fun consume(consumer: P1Function): Pipeline { + consumer.call(value) + return this + } + + /** + * 判断当前值是否为null + * @return true表示当前值为null,false表示不为null + */ + fun isNull(): Boolean = (value == null) + + /** + * 判断当前值是否不为null + * @return true表示当前值不为null,false表示为null + */ + fun isNotNull(): Boolean = (value != null) + + /** + * 根据条件过滤当前值,如果条件满足则保持原值,否则设置为null + * @param predicate 过滤条件函数,接收当前值并返回布尔值 + * @return 包含过滤后结果的Pipeline实例 + */ + fun filter(predicate: P1RFunction): Pipeline = + if (predicate.call(value)) Pipeline(value) else Pipeline(null) + + /** + * 获取当前流水线中的值 + * @return 当前流水线中存储的值 + */ + fun getValue(): T = value + + /** + * 安全地转换当前值,允许转换结果为null + * @param transformer 转换函数,可能返回null + * @return 包含转换后结果(可能为null)的Pipeline实例 + */ + fun safeTransform(transformer: P1RFunction): Pipeline = Pipeline(transformer.call(value)) + + /** + * 将当前值映射为另一个Pipeline实例 + * @param mapper 映射函数,接收当前值并返回Pipeline实例 + * @return 映射后的Pipeline实例 + */ + fun flatMap(mapper: P1RFunction>): Pipeline = mapper.call(value) + + /** + * 将当前值映射为非null结果,如果当前值为null则直接返回null + * @param mapper 映射函数,可能返回null + * @return 包含映射后结果的Pipeline实例 + */ + fun mapNotNull(mapper: P1RFunction): Pipeline = + if (value != null) Pipeline(mapper.call(value)!!) else Pipeline(null) + + + /** + * 将当前值强制转换为指定类型 + * @param type 目标类型Class对象 + * @return 包含转换后类型的Pipeline实例 + * @throws ClassCastException 当类型转换失败时抛出异常 + */ + @Throws(ClassCastException::class) + fun cast(type: Class): Pipeline = Pipeline(value as E) + + /** + * 根据条件判断是否保留当前值,条件满足时保留,否则返回null + * @param predicate 条件判断函数 + * @return 包含条件判断结果的Pipeline实例 + */ + fun takeIf(predicate: P1RFunction): Pipeline = Pipeline(if (predicate.call(value)) value else null) + + /** + * 根据条件判断是否保留当前值,条件不满足时保留,否则返回null + * @param predicate 条件判断函数 + * @return 包含条件判断结果的Pipeline实例 + */ + fun takeUnless(predicate: P1RFunction): Pipeline = + Pipeline(if (!predicate.call(value)) value else null) + + /** + * 在当前值上执行指定操作并返回操作结果 + * @param block 执行函数,接收当前值并返回结果 + * @return 包含执行结果的Pipeline实例 + */ + fun let(block: P1RFunction): Pipeline = Pipeline(block.call(value)) + + /** + * 如果当前值不为null则返回自身,否则返回默认值的Pipeline实例 + * @param defaultValue 默认值 + * @return 当前值或默认值的Pipeline实例 + */ + fun orElse(defaultValue: T): Pipeline = if (value != null) this else Pipeline(defaultValue) + + /** + * 如果当前值不为null则返回自身,否则通过供应商函数获取默认值 + * @param supplier 默认值供应商函数 + * @return 当前值或供应商提供的值的Pipeline实例 + */ + fun orElseGet(supplier: RFunction): Pipeline = if (value != null) this else Pipeline(supplier.call()) + + /** + * 验证当前值是否等于指定值,如果不相等则抛出异常 + * @param any 比较的目标值 + * @param message 错误消息 + * @param exception 异常类型,默认为IllegalArgumentException + * @return 当前Pipeline实例 + */ + fun require( + any: Any, message: String, exception: Class = IllegalArgumentException::class.java + ): Pipeline { + Require.require(Objects.equals(any, value), message, exception) + return this + } + + + /** + * 验证当前值是否等于指定值,如果不相等则抛出IllegalArgumentException异常 + * @param any 比较的目标值 + * @param message 错误消息 + * @return 当前Pipeline实例 + */ + fun require( + any: Any, message: String + ): Pipeline { + Require.RequireLayz.require(any == value, message) + return this + } + + /** + * 使用P1RFunction验证当前值是否满足条件,不满足则抛出异常 + * @param must 验证条件函数 + * @param message 错误消息 + * @param exception 异常类型,默认为IllegalArgumentException + * @return 当前Pipeline实例 + */ + fun require( + must: P1RFunction, + message: String, + exception: Class = IllegalArgumentException::class.java + ): Pipeline { + Require.require(must.call(value), message, exception) + return this + } + + /** + * 使用P1RFunction验证当前值是否满足条件,不满足则抛出IllegalArgumentException异常 + * @param must 验证条件函数 + * @param message 错误消息 + * @return 当前Pipeline实例 + */ + fun require( + must: P1RFunction, message: String + ): Pipeline { + Require.require(must.call(value), message, IllegalArgumentException::class.java) + return this + } + + + /** + * 对当前值执行指定操作但不改变流水线状态 + * @param block 执行函数,接收当前值 + * @return 当前Pipeline实例 + */ + fun also(block: P1Function): Pipeline { + block.call(value) + return this + } + + /** + * 验证当前值是否满足指定条件,不满足则抛出IllegalArgumentException异常 + * @param predicate 验证条件函数 + * @param lazyMessage 延迟错误消息生成函数,默认返回"Requirement failed" + * @return 当前Pipeline实例 + */ + fun require( + predicate: P1RFunction, + lazyMessage: P1RFunction = P1RFunction { "Requirement failed" } + ): Pipeline { + if (!predicate.call(value)) { + throw IllegalArgumentException(lazyMessage.call(value).toString()) + } + return this + } + + /** + * 使用比较器比较当前值与另一个值 + * @param other 另一个比较值 + * @param comparator 比较器 + * @return 比较结果,负数表示小于,0表示相等,正数表示大于 + */ + fun compareWith(other: T, comparator: Comparator): Int = comparator.compare(value, other) + + /** + * 使用选择器将当前值转换为可比较类型后与另一个值比较 + * @param other 另一个比较值 + * @param selector 选择器函数,将当前值转换为可比较类型 + * @return 比较结果 + */ + fun > compareTo(other: R, selector: P1RFunction): Int = + selector.call(value).compareTo(other) + + + companion object { + /** + * 创建包含指定值的Pipeline实例 + * @param value 要包装的值 + * @return 新的Pipeline实例 + */ + @JvmStatic + fun of(value: T): Pipeline = Pipeline(value) + + /** + * 通过供应商函数创建Pipeline实例 + * @param transformer 值供应商函数 + * @return 新的Pipeline实例 + */ + @JvmStatic + fun of(transformer: RFunction): Pipeline = Pipeline(transformer.call()) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/http/Response.kt b/src/main/kotlin/com/mingliqiye/utils/http/Response.kt index 340a20d..1d7c5d0 100644 --- a/src/main/kotlin/com/mingliqiye/utils/http/Response.kt +++ b/src/main/kotlin/com/mingliqiye/utils/http/Response.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,48 +16,260 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Response.kt - * LastUpdate 2025-09-15 09:04:05 + * LastUpdate 2026-02-07 22:18:42 * UpdateUser MingLiPro */ package com.mingliqiye.utils.http +import com.mingliqiye.utils.annotation.DateTimeJsonFormat +import com.mingliqiye.utils.json.converters.DateTimeJsonConverter +import com.mingliqiye.utils.json.converters.base.AnnotationGetter import com.mingliqiye.utils.time.DateTime -import com.mingliqiye.utils.time.Formatter +/** + * HTTP响应数据类 + * 封装了时间、消息、数据和状态码等响应信息 + * + * @param T 响应数据的类型 + * @property time 响应时间 + * @property message 响应消息 + * @property data 响应数据 + * @property statusCode 状态码 + */ data class Response( - val time: String, - var message: String, - var data: T?, - var statusCode: Int + private var time: DateTime, + private var message: String, + private var data: T?, + private var statusCode: Int, ) { + private var timeFormat: DateTimeJsonFormat = DateTimeJsonFormat() companion object { - @JvmStatic - fun ok(data: T): Response { - return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), "操作成功", data, 200) - } + /** + * 创建一个成功的响应对象(仅包含消息) + * + * @param message 响应消息 + * @return Response 成功的响应对象 + */ @JvmStatic - fun ok(message: String): Response { - return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), message, null, 200) - } + fun ok(message: String) = Response( + time = DateTime.now(), + message = message, + data = null, + statusCode = 200 + ) + + /** + * 创建一个成功的响应对象(仅包含数据) + * + * @param T 响应数据的类型 + * @param data 响应数据 + * @return Response 成功的响应对象 + */ + @JvmStatic + fun okData(data: T) = Response( + time = DateTime.now(), + message = "操作成功", + data = data, + statusCode = 200 + ) + + /** + * 创建一个成功的响应对象(包含数据和消息) + * + * @param T 响应数据的类型 + * @param data 响应数据 + * @param message 响应消息 + * @return Response 成功的响应对象 + */ + @JvmStatic + fun okData(data: T, message: String) = Response( + time = DateTime.now(), + message = message, + data = data, + statusCode = 200 + ) + + + /** + * 创建一个指定状态码的响应对象(仅包含状态码) + * + * @param statusCode 状态码 + * @return Response 指定状态码的响应对象 + */ + @JvmStatic + fun code(statusCode: Int) = Response( + time = DateTime.now(), + message = "操作成功", + data = null, + statusCode = statusCode + ) + + /** + * 创建一个指定状态码的响应对象(包含状态码和消息) + * + * @param statusCode 状态码 + * @param message 响应消息 + * @return Response 指定状态码的响应对象 + */ + @JvmStatic + fun code(statusCode: Int, message: String) = Response( + time = DateTime.now(), + message = message, + data = null, + statusCode = statusCode + ) } + /** + * 默认构造函数,创建一个默认的成功响应对象 + */ + constructor() : this( + time = DateTime.now(), message = "操作成功", statusCode = 200, data = null + ) + + + /** + * 获取格式化后的时间字符串。 + * + * @return 格式化后的时间字符串,使用 [DateTimeJsonConverter] 和 [timeFormat] 注解进行转换。 + */ + fun getTime(): String = + DateTimeJsonConverter.getJsonConverter().convert(time, AnnotationGetter.oneGetter(timeFormat))!! + + /** + * 设置时间字段的值。 + * + * @param dateTime 格式化后的时间字符串,将被反序列化为内部时间对象。 + * @return 返回当前对象实例,支持链式调用。 + */ + fun setTime(dateTime: String): Response { + // 使用 DateTimeJsonConverter 将输入的字符串反序列化为时间对象,并更新内部 time 字段 + time = DateTimeJsonConverter.getJsonConverter().deConvert(dateTime, AnnotationGetter.oneGetter(timeFormat))!! + return this + } + + + /** + * 获取响应消息 + * + * @return String 响应消息 + */ + fun getMessage(): String = message + + /** + * 设置响应消息 + * + * @param message 响应消息 + * @return Response 当前响应对象(用于链式调用) + */ fun setMessage(message: String): Response { this.message = message return this } - fun setData(data: T): Response { - this.data = data - return ok(this.data) - .setMessage(this.message) - .setStatusCode(this.statusCode) + /** + * 获取响应数据 + * + * @return T? 响应数据,可能为空 + */ + fun getData(): T? = data + + /** + * 获取非空数据对象 + * + * 此方法强制解包data属性,如果data为null则会抛出NullPointerException异常 + * + * @param T 泛型类型参数,表示返回的数据类型 + * @return 返回非空的数据对象,类型为T + * @throws NullPointerException 当data属性为null时抛出此异常 + */ + @Throws(NullPointerException::class) + fun notNullData(): T { + return data ?: throw NullPointerException("at Response.notNullData() because data is null") } + + /** + * 设置响应数据 + * + * @param D 数据类型 + * @param data 响应数据 + * @return Response 当前响应对象(用于链式调用) + * + */ + fun setData(data: T): Response { + this.data = data + return this + } + + /** + * 创建一个新的Response对象,使用指定的时间 + * + * @param time 新的响应时间 + * @return Response 新的响应对象 + */ + fun withTime(time: DateTime): Response = + if (this.time == time) this else Response(time, message, data, statusCode) + + /** + * 创建一个新的Response对象,使用指定的数据 + * + * @param D 新的数据类型 + * @param data 新的响应数据 + * @return Response 新的响应对象 + */ + fun withData(data: D): Response = + Response(this.time, this.message, data, this.statusCode) + + /** + * 创建一个新的Response对象,使用指定的消息 + * + * @param message 新的响应消息 + * @return Response 新的响应对象 + */ + fun withMessage(message: String): Response = + if (this.message == message) this else Response(time, message, data, statusCode) + + /** + * 创建一个新的Response对象,使用指定的状态码 + * + * @param statusCode 新的状态码 + * @return Response 新的响应对象 + */ + fun withStatusCode(statusCode: Int): Response = + if (this.statusCode == statusCode) this else Response(time, message, data, statusCode) + + /** + * 获取状态码 + * + * @return Int 状态码 + */ + fun getStatusCode(): Int = statusCode + + /** + * 设置状态码 + * + * @param statusCode 状态码 + * @return Response 当前响应对象(用于链式调用) + */ fun setStatusCode(statusCode: Int): Response { this.statusCode = statusCode return this } + + fun writeTimeFormat(timeFormat: DateTimeJsonFormat): Response { + this.timeFormat = timeFormat + return this + } + + fun readTimeFormat(): DateTimeJsonFormat = timeFormat + + /** + * 返回响应对象的字符串表示 + */ + override fun toString(): String = + "Response(time=${getTime()}, message=${getMessage()}, data:[${data?.javaClass?.simpleName}]=${getData()}, statusCode=${getStatusCode()})" } diff --git a/src/main/kotlin/com/mingliqiye/utils/i18n/I18N.kt b/src/main/kotlin/com/mingliqiye/utils/i18n/I18N.kt new file mode 100644 index 0000000..84d8ded --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/i18n/I18N.kt @@ -0,0 +1,964 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile I18N.kt + * LastUpdate 2026-02-05 22:39:07 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.i18n + +import com.fasterxml.jackson.databind.ObjectMapper +import org.slf4j.Logger + + +object I18N { + + @JvmStatic + private var _Internationalization: Internationalization = Internationalization( + clazz = I18N::class.java, + objectMapper = ObjectMapper(), + isloadSlef = true + ) + + fun setInternationalization(value: Internationalization) { + this._Internationalization = value + } + + fun getInternationalization() = _Internationalization + + @JvmStatic + fun getString(string: String, vararg any: Any): String = _Internationalization.getString(string, *any) + + @JvmStatic + fun getString(string: String): String = _Internationalization.getString(string) + + @JvmStatic + fun getKeyString(key: String): String = _Internationalization.getKeyString(key) + + + fun Logger.infoTranslater(string: String, vararg any: Any) = this.info(getString(string, *any)) + fun Logger.warnTranslater(string: String, vararg any: Any) = this.warn(getString(string, *any)) + fun Logger.debugTranslater(string: String, vararg any: Any) = this.debug(getString(string, *any)) + fun Logger.traceTranslater(string: String, vararg any: Any) = this.trace(getString(string, *any)) + + // 0 个参数 + fun Logger.errorTranslater(string: String, any1: Any) { + this.error(getString(string)) + } + + fun Logger.errorTranslater(string: String) { + this.error(getString(string)) + } + + // 2 个参数 + fun Logger.errorTranslater(string: String, any1: Any, any2: Any) { + this.error(getString(string, any1, any2)) + } + + // 3 个参数 + fun Logger.errorTranslater(string: String, any1: Any, any2: Any, any3: Any) { + this.error(getString(string, any1, any2, any3)) + } + + // 4 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4)) + } + + // 5 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5)) + } + + // 6 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6)) + } + + // 7 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7)) + } + + // 8 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8)) + } + + // 9 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9)) + } + + // 10 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10)) + } + + // 11 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, + any6: Any, any7: Any, any8: Any, any9: Any, any10: Any, any11: Any, + + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11)) + } + + // 12 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, + any6: Any, any7: Any, any8: Any, any9: Any, any10: Any, any11: Any, any12: Any, + + ) { + this.error( + getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12) + ) + } + + // 13 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, + any6: Any, any7: Any, any8: Any, any9: Any, any10: Any, any11: Any, any12: Any, any13: Any, + + ) { + this.error( + getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13), + + ) + } + + // 14 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, + any6: Any, any7: Any, any8: Any, any9: Any, any10: Any, any11: Any, any12: Any, any13: Any, any14: Any, + + ) { + this.error( + getString( + string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13, any14 + ) + ) + } + + // 15 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + + ) { + this.error( + getString( + string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13, any14, any15 + ) + ) + } + + // 16 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16 + ) + ) + } + + // 17 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17 + ) + ) + } + + // 18 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18 + ) + ) + } + + // 19 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + any19: Any, + + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18, + any19 + ) + ) + } + + // 20 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + any19: Any, + any20: Any, + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18, + any19, + any20 + ) + ) + } + + + fun Logger.errorTranslater(string: String, throwable: Throwable) { + this.error(getString(string), throwable) + } + + // 1 个参数 + fun Logger.errorTranslater(string: String, any1: Any, throwable: Throwable) { + this.error(getString(string, any1), throwable) + } + + // 2 个参数 + fun Logger.errorTranslater(string: String, any1: Any, any2: Any, throwable: Throwable) { + this.error(getString(string, any1, any2), throwable) + } + + // 3 个参数 + fun Logger.errorTranslater(string: String, any1: Any, any2: Any, any3: Any, throwable: Throwable) { + this.error(getString(string, any1, any2, any3), throwable) + } + + // 4 个参数 + fun Logger.errorTranslater( + string: String, any1: Any, any2: Any, any3: Any, any4: Any, throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4), throwable) + } + + // 5 个参数 + fun Logger.errorTranslater( + string: String, any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5), throwable) + } + + // 6 个参数 + fun Logger.errorTranslater( + string: String, any1: Any, any2: Any, any3: Any, any4: Any, any5: Any, any6: Any, throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6), throwable) + } + + // 7 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7), throwable) + } + + // 8 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8), throwable) + } + + // 9 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9), throwable) + } + + // 10 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10), throwable) + } + + // 11 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + throwable: Throwable + ) { + this.error(getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11), throwable) + } + + // 12 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + throwable: Throwable + ) { + this.error( + getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12), throwable + ) + } + + // 13 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + throwable: Throwable + ) { + this.error( + getString(string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13), + throwable + ) + } + + // 14 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + throwable: Throwable + ) { + this.error( + getString( + string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13, any14 + ), throwable + ) + } + + // 15 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + throwable: Throwable + ) { + this.error( + getString( + string, any1, any2, any3, any4, any5, any6, any7, any8, any9, any10, any11, any12, any13, any14, any15 + ), throwable + ) + } + + // 16 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + throwable: Throwable + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16 + ), throwable + ) + } + + // 17 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + throwable: Throwable + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17 + ), throwable + ) + } + + // 18 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + throwable: Throwable + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18 + ), throwable + ) + } + + // 19 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + any19: Any, + throwable: Throwable + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18, + any19 + ), throwable + ) + } + + // 20 个参数 + fun Logger.errorTranslater( + string: String, + any1: Any, + any2: Any, + any3: Any, + any4: Any, + any5: Any, + any6: Any, + any7: Any, + any8: Any, + any9: Any, + any10: Any, + any11: Any, + any12: Any, + any13: Any, + any14: Any, + any15: Any, + any16: Any, + any17: Any, + any18: Any, + any19: Any, + any20: Any, + throwable: Throwable + ) { + this.error( + getString( + string, + any1, + any2, + any3, + any4, + any5, + any6, + any7, + any8, + any9, + any10, + any11, + any12, + any13, + any14, + any15, + any16, + any17, + any18, + any19, + any20 + ), throwable + ) + } + + +} diff --git a/src/main/kotlin/com/mingliqiye/utils/i18n/Internationalization.kt b/src/main/kotlin/com/mingliqiye/utils/i18n/Internationalization.kt new file mode 100644 index 0000000..dc1446b --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/i18n/Internationalization.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Internationalization.kt + * LastUpdate 2026-02-06 08:47:26 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.i18n + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import org.slf4j.Logger +import java.net.URL +import java.util.* + +class Internationalization { + var clazz: Class<*> + var objectMapper: ObjectMapper + var locale: Locale + var backLocale: Locale + val langPath: String + val thisName: String + val thisBackName: String + private var log: Logger = MingLiLoggerFactory.getLogger() + + + constructor( + clazz: Class<*>, + objectMapper: ObjectMapper, + locale: Locale = Locale.getDefault(), + backLocale: Locale = Locale.US, + langPath: String = "/lang", + isloadSlef: Boolean = false + ) { + this.clazz = clazz + this.objectMapper = objectMapper + this.locale = locale + this.backLocale = backLocale + this.langPath = langPath + thisName = getLanguageName(locale) + thisBackName = getLanguageName(backLocale) + readJson("/assets/mingli-utils/lang/${thisName}.json", Internationalization::class.java, thisName) + if (!isloadSlef) { + if (!readJson(fileName = "$langPath/${thisName}.json", lang = thisName)) { + log.warn(getString("com.mingliqiye.utils.i18n.readjson.error", "$langPath/${thisName}.json")) + } + } + if (thisName != thisBackName) { + readJson("/assets/mingli-utils/lang/${thisBackName}.json", Internationalization::class.java, thisBackName) + if (!isloadSlef) { + if (!readJson(fileName = "$langPath/${thisBackName}.json", lang = thisBackName)) { + log.warn(getString("com.mingliqiye.utils.i18n.readjson.error", "$langPath/${thisBackName}.json")) + } + } + } + } + + fun getString(string: String, vararg any: Any): String { + return getString(string).format(*any) + } + + fun getString(string: String): String { + return getKeyString(string) + } + + fun getKeyString(key: String): String { + val s = localesData[thisName]?.get(key) ?: localesData[thisBackName]?.get(key) + if (s == null) { + return key + } + return s + } + + fun getLanguageName(locale: Locale): String = + if (locale.country == null || locale.language == null) locale.country + locale.language else locale.language + '_' + locale.country + + constructor( + clazz: Class<*>, + objectMapper: ObjectMapper, + ) : this( + locale = Locale.getDefault(), clazz = clazz, objectMapper = objectMapper + ) + + constructor( + clazz: Class<*>, objectMapper: ObjectMapper, langPath: String = "/lang" + ) : this( + locale = Locale.getDefault(), clazz = clazz, langPath = langPath, objectMapper = objectMapper + ) + + val localesData: MutableMap> = mutableMapOf() + + fun getlangFile( + clazzd: Class<*>, fileName: String + ): URL? { + return clazzd.getResource(fileName) + } + + fun readJson( + fileName: String, clazzd: Class<*> = clazz, lang: String + ): Boolean { + val byteArray: ByteArray? = getlangFile(clazzd, fileName)?.openStream()?.use { it.readBytes() } + if (byteArray == null) return false + val node: JsonNode = objectMapper.readTree(byteArray) + if (node.isArray) return false + if (node.isEmpty) return false + var m = localesData[lang] + if (m == null) { + m = mutableMapOf() + localesData[lang] = m + } + readJsonNode(node, "", m) + return true + } + + fun readJsonNode(node: JsonNode, path: String, map: MutableMap) { + val fields = node.properties().iterator() + while (fields.hasNext()) { + val (k, v) = fields.next() + val pathName = if (path.isEmpty()) path + k else "$path.$k" + if (v.isTextual) { + map[pathName] = v.asText() + } else if (v.isObject) { + readJsonNode(v, pathName, map) + } + } + } + +} diff --git a/src/main/kotlin/com/mingliqiye/utils/io/IO.kt b/src/main/kotlin/com/mingliqiye/utils/io/IO.kt index e288ee3..8165627 100644 --- a/src/main/kotlin/com/mingliqiye/utils/io/IO.kt +++ b/src/main/kotlin/com/mingliqiye/utils/io/IO.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,48 +16,224 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile IO.kt - * LastUpdate 2025-09-20 16:03:14 + * LastUpdate 2026-02-06 13:21:33 * UpdateUser MingLiPro */ package com.mingliqiye.utils.io - -fun Any?.println() { - IO.println(this) -} +import com.mingliqiye.utils.array.toHexString +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import com.mingliqiye.utils.string.join +import org.slf4j.Logger +import java.io.OutputStream +import java.io.PrintStream -class IO { - companion object { +/** + * IO工具类,提供打印功能和系统输出流重定向到日志的功能 + */ +object IO { - @JvmStatic - fun print(vararg args: Any?) { - printA(" ", *args) - } + @JvmStatic + fun ByteArray.println(): ByteArray { + this.toHexString().chunked(2).println() + return this + } - @JvmStatic - fun println(vararg args: Any?) { - printlnA(" ", *args) - } + @JvmStatic + fun List.println(): List { + println("{" + ",".join(this) + "}") + return this + } - @JvmStatic - fun printlnA(sp: String, vararg args: Any?) { - printA(" ", *args) + @JvmStatic + fun Array.println(): Array { + println("{" + ",".join(this) + "}") + return this + } + + @JvmStatic + fun T.println(): T { + println(this) + return this + } + + @JvmStatic + var originalOut: PrintStream = System.out + + @JvmStatic + var originalErr: PrintStream = System.err + + + @JvmStatic + val outLog: Logger = MingLiLoggerFactory.getLogger("out") + + @JvmStatic + val errLog: Logger = MingLiLoggerFactory.getLogger("err") + + /** + * 打印多个参数,使用空格分隔 + * @param args 要打印的参数数组 + */ + @JvmStatic + fun print(vararg args: Any?) { + printA(" ", *args) + } + + /** + * 打印多个参数并换行,使用空格分隔 + * @param args 要打印的参数数组 + */ + @JvmStatic + fun println(vararg args: Any?) { + printlnA(" ", *args) + } + + /** + * 打印多个参数并换行,指定分隔符 + * @param sp 分隔符 + * @param args 要打印的参数数组 + */ + @JvmStatic + fun printlnA(sp: String, vararg args: Any?) { + printA(" ", *args) + kotlin.io.println() + } + + /** + * 打印多个参数,指定分隔符 + * @param sp 分隔符,默认为空字符串 + * @param args 要打印的参数数组 + */ + @JvmStatic + fun printA(sp: String = "", vararg args: Any?) { + if (args.isEmpty()) { kotlin.io.println() } - - @JvmStatic - fun printA(sp: String = "", vararg args: Any?) { - if (args.isEmpty()) { - kotlin.io.println() - } - val sb = StringBuilder() - for (i in args.indices) { - sb.append(args[i]) - if (i < args.size - 1) sb.append(sp) - } - kotlin.io.print(sb) + val sb = StringBuilder() + for (i in args.indices) { + sb.append(args[i]) + if (i < args.size - 1) sb.append(sp) } + kotlin.io.print(sb) + } + + @JvmStatic + /** + * 重定向 System.out 到 INFO 级别日志 + */ + fun redirectOutToInfo() { + val outLogger = PrintStream(object : OutputStream() { + private val buffer = StringBuilder() + + override fun write(b: Int) { + if (b == '\n'.code) { + flushBuffer() + } else { + buffer.append(b.toChar()) + } + } + + override fun write(b: ByteArray, off: Int, len: Int) { + val str = String(b, off, len) + if (str.contains("\n")) { + val lines = str.split("\n") + lines.forEachIndexed { index, line -> + if (index == lines.size - 1 && !str.endsWith("\n")) { + buffer.append(line) + } else { + buffer.append(line) + flushBuffer() + } + } + } else { + buffer.append(str) + } + } + + private fun flushBuffer() { + val message = buffer.toString().trim() + if (message.isNotBlank()) { + outLog.info(message) + } + buffer.clear() + } + + override fun flush() { + flushBuffer() + super.flush() + } + }, true) + + System.setOut(outLogger) + } + + @JvmStatic + /** + * 重定向 System.err 到 ERROR 级别 + */ + fun redirectErrToError() { + val errLogger = PrintStream(object : OutputStream() { + private val buffer = StringBuilder() + + override fun write(b: Int) { + if (b == '\n'.code) { + flushBuffer() + } else { + buffer.append(b.toChar()) + } + } + + override fun write(b: ByteArray, off: Int, len: Int) { + val str = String(b, off, len) + if (str.contains("\n")) { + val lines = str.split("\n") + lines.forEachIndexed { index, line -> + if (index == lines.size - 1 && !str.endsWith("\n")) { + buffer.append(line) + } else { + buffer.append(line) + flushBuffer() + } + } + } else { + buffer.append(str) + } + } + + private fun flushBuffer() { + val message = buffer.toString().trim() + if (message.isNotBlank()) { + errLog.error(message) + } + buffer.clear() + } + + override fun flush() { + flushBuffer() + super.flush() + } + }, true) + + System.setErr(errLogger) + } + + @JvmStatic + /** + * 完全重定向(包括第三方库的输出) + */ + fun redirectAll() { + redirectOutToInfo() + redirectErrToError() + } + + @JvmStatic + /** + * 恢复原始输出流 + */ + fun restore() { + System.setOut(originalOut) + System.setErr(originalErr) } } diff --git a/src/main/kotlin/com/mingliqiye/utils/json/GsonJsonApi.kt b/src/main/kotlin/com/mingliqiye/utils/json/GsonJsonApi.kt deleted file mode 100644 index 934fb76..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/json/GsonJsonApi.kt +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile GsonJsonApi.kt - * LastUpdate 2025-09-15 22:07:43 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.json - -import com.google.gson.* -import com.mingliqiye.utils.json.converters.JsonConverter -import com.mingliqiye.utils.json.converters.JsonStringConverter - -class GsonJsonApi : JsonApi { - - private var gsonUnicode: Gson - private var gsonPretty: Gson - private var gsonPrettyUnicode: Gson - private var gson: Gson - - constructor() { - gson = GsonBuilder() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - - gsonUnicode = GsonBuilder() - .disableHtmlEscaping() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - - gsonPretty = GsonBuilder() - .setPrettyPrinting() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - - gsonPrettyUnicode = GsonBuilder() - .setPrettyPrinting() - .disableHtmlEscaping() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - } - - constructor(gson: Gson) { - this.gson = gson - .newBuilder() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - this.gsonUnicode = gson - .newBuilder() - .disableHtmlEscaping() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - this.gsonPretty = gson - .newBuilder() - .setPrettyPrinting() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - this.gsonPrettyUnicode = gson - .newBuilder() - .setPrettyPrinting() - .disableHtmlEscaping() - .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) - .create() - } - - override fun parse(json: String, clazz: Class): T { - return gson.fromJson(json, clazz) - } - - override fun parse(json: String, type: JsonTypeReference): T { - return gson.fromJson(json, type.type) - } - - override fun format(obj: Any): String { - return gson.toJson(obj) - } - - override fun formatUnicode(obj: Any): String { - return gsonUnicode.toJson(obj) - } - - override fun formatPretty(obj: Any): String { - return gsonPretty.toJson(obj) - } - - override fun formatPrettyUnicode(obj: Any): String { - return gsonPrettyUnicode.toJson(obj) - } - - override fun isValidJson(json: String): Boolean { - return try { - JsonParser.parseString(json) - true - } catch (e: JsonSyntaxException) { - false - } catch (e: Exception) { - false - } - } - - override fun merge(vararg jsons: String): String { - val merged = JsonObject() - for (json in jsons) { - if (json.isNullOrEmpty()) { - continue - } - try { - val obj = JsonParser.parseString(json).asJsonObject - for (key in obj.keySet()) { - merged.add(key, obj.get(key)) - } - } catch (e: Exception) { - // 忽略无效的 JSON 字符串 - } - } - return gson.toJson(merged) - } - - override fun getNodeValue(json: String, path: String): String? { - return try { - var element = JsonParser.parseString(json) - val paths = path.split("\\.".toRegex()).toTypedArray() - var current = element - - for (p in paths) { - if (current.isJsonObject) { - current = current.asJsonObject.get(p) - } else { - return null - } - - if (current == null) { - return null - } - } - - if (current.isJsonPrimitive) current.asString else current.toString() - } catch (e: Exception) { - null - } - } - - override fun updateNodeValue(json: String, path: String, newValue: Any): String { - return try { - val obj = JsonParser.parseString(json).asJsonObject - val paths = path.split("\\.".toRegex()).toTypedArray() - var current = obj - - // 导航到倒数第二层 - for (i in 0 until paths.size - 1) { - val p = paths[i] - if (!current.has(p) || !current.get(p).isJsonObject) { - current.add(p, JsonObject()) - } - current = current.getAsJsonObject(p) - } - - // 设置最后一层的值 - val lastPath = paths[paths.size - 1] - val element = gson.toJsonTree(newValue) - current.add(lastPath, element) - - gson.toJson(obj) - } catch (e: Exception) { - json - } - } - - override fun convert(source: T, destinationClass: Class): D { - val json = gson.toJson(source) - return gson.fromJson(json, destinationClass) - } - - override fun convert(source: T, destinationType: JsonTypeReference): D { - val json = gson.toJson(source) - return gson.fromJson(json, destinationType.type) - } - - override fun addJsonConverter(c: JsonConverter<*, *>) { - c.getStringConverter()?.let { - gson = gson - .newBuilder() - .registerTypeAdapter( - it.tClass, - it.gsonJsonStringConverterAdapter - ) - .create() - gsonUnicode = gsonUnicode - .newBuilder() - .registerTypeAdapter( - it.tClass, - it.gsonJsonStringConverterAdapter - ) - .create() - gsonPretty = gsonPretty - .newBuilder() - .registerTypeAdapter( - it.tClass, - it.gsonJsonStringConverterAdapter - ) - .create() - gsonPrettyUnicode = gsonPrettyUnicode - .newBuilder() - .registerTypeAdapter( - it.tClass, - it.gsonJsonStringConverterAdapter - ) - .create() - } - - } - - override fun addJsonStringConverter(c: JsonStringConverter<*>) { - addJsonConverter(c) - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/api/JSONA.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/JSONA.kt new file mode 100644 index 0000000..e4e731f --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/JSONA.kt @@ -0,0 +1,644 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JSONA.kt + * LastUpdate 2026-02-05 10:34:30 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.api + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.kotlinModule +import com.mingliqiye.utils.json.api.base.JsonApi +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import com.mingliqiye.utils.json.api.type.listType +import com.mingliqiye.utils.json.converters.base.BaseJsonConverter +import java.io.File +import java.io.InputStream +import java.io.OutputStream +import java.nio.file.Path + +/** + * JSON工具类,提供静态方法访问JSON API功能 + */ +object JSONA { + @JvmStatic + private var jsonApi: JsonApi? = null + + /** + * 获取JSON API实例 + * + * @return JSON API实例 + * @throws NullPointerException 当JSON API未初始化时抛出异常 + */ + @Throws(NullPointerException::class) + @JvmStatic + fun getJsonApi(): JsonApi { + if (jsonApi == null) { + throw NullPointerException("jsonApi is null plase setJsonApi first") + } + return jsonApi!! + } + + /** + * 设置JSON API实例 + * + * @param jsa JSON API实例 + */ + @JvmStatic + fun setJsonApi(jsa: JsonApi) { + jsonApi = jsa + } + + /** + * 使用反射创建并设置指定类型的JSON API实例 + * + * @param T 继承自JsonApi的具体实现类 + */ + inline fun setJsonApi() { + setJsonApi(T::class.java.newInstance() as JsonApi) + } + + /** + * 将JSON字符串解析为指定类型的对象 + * + * @param json 待解析的JSON字符串 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parse(json: String, clazz: Class): T = getJsonApi().parse(json, clazz) + + /** + * 将JSON字符串解析为指定泛型类型对象 + * + * @param json 待解析的JSON字符串 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + inline fun parse(json: String): T { + return getJsonApi().parse(json, (object : JsonTypeReference() {})) + } + + /** + * 将字节数组形式的JSON解析为指定泛型类型对象 + * + * @param json 待解析的JSON字节数组 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + inline fun parse(json: ByteArray): T = getJsonApi().parse(json, object : JsonTypeReference() {}) + + /** + * 将JSON字符串解析为指定泛型类型对象 + * + * @param json 待解析的JSON字符串 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parse(json: String, type: JsonTypeReference): T = getJsonApi().parse(json, type) + + /** + * 将对象格式化为JSON字符串 + * + * @param obj 待格式化的对象 + * @return 格式化后的JSON字符串 + */ + @JvmStatic + fun format(obj: Any): String = getJsonApi().format(obj) + + /** + * 将对象格式化为带Unicode转义的JSON字符串 + * + * @param obj 待格式化的对象 + * @return 格式化后的带Unicode转义的JSON字符串 + */ + @JvmStatic + fun formatUnicode(obj: Any): String = getJsonApi().formatPrettyUnicode(obj) + + /** + * 从文件路径解析JSON为指定类型的对象 + * + * @param path 文件路径 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(path: String, clazz: Class): T = getJsonApi().parseFrom(path, clazz) + + /** + * 从Path对象解析JSON为指定类型的对象 + * + * @param path Path对象 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(path: Path, clazz: Class): T = getJsonApi().parseFrom(path, clazz) + + /** + * 从File对象解析JSON为指定类型的对象 + * + * @param file File对象 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(file: File, clazz: Class): T = getJsonApi().parseFrom(file, clazz) + + /** + * 从InputStream解析JSON为指定类型的对象 + * + * @param inputStream InputStream对象 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(inputStream: InputStream, clazz: Class): T = getJsonApi().parseFrom(inputStream, clazz) + + /** + * 从文件路径解析JSON为指定泛型类型对象 + * + * @param path 文件路径 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(path: String, type: JsonTypeReference): T = getJsonApi().parseFrom(path, type) + + /** + * 从Path对象解析JSON为指定泛型类型对象 + * + * @param path Path对象 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(path: Path, type: JsonTypeReference): T = getJsonApi().parseFrom(path, type) + + /** + * 从File对象解析JSON为指定泛型类型对象 + * + * @param file File对象 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(file: File, type: JsonTypeReference): T = getJsonApi().parseFrom(file, type) + + /** + * 从InputStream解析JSON为指定泛型类型对象 + * + * @param inputStream InputStream对象 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parseFrom(inputStream: InputStream, type: JsonTypeReference): T = + getJsonApi().parseFrom(inputStream, type) + + /** + * 将字节数组形式的JSON解析为指定类型的对象 + * + * @param json 待解析的JSON字节数组 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parse(json: ByteArray, clazz: Class): T = getJsonApi().parse(json, clazz) + + /** + * 将字节数组形式的JSON解析为指定泛型类型对象 + * + * @param json 待解析的JSON字节数组 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + @JvmStatic + fun parse(json: ByteArray, type: JsonTypeReference): T = getJsonApi().parse(json, type) + + /** + * 将JSON字符串解析为指定类型的对象,解析失败时返回默认值 + * + * @param json 待解析的JSON字符串 + * @param clazz 目标对象的Class类型 + * @param defaultValue 解析失败时返回的默认值 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例或默认值 + */ + @JvmStatic + fun parse(json: String, clazz: Class, defaultValue: T): T = getJsonApi().parse(json, clazz, defaultValue) + + /** + * 将JSON字符串解析为指定泛型类型对象,解析失败时返回默认值 + * + * @param json 待解析的JSON字符串 + * @param type 目标对象的Type类型(支持泛型) + * @param defaultValue 解析失败时返回的默认值 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例或默认值 + */ + @JvmStatic + fun parse( + json: String, type: JsonTypeReference, defaultValue: T + ): T = getJsonApi().parse(json, type, defaultValue) + + /** + * 将对象格式化为美化格式的JSON字符串(带缩进和换行) + * + * @param obj 待格式化的对象 + * @return 格式化后的美化JSON字符串 + */ + @JvmStatic + fun formatPretty(obj: Any): String = getJsonApi().formatPretty(obj) + + /** + * 将对象格式化为美化格式的JSON字节数组 + * + * @param obj 待格式化的对象 + * @return 格式化后的美化JSON字节数组 + */ + @JvmStatic + fun formatPrettyBytes(obj: Any): ByteArray = getJsonApi().formatPrettyBytes(obj) + + /** + * 将对象格式化为带Unicode转义的美化JSON字符串 + * + * @param obj 待格式化的对象 + * @return 格式化后的带Unicode转义的美化JSON字符串 + */ + @JvmStatic + fun formatPrettyUnicode(obj: Any): String = getJsonApi().formatPrettyUnicode(obj) + + /** + * 将对象格式化为带Unicode转义的美化JSON字节数组 + * + * @param obj 待格式化的对象 + * @return 格式化后的带Unicode转义的美化JSON字节数组 + */ + @JvmStatic + fun formatPrettyUnicodeBytes(obj: Any): ByteArray = getJsonApi().formatPrettyUnicodeBytes(obj) + + /** + * 将对象格式化为美化格式的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file 文件路径 + */ + @JvmStatic + fun formatPretty(obj: Any, file: String) = getJsonApi().formatPretty(obj, file) + + /** + * 将对象格式化为美化格式的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file Path对象 + */ + @JvmStatic + fun formatPretty(obj: Any, file: Path) = getJsonApi().formatPretty(obj, file) + + /** + * 将对象格式化为美化格式的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file File对象 + */ + @JvmStatic + fun formatPretty(obj: Any, file: File) = getJsonApi().formatPretty(obj, file) + + /** + * 将对象格式化为美化格式的JSON字符串并写入输出流 + * + * @param obj 待格式化的对象 + * @param stream OutputStream对象 + */ + @JvmStatic + fun formatPretty(obj: Any, stream: OutputStream) = getJsonApi().formatPretty(obj, stream) + + /** + * 将对象格式化为带Unicode转义的美化JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file 文件路径 + */ + @JvmStatic + fun formatPrettyUnicode(obj: Any, file: String) = getJsonApi().formatPrettyUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的美化JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file Path对象 + */ + @JvmStatic + fun formatPrettyUnicode(obj: Any, file: Path) = getJsonApi().formatPrettyUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的美化JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file File对象 + */ + @JvmStatic + fun formatPrettyUnicode(obj: Any, file: File) = getJsonApi().formatPrettyUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的美化JSON字符串并写入输出流 + * + * @param obj 待格式化的对象 + * @param stream OutputStream对象 + */ + @JvmStatic + fun formatPrettyUnicode(obj: Any, stream: OutputStream) = getJsonApi().formatPrettyUnicode(obj, stream) + + /** + * 将对象格式化为JSON字节数组 + * + * @param obj 待格式化的对象 + * @return 格式化后的JSON字节数组 + */ + @JvmStatic + fun formatBytes(obj: Any): ByteArray = getJsonApi().formatBytes(obj) + + /** + * 将对象格式化为带Unicode转义的JSON字节数组 + * + * @param obj 待格式化的对象 + * @return 格式化后的带Unicode转义的JSON字节数组 + */ + @JvmStatic + fun formatUnicodeBytes(obj: Any): ByteArray = getJsonApi().formatUnicodeBytes(obj) + + /** + * 将对象格式化为JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file 文件路径 + */ + @JvmStatic + fun format(obj: Any, file: String) = getJsonApi().format(obj, file) + + /** + * 将对象格式化为JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file Path对象 + */ + @JvmStatic + fun format(obj: Any, file: Path) = getJsonApi().format(obj, file) + + /** + * 将对象格式化为JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file File对象 + */ + @JvmStatic + fun format(obj: Any, file: File) = getJsonApi().format(obj, file) + + /** + * 将对象格式化为JSON字符串并写入输出流 + * + * @param obj 待格式化的对象 + * @param stream OutputStream对象 + */ + @JvmStatic + fun format(obj: Any, stream: OutputStream) = getJsonApi().format(obj, stream) + + /** + * 将对象格式化为带Unicode转义的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file 文件路径 + */ + @JvmStatic + fun formatUnicode(obj: Any, file: String) = getJsonApi().formatUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file Path对象 + */ + @JvmStatic + fun formatUnicode(obj: Any, file: Path) = getJsonApi().formatUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的JSON字符串并写入文件 + * + * @param obj 待格式化的对象 + * @param file File对象 + */ + @JvmStatic + fun formatUnicode(obj: Any, file: File) = getJsonApi().formatUnicode(obj, file) + + /** + * 将对象格式化为带Unicode转义的JSON字符串并写入输出流 + * + * @param obj 待格式化的对象 + * @param stream OutputStream对象 + */ + @JvmStatic + fun formatUnicode(obj: Any, stream: OutputStream) = getJsonApi().formatUnicode(obj, stream) + + /** + * 将JSON字符串解析为指定元素类型的List集合 + * + * @param json 待解析的JSON字符串 + * @param elementType List中元素的类型 + * @param 泛型参数,表示List中元素的类型 + * @return 解析后的List集合 + */ + @JvmStatic + fun parseList(json: String, elementType: Class): List = parse(json, listType(elementType)) + + /** + * 将JSON字符串解析为指定元素类型的List集合 + * + * @param json 待解析的JSON字符串 + * @param 泛型参数,表示List中元素的类型 + * @return 解析后的List集合 + */ + @JvmStatic + inline fun parseList(json: String): List = parse(json, listType(T::class.java)) + + /** + * 将JSON字符串解析为指定键值类型的Map集合 + * + * @param json 待解析的JSON字符串 + * @param keyType Map中键的类型 + * @param valueType Map中值的类型 + * @param 泛型参数,表示Map中键的类型 + * @param 泛型参数,表示Map中值的类型 + * @return 解析后的Map集合 + */ + @JvmStatic + fun parseMap( + json: String, keyType: Class, valueType: Class + ): MutableMap = getJsonApi().parseMap(json, keyType, valueType) + + /** + * 将JSON字符串解析为指定键值类型的Map集合 + * + * @param json 待解析的JSON字符串 + * @param 泛型参数,表示Map中键的类型 + * @param 泛型参数,表示Map中值的类型 + * @return 解析后的Map集合 + */ + @JvmStatic + inline fun parseMap( + json: String + ): MutableMap = getJsonApi().parseMap(json, K::class.java, V::class.java) + + /** + * 验证字符串是否为有效的JSON格式 + * + * @param json 待验证的字符串 + * @return 如果是有效的JSON格式返回true,否则返回false + */ + @JvmStatic + fun isValidJson(json: String): Boolean = getJsonApi().isValidJson(json) + + /** + * 将对象转换为JSON字节数组 + * + * @param object 待转换的对象 + * @return 转换后的JSON字节数组 + */ + @JvmStatic + fun toBytes(obj: Any): ByteArray = getJsonApi().toBytes(obj) + + /** + * 将对象转换为美化格式的JSON字节数组 + * + * @param object 待转换的对象 + * @return 转换后的美化格式JSON字节数组 + */ + @JvmStatic + fun toBytesPretty(obj: Any): ByteArray = getJsonApi().toBytesPretty(obj) + + /** + * 合并多个JSON字符串为一个JSON对象 + * + * @param jsons 待合并的JSON字符串数组 + * @return 合并后的JSON字符串 + */ + @JvmStatic + fun merge(vararg jsons: String): String = getJsonApi().merge(*jsons) + + /** + * 获取JSON字符串中指定路径节点的值 + * + * @param json JSON字符串 + * @param path 节点路径(如:"user.name") + * @return 节点值的字符串表示 + */ + @JvmStatic + fun getNodeValue(json: String, path: String): String? = getJsonApi().getNodeValue(json, path) + + /** + * 更新JSON字符串中指定路径节点的值 + * + * @param json 原始JSON字符串 + * @param path 节点路径(如:"user.name") + * @param newValue 新的节点值 + * @return 更新后的JSON字符串 + */ + @JvmStatic + fun updateNodeValue(json: String, path: String, newValue: Any): String = + getJsonApi().updateNodeValue(json, path, newValue) + + /** + * 将源对象转换为目标类型的对象 + * + * @param T 源对象的类型 + * @param D 目标对象的类型 + * @param source 需要转换的源对象 + * @param destinationClass 目标对象的Class类型 + * @return 转换后的目标类型对象 + */ + @JvmStatic + fun convert(source: Any, destinationClass: Class): D = getJsonApi().convert(source, destinationClass) + + /** + * 使用内联函数和reified类型参数将源对象转换为目标类型的对象 + * + * @param T 源对象的类型 + * @param D 目标对象的类型(通过reified类型参数推断) + * @param source 需要转换的源对象 + * @return 转换后的目标类型对象 + */ + @JvmStatic + inline fun convert(source: Any): D = getJsonApi().convert(source, object : JsonTypeReference() {}) + + /** + * 将源对象转换为目标类型的对象,使用JsonTypeReference指定目标类型 + * + * @param T 源对象的类型 + * @param D 目标对象的类型 + * @param source 需要转换的源对象 + * @param destinationType 目标对象的JsonTypeReference类型引用 + * @return 转换后的目标类型对象 + */ + @JvmStatic + fun convert(source: Any, destinationType: JsonTypeReference): D = + getJsonApi().convert(source, destinationType) + + /** + * 添加JSON转换器到API中 + * + * @param c 需要添加的JSON转换器实例 + */ + @JvmStatic + fun addJsonConverter(c: BaseJsonConverter<*, *>) = getJsonApi().addJsonConverter(c) + + /** + * 使用反射创建并添加指定类型的JSON转换器到API中 + * + * @param T 继承自BaseJsonConverter的具体实现类 + */ + inline fun > addJsonConverter() = + addJsonConverter(T::class.java.newInstance()) + + + inline fun String.parseJson() = parse(this) + inline fun ByteArray.parseJson() = parse(this) + inline fun InputStream.parseJson() = this.use { parse(readBytes()) } + inline fun File.parseJson() = this.inputStream().parseJson() + inline fun Path.parseJson() = this.toFile().inputStream().parseJson() + + fun Any.toJson() = format(this) + + fun jacksonKotlinObjectMapper(): ObjectMapper = ObjectMapper().jacksonKotlinObjectMapper() + fun ObjectMapper.jacksonKotlinObjectMapper(): ObjectMapper = this.registerModule(kotlinModule()) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/JacksonJsonApi.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/JacksonJsonApi.kt similarity index 79% rename from src/main/kotlin/com/mingliqiye/utils/json/JacksonJsonApi.kt rename to src/main/kotlin/com/mingliqiye/utils/json/api/JacksonJsonApi.kt index 1e9dfb6..319d244 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/JacksonJsonApi.kt +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/JacksonJsonApi.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile JacksonJsonApi.kt - * LastUpdate 2025-09-15 22:07:43 + * LastUpdate 2026-02-05 14:41:27 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.json +package com.mingliqiye.utils.json.api import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.core.JsonProcessingException @@ -28,9 +28,10 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectReader import com.fasterxml.jackson.databind.node.ObjectNode -import com.mingliqiye.utils.json.converters.JsonConverter -import com.mingliqiye.utils.json.converters.JsonStringConverter -import java.io.IOException +import com.mingliqiye.utils.exception.JsonException +import com.mingliqiye.utils.json.api.base.JsonApi +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import com.mingliqiye.utils.json.converters.base.BaseJsonConverter /** * 基于Jackson的JSON处理实现类,提供JSON字符串解析、格式化、合并、节点操作等功能。 @@ -52,7 +53,7 @@ class JacksonJsonApi : JsonApi { * @param objectMapper 自定义的ObjectMapper实例 */ constructor(objectMapper: ObjectMapper) { - this.objectMapper = objectMapper.copy() + this.objectMapper = objectMapper } /** @@ -67,7 +68,7 @@ class JacksonJsonApi : JsonApi { override fun parse(json: String, clazz: Class): T { return try { objectMapper.readValue(json, clazz) - } catch (e: IOException) { + } catch (e: Exception) { throw JsonException("Failed to parse JSON string", e) } } @@ -87,7 +88,7 @@ class JacksonJsonApi : JsonApi { objectMapper.constructType(type.type) ) reader.readValue(json) - } catch (e: IOException) { + } catch (e: Exception) { throw JsonException("Failed to parse JSON string", e) } } @@ -102,21 +103,17 @@ class JacksonJsonApi : JsonApi { override fun format(obj: Any): String { return try { objectMapper.writeValueAsString(obj) - } catch (e: JsonProcessingException) { + } catch (e: Exception) { throw JsonException( - "Failed to format object to JSON string", - e + "Failed to format object to JSON string", e ) } } override fun formatUnicode(obj: Any): String { return try { - objectMapper - .writer() - .with(JsonGenerator.Feature.ESCAPE_NON_ASCII) - .writeValueAsString(obj) - } catch (e: JsonProcessingException) { + objectMapper.writer().with(JsonGenerator.Feature.ESCAPE_NON_ASCII).writeValueAsString(obj) + } catch (e: Exception) { throw JsonException(e) } } @@ -130,27 +127,21 @@ class JacksonJsonApi : JsonApi { */ override fun formatPretty(obj: Any): String { return try { - objectMapper - .writerWithDefaultPrettyPrinter() - .writeValueAsString(obj) - } catch (e: JsonProcessingException) { + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj) + } catch (e: Exception) { throw JsonException( - "Failed to format object to pretty JSON string", - e + "Failed to format object to pretty JSON string", e ) } } override fun formatPrettyUnicode(obj: Any): String { return try { - objectMapper - .writerWithDefaultPrettyPrinter() - .with(JsonGenerator.Feature.ESCAPE_NON_ASCII) + objectMapper.writerWithDefaultPrettyPrinter().with(JsonGenerator.Feature.ESCAPE_NON_ASCII) .writeValueAsString(obj) - } catch (e: JsonProcessingException) { + } catch (e: Exception) { throw JsonException( - "Failed to format object to pretty JSON string", - e + "Failed to format object to pretty JSON string", e ) } } @@ -186,8 +177,7 @@ class JacksonJsonApi : JsonApi { if (node.isObject) { result.setAll(node as ObjectNode) } - } catch (e: IOException) { - // 忽略无效的JSON字符串 + } catch (e: Exception) { } } return try { @@ -213,7 +203,7 @@ class JacksonJsonApi : JsonApi { node = node.get(p) } node.asText() - } catch (e: IOException) { + } catch (e: Exception) { throw JsonException("Failed to get node value", e) } } @@ -247,15 +237,14 @@ class JacksonJsonApi : JsonApi { if (current is ObjectNode) { val parent: ObjectNode = current parent.set( - paths[paths.size - 1], - objectMapper.valueToTree(newValue) + paths[paths.size - 1], objectMapper.valueToTree(newValue) ) } objectMapper.writeValueAsString(objectNode) } json - } catch (e: IOException) { + } catch (e: Exception) { throw JsonException("Failed to update node value", e) } } @@ -269,8 +258,12 @@ class JacksonJsonApi : JsonApi { * @param 目标对象类型 * @return 转换后的对象 */ - override fun convert(source: T, destinationClass: Class): D { - return objectMapper.convertValue(source, destinationClass) + override fun convert(source: Any, destinationClass: Class): D { + try { + return objectMapper.convertValue(source, destinationClass) + } catch (e: Exception) { + throw JsonException("Failed to update node value", e) + } } /** @@ -282,20 +275,21 @@ class JacksonJsonApi : JsonApi { * @param 目标对象类型 * @return 转换后的对象 */ - override fun convert(source: T, destinationType: JsonTypeReference): D { - return objectMapper.convertValue( - source, - objectMapper.constructType(destinationType.type) - ) - } - - override fun addJsonConverter(c: JsonConverter<*, *>) { - c.getStringConverter()?.let { - objectMapper.registerModule(it.jacksonJsonStringConverterAdapter.jacksonModule) + override fun convert(source: Any, destinationType: JsonTypeReference): D { + try { + return objectMapper.convertValue( + source, objectMapper.constructType(destinationType.type) + ) + } catch (e: Exception) { + throw JsonException("Failed to update node value", e) } } - override fun addJsonStringConverter(c: JsonStringConverter<*>) { - addJsonConverter(c) + override fun addJsonConverter(c: BaseJsonConverter<*, *>) { + try { + objectMapper.registerModule(c.getJacksonModule()) + } catch (e: Exception) { + throw JsonException("Failed to update node value", e) + } } } diff --git a/src/main/kotlin/com/mingliqiye/utils/json/JsonApi.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/base/JsonApi.kt similarity index 59% rename from src/main/kotlin/com/mingliqiye/utils/json/JsonApi.kt rename to src/main/kotlin/com/mingliqiye/utils/json/api/base/JsonApi.kt index 0de3c89..4b9cfc7 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/JsonApi.kt +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/base/JsonApi.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,128 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile JsonApi.kt - * LastUpdate 2025-09-15 22:32:50 + * LastUpdate 2026-02-04 21:00:48 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.json +package com.mingliqiye.utils.json.api.base -import com.mingliqiye.utils.json.converters.JsonConverter -import com.mingliqiye.utils.json.converters.JsonStringConverter +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import com.mingliqiye.utils.json.api.type.listType +import com.mingliqiye.utils.json.converters.base.BaseJsonConverter import java.io.* import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths - /** * JSON处理接口,提供JSON字符串与Java对象之间的相互转换功能 */ interface JsonApi { + + companion object { + /** + * 将JSON字符串解析为指定泛型类型对象 + * + * @param json 待解析的JSON字符串 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parse(json: String): T = parse(json, object : JsonTypeReference() {}) + + /** + * 将JSON字节数组解析为指定泛型类型对象 + * + * @param json 待解析的JSON字节数组 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parse(json: ByteArray): T = parse(json, object : JsonTypeReference() {}) + + /** + * 将JSON字符串解析为指定泛型类型对象,解析失败时返回默认值 + * + * @param json 待解析的JSON字符串 + * @param defect 解析失败时返回的默认值 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例或默认值 + */ + inline fun JsonApi.parse(json: String, defect: T): T = + parse(json, object : JsonTypeReference() {}, defect) + + /** + * 从文件路径读取JSON并解析为指定泛型类型对象 + * + * @param path 文件路径 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parseFrom(path: String): T = parseFrom(path, object : JsonTypeReference() {}) + + /** + * 从文件读取JSON并解析为指定泛型类型对象 + * + * @param path 文件对象 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parseFrom(path: File): T = parseFrom(path, object : JsonTypeReference() {}) + + /** + * 从输入流读取JSON并解析为指定泛型类型对象 + * + * @param path 输入流 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parseFrom(path: InputStream): T = + parseFrom(path, object : JsonTypeReference() {}) + + /** + * 从路径读取JSON并解析为指定泛型类型对象 + * + * @param path 路径对象 + * @param T 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ + inline fun JsonApi.parseFrom(path: Path): T = parseFrom(path, object : JsonTypeReference() {}) + + /** + * 将JSON字符串解析为指定键值类型的Map集合 + * + * @param json 待解析的JSON字符串 + * @param K 泛型参数,表示Map中键的类型 + * @param V 泛型参数,表示Map中值的类型 + * @return 解析后的Map集合 + */ + inline fun JsonApi.parseMap( + json: String + ): MutableMap = parseMap(json, K::class.java, V::class.java) + + + /** + * 使用内联函数和reified类型参数将源对象转换为目标类型的对象 + * + * @param T 源对象的类型 + * @param D 目标对象的类型(通过reified类型参数推断) + * @param source 需要转换的源对象 + * @return 转换后的目标类型对象 + */ + @JvmStatic + inline fun JsonApi.convert(source: Any): D = convert(source, object : JsonTypeReference() {}) + + /** + * 添加JSON转换器到API中 + * + * @param T 需要添加的JSON转换器类 + */ + @JvmStatic + inline fun > JsonApi.addJsonConverter() { + addJsonConverter(T::class.java.newInstance()) + } + + } + /** * 将JSON字符串解析为指定类型的对象 * @@ -64,24 +168,52 @@ interface JsonApi { fun formatUnicode(obj: Any): String - @Throws(IOException::class) + /** + * 从文件路径读取JSON并解析为指定类型对象 + * + * @param path 文件路径 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(path: String, clazz: Class): T { return parseFrom(Paths.get(path), clazz) } - @Throws(IOException::class) + /** + * 从路径读取JSON并解析为指定类型对象 + * + * @param path 路径对象 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(path: Path, clazz: Class): T { return parseFrom(path.toFile(), clazz) } - @Throws(IOException::class) + /** + * 从文件读取JSON并解析为指定类型对象 + * + * @param file 文件对象 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(file: File, clazz: Class): T { Files.newInputStream(file.toPath()).use { inputStream -> return parseFrom(inputStream, clazz) } } - @Throws(IOException::class) + /** + * 从输入流读取JSON并解析为指定类型对象 + * + * @param inputStream 输入流 + * @param clazz 目标对象的Class类型 + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(inputStream: InputStream, clazz: Class): T { val bytes = ByteArray(1024) ByteArrayOutputStream().use { bos -> @@ -93,24 +225,52 @@ interface JsonApi { } } - @Throws(IOException::class) + /** + * 从文件路径读取JSON并解析为指定泛型类型对象 + * + * @param path 文件路径 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(path: String, type: JsonTypeReference): T { return parseFrom(Paths.get(path), type) } - @Throws(IOException::class) + /** + * 从路径读取JSON并解析为指定泛型类型对象 + * + * @param path 路径对象 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(path: Path, type: JsonTypeReference): T { return parseFrom(path.toFile(), type) } - @Throws(IOException::class) + /** + * 从文件读取JSON并解析为指定泛型类型对象 + * + * @param file 文件对象 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(file: File, type: JsonTypeReference): T { Files.newInputStream(file.toPath()).use { inputStream -> return parseFrom(inputStream, type) } } - @Throws(IOException::class) + /** + * 从输入流读取JSON并解析为指定泛型类型对象 + * + * @param inputStream 输入流 + * @param type 目标对象的Type类型(支持泛型) + * @param 泛型参数,表示目标对象的类型 + * @return 解析后的对象实例 + */ fun parseFrom(inputStream: InputStream, type: JsonTypeReference): T { val bytes = ByteArray(1024) ByteArrayOutputStream().use { bos -> @@ -156,10 +316,10 @@ interface JsonApi { * @return 解析后的对象实例或默认值 */ fun parse(json: String, clazz: Class, defaultValue: T): T { - try { - return parse(json, clazz) + return try { + parse(json, clazz) } catch (e: Exception) { - return defaultValue + defaultValue } } @@ -173,14 +333,12 @@ interface JsonApi { * @return 解析后的对象实例或默认值 **/ fun parse( - json: String, - type: JsonTypeReference, - defaultValue: T + json: String, type: JsonTypeReference, defaultValue: T ): T { - try { - return parse(json, type) + return try { + parse(json, type) } catch (e: Exception) { - return defaultValue + defaultValue } } @@ -202,46 +360,38 @@ interface JsonApi { return formatPrettyUnicode(obj)!!.toByteArray() } - @Throws(IOException::class) fun formatPretty(obj: Any, file: String) { formatPretty(obj, Paths.get(file)) } - @Throws(IOException::class) fun formatPretty(obj: Any, file: Path) { formatPretty(obj, file.toFile()) } - @Throws(IOException::class) fun formatPretty(obj: Any, file: File) { FileOutputStream(file).use { fos -> formatPretty(obj, fos) } } - @Throws(IOException::class) fun formatPretty(obj: Any, stream: OutputStream) { stream.write(formatPrettyBytes(obj)) } - @Throws(IOException::class) fun formatPrettyUnicode(obj: Any, file: String) { formatPrettyUnicode(obj, Paths.get(file)) } - @Throws(IOException::class) fun formatPrettyUnicode(obj: Any, file: Path) { formatPrettyUnicode(obj, file.toFile()) } - @Throws(IOException::class) fun formatPrettyUnicode(obj: Any, file: File) { FileOutputStream(file).use { fos -> formatPrettyUnicode(obj, fos) } } - @Throws(IOException::class) fun formatPrettyUnicode(obj: Any, stream: OutputStream) { stream.write(formatPrettyUnicodeBytes(obj)) } @@ -254,46 +404,38 @@ interface JsonApi { return formatUnicode(obj)!!.toByteArray() } - @Throws(IOException::class) fun format(obj: Any, file: String) { format(obj, Paths.get(file)) } - @Throws(IOException::class) fun format(obj: Any, file: Path) { format(obj, file.toFile()) } - @Throws(IOException::class) fun format(obj: Any, file: File) { FileOutputStream(file).use { fos -> format(obj, fos) } } - @Throws(IOException::class) fun format(obj: Any, stream: OutputStream) { stream.write(formatPrettyBytes(obj)) } - @Throws(IOException::class) fun formatUnicode(obj: Any, file: String) { formatUnicode(obj, Paths.get(file)) } - @Throws(IOException::class) fun formatUnicode(obj: Any, file: Path) { formatUnicode(obj, file.toFile()) } - @Throws(IOException::class) fun formatUnicode(obj: Any, file: File) { FileOutputStream(file).use { fos -> formatUnicode(obj, fos) } } - @Throws(IOException::class) fun formatUnicode(obj: Any, stream: OutputStream) { stream.write(formatPrettyUnicodeBytes(obj)) } @@ -321,9 +463,7 @@ interface JsonApi { * @return 解析后的Map集合 */ fun parseMap( - json: String, - keyType: Class, - valueType: Class + json: String, keyType: Class, valueType: Class ): MutableMap { val mapType: JsonTypeReference> = object : JsonTypeReference>() {} return parse>(json, mapType) @@ -384,10 +524,9 @@ interface JsonApi { */ fun updateNodeValue(json: String, path: String, newValue: Any): String - fun convert(source: T, destinationClass: Class): D + fun convert(source: Any, destinationClass: Class): D - fun convert(source: T, destinationType: JsonTypeReference): D + fun convert(source: Any, destinationType: JsonTypeReference): D - fun addJsonConverter(c: JsonConverter<*, *>) - fun addJsonStringConverter(c: JsonStringConverter<*>) + fun addJsonConverter(c: BaseJsonConverter<*, *>) } diff --git a/src/main/kotlin/com/mingliqiye/utils/json/JsonTypeReference.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeReference.kt similarity index 87% rename from src/main/kotlin/com/mingliqiye/utils/json/JsonTypeReference.kt rename to src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeReference.kt index a09739d..d824f55 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/JsonTypeReference.kt +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeReference.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile JsonTypeReference.kt - * LastUpdate 2025-09-15 22:32:50 + * LastUpdate 2026-02-05 11:12:36 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.json +package com.mingliqiye.utils.json.api.type import java.lang.reflect.ParameterizedType import java.lang.reflect.Type @@ -68,8 +68,7 @@ abstract class JsonTypeReference : Comparable> { * @return 类型引用实例 */ companion object { - @JvmStatic - fun of(): JsonTypeReference { + inline fun of(): JsonTypeReference { return object : JsonTypeReference() {} } @@ -116,6 +115,11 @@ abstract class JsonTypeReference : Comparable> { throw IllegalStateException("无法获取原始类型: $type") } + /** + * 判断两个 JsonTypeReference 实例是否相等 + * @param other 另一个对象 + * @return 是否相等 + */ override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this.javaClass != other.javaClass) return false @@ -142,6 +146,10 @@ abstract class JsonTypeReference : Comparable> { return Objects.equals(type, that.type) } + /** + * 计算当前实例的哈希码 + * @return 哈希码值 + */ override fun hashCode(): Int { if (type is ParameterizedType) { val paramType = type as ParameterizedType @@ -154,10 +162,19 @@ abstract class JsonTypeReference : Comparable> { return Objects.hash(type) } + /** + * 返回当前实例的字符串表示形式 + * @return 字符串描述 + */ override fun toString(): String { - return "JsonTypeReference{$type}" + return "com.mingliqiye.utils.json.JsonTypeReference<${TypeReference.getRawString(type)}>" } + /** + * 比较当前实例与另一个实例的大小关系 + * @param other 另一个 JsonTypeReference 实例 + * @return 比较结果 + */ override fun compareTo(other: JsonTypeReference): Int { return this.type.toString().compareTo(other.type.toString()) } diff --git a/src/main/kotlin/com/mingliqiye/utils/json/JsonTypeUtils.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeUtils.kt similarity index 98% rename from src/main/kotlin/com/mingliqiye/utils/json/JsonTypeUtils.kt rename to src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeUtils.kt index b7dfe42..87e8b05 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/JsonTypeUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/type/JsonTypeUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile JsonTypeUtils.kt - * LastUpdate 2025-09-17 11:12:06 + * LastUpdate 2026-02-04 21:00:48 * UpdateUser MingLiPro */ @file:JvmName("JsonTypeUtils") -package com.mingliqiye.utils.json +package com.mingliqiye.utils.json.api.type import java.lang.reflect.ParameterizedType import java.lang.reflect.Type diff --git a/src/main/kotlin/com/mingliqiye/utils/json/api/type/TypeReference.kt b/src/main/kotlin/com/mingliqiye/utils/json/api/type/TypeReference.kt new file mode 100644 index 0000000..f96b554 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/api/type/TypeReference.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile TypeReference.kt + * LastUpdate 2026-02-04 21:00:48 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.api.type + +import com.mingliqiye.utils.string.join +import sun.reflect.generics.reflectiveObjects.WildcardTypeImpl +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type + +class TypeReference( + val rawClass: Type, + vararg paramType: Type +) : ParameterizedType { + + private val typeArguments: Array = paramType + override fun getActualTypeArguments(): Array = typeArguments + + override fun getRawType(): Type = rawClass + + override fun getOwnerType(): Type? = null + + + override fun toString(): String = "${getRawString(rawType)}<${ + ",".join(typeArguments, TypeReference::getRawString) + }>" + + companion object { + + fun getRawString(s: Any): String { + if (s is Class<*>) { + return s.name + } + if (s is WildcardTypeImpl) { + return getRawString(s.upperBounds[0]) + } + if (s is ParameterizedType) { + return of(s).toString() + } + return s.toString() + } + + inline fun of(): TypeReference { + return of((object : JsonTypeReference() {}).type) + } + + fun of(type: Type): TypeReference { + if (type is Class<*>) { + return TypeReference(type) + } + if (type is ParameterizedType) { + return TypeReference(type.rawType, *type.actualTypeArguments) + } + throw IllegalStateException("无法获取类型: $type") + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/DateTimeJsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/DateTimeJsonConverter.kt new file mode 100644 index 0000000..53e7319 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/DateTimeJsonConverter.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile DateTimeJsonConverter.kt + * LastUpdate 2026-02-07 22:13:41 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters + +import com.mingliqiye.utils.annotation.DateTimeJsonFormat +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import com.mingliqiye.utils.json.converters.base.AnnotationGetter +import com.mingliqiye.utils.json.converters.base.AnnotationGetter.Companion.get +import com.mingliqiye.utils.json.converters.base.BaseJsonStringConverter +import com.mingliqiye.utils.objects.isNull +import com.mingliqiye.utils.string.isNullish +import com.mingliqiye.utils.time.DateTime +import com.mingliqiye.utils.time.Formatter + + +/** + * DateTimeJsonConverter 是一个用于处理 DateTime 类型与 JSON 字符串之间转换的类。 + * 它继承自 BaseJsonStringConverter,提供了序列化(convert)和反序列化(deConvert)的功能。 + */ +class DateTimeJsonConverter private constructor() : BaseJsonStringConverter { + + + companion object { + private val dateTimeJsonConverter by lazy { + DateTimeJsonConverter() + } + + @JvmStatic + fun getJsonConverter(): DateTimeJsonConverter = dateTimeJsonConverter + } + + /** + * 将 DateTime 对象转换为 JSON 字符串。 + * + * @param obj 需要转换的 DateTime 对象,可能为 null。 + * @param annotationGetter 用于获取注解信息的对象,用于决定格式化方式。 + * @return 转换后的字符串,如果输入为 null 则返回 null。 + * @throws Exception 如果在转换过程中发生异常。 + */ + @Throws(Exception::class) + override fun convert(obj: DateTime?, annotationGetter: AnnotationGetter): String? { + // 如果输入对象为 null,直接返回 null + if (obj.isNull()) return null + + // 获取 DateTimeJsonFormat 注解信息 + val dateTimeJsonFormat: DateTimeJsonFormat? = annotationGetter.get() + + // 根据注解中的格式化规则进行转换 + return if (Formatter.NONE != dateTimeJsonFormat?.value && dateTimeJsonFormat != null) { + obj.format(dateTimeJsonFormat.value, dateTimeJsonFormat.repcZero) + } else if (dateTimeJsonFormat?.formatter?.isEmpty() == false) { + obj.format(dateTimeJsonFormat.formatter, dateTimeJsonFormat.repcZero) + } else { + obj.format() + } + } + + /** + * 将 JSON 字符串转换为 DateTime 对象。 + * + * @param obj 需要转换的字符串,可能为 null 或空。 + * @param annotationGetter 用于获取注解信息的对象,用于决定解析方式。 + * @return 解析后的 DateTime 对象,如果输入为 null 或空则返回 null。 + * @throws Exception 如果在解析过程中发生异常。 + */ + @Throws(Exception::class) + override fun deConvert(obj: String?, annotationGetter: AnnotationGetter): DateTime? { + // 如果输入字符串为 null 或空,直接返回 null + if (obj.isNullish()) return null + + // 获取 DateTimeJsonFormat 注解信息 + val dateTimeJsonFormat: DateTimeJsonFormat? = annotationGetter.get() + + // 根据注解中的解析规则进行转换 + return if (Formatter.NONE != dateTimeJsonFormat?.value && dateTimeJsonFormat != null) { + DateTime.parse(obj, dateTimeJsonFormat.value, dateTimeJsonFormat.repcZero) + } else if (dateTimeJsonFormat?.formatter?.isEmpty() == false) { + DateTime.parse(obj, dateTimeJsonFormat.formatter, dateTimeJsonFormat.repcZero) + } else { + DateTime.parse(obj) + } + } + + /** + * 获取当前转换器支持的目标类型引用。 + * + * @return 返回 DateTime 类型的 JsonTypeReference。 + * @throws Exception 如果在获取类型引用时发生异常。 + */ + @Throws(Exception::class) + override fun getFromType(): JsonTypeReference = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/JsonStringConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/JsonStringConverter.kt deleted file mode 100644 index fb75153..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/json/converters/JsonStringConverter.kt +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile JsonStringConverter.kt - * LastUpdate 2025-09-17 19:09:17 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.json.converters - -import com.alibaba.fastjson2.JSONReader -import com.alibaba.fastjson2.JSONWriter -import com.alibaba.fastjson2.reader.ObjectReader -import com.alibaba.fastjson2.writer.ObjectWriter -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.* -import com.fasterxml.jackson.databind.module.SimpleModule -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import com.mingliqiye.utils.time.DateTime -import com.mingliqiye.utils.time.DateTime.Companion.parse -import com.mingliqiye.utils.uuid.UUID -import com.mingliqiye.utils.uuid.UUID.Companion.of -import java.io.IOException -import java.lang.reflect.Type - -/** - * JSON转换器接口,提供对象与字符串之间的相互转换功能,并支持多种JSON库 - * - * @param 需要转换的对象类型 - */ -abstract class JsonStringConverter : JsonConverter { - val fastjsonJsonStringConverterAdapter: FastjsonJsonStringConverterAdapter, T> - /** - * 获取 Fastjson 的适配器 - * @return 适配器实例 - */ - get() = FastjsonJsonStringConverterAdapter.of(this) - - val gsonJsonStringConverterAdapter: GsonJsonStringConverterAdapter, T> - /** - * 获取 Gson 的适配器 - * @return 适配器实例 - */ - get() = GsonJsonStringConverterAdapter.of(this) - - val jacksonJsonStringConverterAdapter: JacksonJsonStringConverterAdapter, T> - /** - * 获取 Jackson 的适配器 - * @return 适配器实例 - */ - get() = JacksonJsonStringConverterAdapter.of(this) -} - - -class JacksonJsonStringConverterAdapter, TT - > private constructor(val jsonStringConverter: T) { - - val jacksonJsonDeserializer: JsonDeserializer - /** - * 获取Jackson反序列化器 - * - * @return Jackson的JsonDeserializer实例 - */ - get() = object : JsonDeserializer() { - @Throws(IOException::class) - override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): TT? { - if (p.isNaN) return null - return jsonStringConverter.deConvert(p.valueAsString) - } - } - - val jacksonJsonSerializer: JsonSerializer - /** - * 获取Jackson序列化器 - * - * @return Jackson的JsonSerializer实例 - */ - get() = object : JsonSerializer() { - @Throws(IOException::class) - override fun serialize( - value: TT?, - gen: JsonGenerator, - serializers: SerializerProvider? - ) { - if (value == null) { - gen.writeNull() - return - } - gen.writeString(jsonStringConverter.convert(value)) - } - } - - val jacksonModule: Module - /** - * - * 获取 Jackson 的格式化模块 - * - * @return 格式化模块 - */ - get() { - val tClass = jsonStringConverter.tClass - val m = SimpleModule(tClass.getSimpleName()) - m.addSerializer(tClass, this.jacksonJsonSerializer) - m.addDeserializer(tClass, this.jacksonJsonDeserializer) - return m - } - - companion object { - /** - * - * @param t JSON转换器实例 - * @return JSON转换器的适配器 - * @param JSON转换器 - * @param JSON转换器的泛型 - **/ - fun , TT - > of(t: T): JacksonJsonStringConverterAdapter { - return JacksonJsonStringConverterAdapter(t) - } - } -} - -class GsonJsonStringConverterAdapter, TT - >(val jsonStringConverter: T) { - - val gsonTypeAdapter: TypeAdapter - /** - * 获取Gson类型适配器 - * - * @return Gson的TypeAdapter实例 - */ - get() = object : TypeAdapter() { - @Throws(IOException::class) - override fun write(out: JsonWriter, value: TT?) { - if (value == null) { - out.nullValue() - return - } - out.value(jsonStringConverter.convert(value)) - } - - @Throws(IOException::class) - override fun read(`in`: JsonReader): TT? { - val value = `in`.nextString() - return jsonStringConverter.deConvert(value) - } - } - - companion object { - fun , TT - > of(t: T): GsonJsonStringConverterAdapter { - return GsonJsonStringConverterAdapter(t) - } - } -} - -class FastjsonJsonStringConverterAdapter, TT - >(val jsonStringConverter: T) { - @Suppress("UNCHECKED_CAST") - val fastJsonObjectWriter: ObjectWriter - /** - * 获取FastJson对象写入器 - * - * @return FastJson的ObjectWriter实例 - */ - get() = ObjectWriter { writer: JSONWriter?, obj: Any?, _: Any?, _: Type?, _: Long - -> - // 如果对象为null则写入null - if (obj == null) { - writer!!.writeNull() - return@ObjectWriter - } - writer!!.writeString(jsonStringConverter.convert(obj as TT)) - } - - val fastJsonObjectReader: ObjectReader - /** - * 获取FastJson对象读取器 - * - * @return FastJson的ObjectReader实例 - */ - get() = ObjectReader { reader: JSONReader?, _: Type?, _: Any?, _: Long - -> - val value = reader!!.readString() - jsonStringConverter.deConvert(value) - } - - companion object { - fun , TT - > of(t: T): FastjsonJsonStringConverterAdapter { - return FastjsonJsonStringConverterAdapter(t) - } - } -} - - -class DateTimeJsonConverter : JsonStringConverter() { - override val tClass = DateTime::class.java - - override fun convert(obj: DateTime?): String? { - if (obj == null) { - return null - } - return obj.format() - } - - override fun deConvert(obj: String?): DateTime? { - if (obj == null) { - return null - } - return parse( - obj - ) - } -} - -class UUIDJsonStringConverter : JsonStringConverter() { - override val tClass: Class = UUID::class.java - - override fun convert(obj: UUID?): String? { - if (obj == null) { - return null - } - return obj.getString() - } - - override fun deConvert(obj: String?): UUID? { - if (obj == null) { - return null - } - return of(obj) - } - -} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/UUIDJsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/UUIDJsonConverter.kt new file mode 100644 index 0000000..1a20a80 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/UUIDJsonConverter.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UUIDJsonConverter.kt + * LastUpdate 2026-02-08 01:37:00 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters + +import com.mingliqiye.utils.annotation.UUIDJsonFormat +import com.mingliqiye.utils.base.BaseType +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import com.mingliqiye.utils.json.converters.base.AnnotationGetter +import com.mingliqiye.utils.json.converters.base.AnnotationGetter.Companion.get +import com.mingliqiye.utils.json.converters.base.BaseJsonStringConverter +import com.mingliqiye.utils.objects.isNull +import com.mingliqiye.utils.string.isNullish +import com.mingliqiye.utils.uuid.UUID +import com.mingliqiye.utils.uuid.UUIDFormatType + +/** + * UUIDJsonConverter 是一个用于处理 UUID 类型与 JSON 字符串之间转换的类。 + * 它继承自 BaseJsonStringConverter,并实现了 convert 和 deConvert 方法, + * 分别用于将 UUID 对象序列化为字符串以及反序列化字符串为 UUID 对象。 + */ +class UUIDJsonConverter private constructor() : BaseJsonStringConverter { + + companion object { + private val uuidJsonConverter by lazy { + UUIDJsonConverter() + } + + @JvmStatic + fun getJsonConverter(): UUIDJsonConverter = uuidJsonConverter + } + + /** + * 将 UUID 对象转换为字符串形式。 + * + * @param obj 需要转换的 UUID 对象,可能为 null。 + * @param annotationGetter 用于获取注解信息的对象。 + * @return 转换后的字符串,如果输入为 null 则返回 null。 + */ + override fun convert( + obj: UUID?, + annotationGetter: AnnotationGetter + ): String? { + // 如果输入对象为 null,直接返回 null + if (obj.isNull()) return null + + // 获取 UUIDJsonFormat 注解信息,若未找到则使用默认格式 + val dateTimeJsonFormat: UUIDJsonFormat = annotationGetter.get() ?: return obj.getString() + + // 根据注解中的 base 和 value 属性选择合适的字符串表示方式 + return if (BaseType.BASE16 != dateTimeJsonFormat.base) { + obj.getString(dateTimeJsonFormat.base) + } else if (UUIDFormatType.NO_UPPER_SPACE != dateTimeJsonFormat.value) { + obj.getString(dateTimeJsonFormat.value) + } else { + obj.getString() + } + } + + /** + * 将字符串反序列化为 UUID 对象。 + * + * @param obj 需要反序列化的字符串,可能为 null 或空。 + * @param annotationGetter 用于获取注解信息的对象。 + * @return 反序列化后的 UUID 对象,如果输入无效则返回 null。 + */ + override fun deConvert( + obj: String?, + annotationGetter: AnnotationGetter + ): UUID? { + // 如果输入字符串为 null 或空,直接返回 null + if (obj.isNullish()) return null + + // 获取 UUIDJsonFormat 注解信息,若未找到则使用默认解析方式 + val dateTimeJsonFormat: UUIDJsonFormat = annotationGetter.get() ?: return UUID.of(obj) + + // 根据注解中的 base 属性选择合适的解析方式 + return if (BaseType.BASE16 != dateTimeJsonFormat.base) { + UUID.of(obj, dateTimeJsonFormat.base) + } else { + UUID.of(obj) + } + } + + /** + * 返回当前转换器支持的目标类型引用。 + * + * @return 表示 UUID 类型的 JsonTypeReference 对象。 + */ + override fun getFromType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/AnnotationGetter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/AnnotationGetter.kt new file mode 100644 index 0000000..747c563 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/AnnotationGetter.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile AnnotationGetter.kt + * LastUpdate 2026-02-06 16:57:45 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +/** + * 定义一个用于获取注解的接口。 + * 提供了一个通用方法来根据注解类型获取对应的注解实例。 + */ +interface AnnotationGetter { + /** + * 根据指定的注解类型获取该类型的注解实例。 + * + * @param clazz 注解的Class对象,表示要获取的注解类型。 + * @return 返回对应类型的注解实例,如果未找到则返回null。 + */ + fun get(clazz: Class): T? + + companion object { + /** + * 使用内联函数和重ified类型参数简化注解获取操作。 + * 通过传入泛型参数自动推断注解类型,避免手动传递Class对象。 + * + * @param T 注解类型,必须继承自Annotation。 + * @return 返回对应类型的注解实例,如果未找到则返回null。 + */ + inline fun AnnotationGetter.get(): T? = this.get(T::class.java) + + /** + * 提供一个默认实现,始终返回null。 + * 可用于需要空注解获取器的场景。 + */ + val nullGetter = object : AnnotationGetter { + /** + * 始终返回null,不执行任何实际逻辑。 + * + * @param clazz 注解的Class对象(未使用)。 + * @return 始终返回null。 + */ + override fun get(clazz: Class): T? = null + } + + + /** + * 创建一个AnnotationGetter对象,用于根据指定的注解类型获取对应的注解实例。 + * + * @param annotation 要包装的注解实例,作为内部逻辑的来源。 + * @return 返回一个实现了AnnotationGetter接口的匿名对象。 + */ + fun oneGetter(annotation: Annotation) = object : AnnotationGetter { + /** + * 根据传入的注解类型clazz,尝试返回与annotation匹配的注解实例。 + * + * @param clazz 目标注解类型的Class对象。 + * @return 如果annotation的类型与clazz一致,则返回annotation转换为T类型的实例;否则返回null。 + */ + override fun get(clazz: Class): T? = + if (annotation.javaClass == clazz) annotation as T else null + } + + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigDecimalConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigDecimalConverter.kt new file mode 100644 index 0000000..fc12e1d --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigDecimalConverter.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonBigDecimalConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import java.math.BigDecimal + +/** + * 接口 [BaseJsonBigDecimalConverter] 定义了一个用于将 JSON 数据转换为 [BigDecimal] 类型的转换器。 + * + * 此接口继承自 [BaseJsonConverter],并指定目标类型为 [BigDecimal]。 + * 实现此接口的类需要提供具体的转换逻辑。 + * + * @param E 转换器处理的源数据类型。 + */ +interface BaseJsonBigDecimalConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法返回一个 [JsonTypeReference] 对象,表示目标类型为 [BigDecimal]。 + * 通过调用 [JsonTypeReference.Companion.of] 方法创建类型引用。 + * + * @return 目标类型 [BigDecimal] 的类型引用。 + * @throws Exception 如果在获取类型引用时发生异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigIntegerConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigIntegerConverter.kt new file mode 100644 index 0000000..2019ea6 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBigIntegerConverter.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonBigIntegerConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference +import java.math.BigInteger + +/** + * 接口 [BaseJsonBigIntegerConverter] 定义了一个用于将 JSON 数据转换为 `BigInteger` 类型的转换器。 + * 该接口继承自 [BaseJsonConverter],并指定了泛型参数 [E] 和 `BigInteger`。 + * + * @param E 表示需要转换的目标类型,由实现类具体指定。 + */ +interface BaseJsonBigIntegerConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用,用于 JSON 反序列化时确定目标类型。 + * 该方法重写了父接口中的 [getToType] 方法,并返回 `BigInteger` 类型的引用。 + * + * @return 返回 [JsonTypeReference] 对象,表示 `BigInteger` 类型的引用。 + * @throws Exception 如果在获取类型引用过程中发生异常,则抛出该异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBooleanConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBooleanConverter.kt new file mode 100644 index 0000000..182c371 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonBooleanConverter.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonBooleanConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonBooleanConverter] 定义了一个用于处理布尔类型 JSON 转换的基础转换器。 + * + * 该接口继承自 [BaseJsonConverter],并专门用于将某种类型 [E] 转换为布尔类型 [Boolean]。 + * 实现该接口的类需要提供具体的转换逻辑。 + */ +interface BaseJsonBooleanConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法返回一个 [JsonTypeReference] 对象,表示目标类型为 [Boolean]。 + * 此方法重写了父接口中的定义,并通过 [JsonTypeReference.Companion.of] 方法获取布尔类型的引用。 + * + * @return [JsonTypeReference] 表示布尔类型的引用。 + * @throws Exception 如果在获取类型引用时发生异常,则抛出此异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonByteConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonByteConverter.kt new file mode 100644 index 0000000..4a5274a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonByteConverter.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonByteConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * BaseJsonByteConverter 是一个接口,继承自 BaseJsonConverter,用于定义字节类型(Byte)的 JSON 转换器。 + * + * 该接口的主要作用是提供一个标准的字节类型转换实现,并通过 getToType 方法返回目标类型的引用。 + * + * @param E 泛型参数,表示需要转换的目标对象类型。 + */ +interface BaseJsonByteConverter : BaseJsonConverter { + /** + * 获取目标类型的引用,用于标识转换的目标类型为 Byte。 + * + * @return 返回 JsonTypeReference 类型的实例,表示目标类型为 Byte。 + * @throws Exception 如果在获取类型引用过程中发生异常,则抛出该异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonConverter.kt new file mode 100644 index 0000000..0c92f26 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonConverter.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonConverter.kt + * LastUpdate 2026-02-08 01:22:35 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +/** + * BaseJsonConverter 是一个泛型接口,用于定义 JSON 转换器的基本行为。 + * + * 该接口继承自 JackSonJsonConverter,并通过泛型参数 F 和 T 定义了转换的源类型和目标类型。 + * 实现该接口的类需要提供具体的 JSON 转换逻辑。 + * + * @param F 源类型,表示需要被转换的数据类型。 + * @param T 目标类型,表示转换后的数据类型。 + */ +interface BaseJsonConverter : JackSonJsonConverter diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonDoubleConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonDoubleConverter.kt new file mode 100644 index 0000000..1ea472c --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonDoubleConverter.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonDoubleConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * BaseJsonDoubleConverter 是一个接口,继承自 BaseJsonConverter, + * 用于定义将 JSON 数据转换为 Double 类型的转换器。 + * + * @param E 泛型参数,表示需要转换的目标类型。 + */ +interface BaseJsonDoubleConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用,用于标识转换的目标类型为 Double。 + * + * @return 返回 JsonTypeReference 类型的实例,表示目标类型为 Double。 + * @throws Exception 如果在获取类型引用时发生异常,则抛出该异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonFloatConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonFloatConverter.kt new file mode 100644 index 0000000..dbca332 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonFloatConverter.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonFloatConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonFloatConverter] 定义了一个用于处理浮点数类型 JSON 转换的基础转换器。 + * + * 该接口继承自 [BaseJsonConverter],并指定泛型参数 [E] 和 [Float], + * 表示将某种类型 [E] 转换为 [Float] 类型的 JSON 数据。 + */ +interface BaseJsonFloatConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法重写了父接口中的 [getToType] 方法,返回 [Float] 类型的 [JsonTypeReference] 实例。 + * 用于标识当前转换器的目标类型为 [Float]。 + * + * @return [JsonTypeReference] 表示 [Float] 类型的引用信息。 + * @throws Exception 如果在获取类型引用时发生异常,则抛出此异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonIntConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonIntConverter.kt new file mode 100644 index 0000000..2a2354a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonIntConverter.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonIntConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonIntConverter] 是一个泛型接口,继承自 [BaseJsonConverter], + * 用于定义将 JSON 数据转换为 [Int] 类型的转换器。 + * + * @param E 表示需要转换的目标类型,通常是一个具体的业务实体或数据模型。 + */ +interface BaseJsonIntConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法重写了父接口中的 [getToType] 方法,返回 [Int] 类型的 [JsonTypeReference] 实例。 + * 用于标识当前转换器的目标类型为 [Int]。 + * + * @return 返回 [JsonTypeReference] 的实例,表示目标类型为 [Int]。 + * @throws Exception 如果在获取类型引用时发生异常,则抛出该异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonLongConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonLongConverter.kt new file mode 100644 index 0000000..de1873b --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonLongConverter.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonLongConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonLongConverter] 定义了一个用于将 JSON 数据转换为 Long 类型的转换器。 + * + * 此接口继承自 [BaseJsonConverter],并指定泛型参数 [E] 和 [Long], + * 表示该转换器处理的是从类型 [E] 到 [Long] 的转换。 + */ +interface BaseJsonLongConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用,用于标识此转换器的目标类型为 [Long]。 + * + * @return 返回 [JsonTypeReference] 的实例,表示目标类型为 [Long]。 + * @throws Exception 如果在获取类型引用时发生异常,则抛出此异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonShortConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonShortConverter.kt new file mode 100644 index 0000000..4f13d70 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonShortConverter.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonShortConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonShortConverter] 定义了一个用于将 JSON 数据转换为 Short 类型的转换器。 + * + * 该接口继承自 [BaseJsonConverter],并指定泛型参数 [E] 和 [Short], + * 表示该转换器处理的源类型为 [E],目标类型为 [Short]。 + */ +interface BaseJsonShortConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法重写了父接口中的 [getToType] 方法,返回 [Short] 类型的 [JsonTypeReference] 实例。 + * 通过 [JsonTypeReference.Companion.of] 方法创建类型引用。 + * + * @return [JsonTypeReference] 表示 [Short] 类型的引用。 + * @throws Exception 如果在获取类型引用过程中发生异常,则抛出该异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonStringConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonStringConverter.kt new file mode 100644 index 0000000..eeaff15 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/BaseJsonStringConverter.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseJsonStringConverter.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * 接口 [BaseJsonStringConverter] 定义了一个用于 JSON 字符串转换的基础接口。 + * + * 该接口继承自 [BaseJsonConverter],并指定泛型参数 [E] 和 [String], + * 表示将类型 [E] 转换为字符串类型的 JSON 数据。 + */ +interface BaseJsonStringConverter : BaseJsonConverter { + + /** + * 获取目标类型的引用信息。 + * + * 该方法重写了父接口中的 [getToType] 方法,返回一个表示 [String] 类型的 [JsonTypeReference] 实例。 + * 此方法可能抛出异常,因此使用 [@Throws(Exception::class)] 注解标记。 + * + * @return 返回一个 [JsonTypeReference] 实例,表示目标类型为 [String]。 + * @throws Exception 如果在获取类型引用时发生错误,则抛出此异常。 + */ + @Throws(Exception::class) + override fun getToType() = JsonTypeReference.of() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonDeserializer.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonDeserializer.kt new file mode 100644 index 0000000..854bf6f --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonDeserializer.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JackJsonDeserializer.kt + * LastUpdate 2026-02-08 02:22:46 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken +import com.fasterxml.jackson.databind.BeanProperty +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.deser.ContextualDeserializer + +class JackJsonDeserializer( + val property: BeanProperty? = null, + val jsonConverter: JsonConverter +) : JsonDeserializer(), ContextualDeserializer { + override fun deserialize( + p: JsonParser, + ctxt: DeserializationContext? + ): F? { + if (p.currentToken == JsonToken.VALUE_NULL) return null + return jsonConverter.deConvert(p.readValueAs(jsonConverter.getToClass()), object : AnnotationGetter { + override fun get(clazz: Class): T? = property?.getAnnotation(clazz) + }) + } + + /** + * 上下文感知方法:设置当前属性信息。 + * + * @param ctxt 反序列化上下文,可选参数。 + * @param property 当前属性信息。 + * @return 返回当前反序列化器实例。 + */ + override fun createContextual( + ctxt: DeserializationContext?, + property: BeanProperty? + ): JackJsonDeserializer { + return JackJsonDeserializer(property, jsonConverter) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonSerializer.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonSerializer.kt new file mode 100644 index 0000000..a96d9c9 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackJsonSerializer.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JackJsonSerializer.kt + * LastUpdate 2026-02-08 02:27:52 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.BeanProperty +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.ContextualSerializer +import java.math.BigDecimal +import java.math.BigInteger + +class JackJsonSerializer( + val property: BeanProperty?, + val jsonConverter: JsonConverter +) : JsonSerializer(), ContextualSerializer { + + /** + * 序列化方法:将源对象转换为目标对象,并根据目标对象的类型写入 JSON。 + * + * @param value 源对象,可能为 null。 + * @param gen JSON 生成器,用于写入 JSON 数据。 + * @param provider 序列化提供者,可选参数。 + */ + override fun serialize( + value: F?, + gen: JsonGenerator, + provider: SerializerProvider? + ) { + // 执行转换逻辑 + val data: T? = jsonConverter.convert(value, object : AnnotationGetter { + override fun get(clazz: Class): T? = property?.getAnnotation(clazz) + }) + + // 根据目标对象的类型写入对应的 JSON 值 + when (data) { + null -> gen.writeNull() + is String -> gen.writeString(data) + is Long -> gen.writeNumber(data) + is Short -> gen.writeNumber(data) + is Byte -> gen.writeNumber(data.toShort()) + is Int -> gen.writeNumber(data) + is BigDecimal -> gen.writeNumber(data) + is BigInteger -> gen.writeNumber(data) + is Float -> gen.writeNumber(data) + is Double -> gen.writeNumber(data) + is Boolean -> gen.writeBoolean(data) + else -> throw IllegalArgumentException("not sport data type ${data.javaClass} $data") + } + } + + /** + * 上下文感知方法:设置当前属性信息。 + * + * @param prov 序列化提供者,可选参数。 + * @param property 当前属性信息。 + * @return 返回当前序列化器实例。 + */ + override fun createContextual( + prov: SerializerProvider?, + property: BeanProperty? + ): JsonSerializer { + return JackJsonSerializer(property, jsonConverter) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackSonJsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackSonJsonConverter.kt new file mode 100644 index 0000000..7214231 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JackSonJsonConverter.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JackSonJsonConverter.kt + * LastUpdate 2026-02-08 02:28:49 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule + +interface JackSonJsonConverter : JsonConverter { + + companion object { + /** + * 扩展ObjectMapper,用于注册指定类型的模块。 + * + * 此函数通过反射创建指定类型的实例,并调用其getJacksonModule方法来获取Jackson模块, + * 然后将该模块注册到当前ObjectMapper实例中。 + * + * @param T 必须继承自BaseJsonConverter的泛型类型。 + * @return 返回注册了模块后的ObjectMapper实例。 + */ + inline fun > ObjectMapper.addJsonConverter(): ObjectMapper = + this.registerModule(getJsonConverter().getJacksonModule()) + + @JvmStatic + fun > ObjectMapper.addJsonConverter(clazz: Class): ObjectMapper = + this.registerModule(getJsonConverter(clazz).getJacksonModule()) + } + + /** + * 创建并返回一个 Jackson 模块,该模块包含自定义的序列化器和反序列化器。 + * + * @return 配置了自定义序列化器和反序列化器的 SimpleModule 对象。 + */ + fun getJacksonModule(): SimpleModule = + SimpleModule("${getFromClass().name}To${getToClass().name}") + .addSerializer(getFromClass(), JackJsonSerializer(null, this)) + .addDeserializer(getFromClass(), JackJsonDeserializer(null, this)) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverter.kt new file mode 100644 index 0000000..d14ed29 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverter.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonConverter.kt + * LastUpdate 2026-02-07 22:30:18 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.json.converters.base + +import com.mingliqiye.utils.json.api.type.JsonTypeReference + +/** + * BaseJsonConverter 是一个通用的 JSON 转换器接口,用于定义对象之间的双向转换逻辑。 + * + * @param F 源类型,表示需要被转换的对象类型。 + * @param T 目标类型,表示转换后的对象类型。 + */ +interface JsonConverter { + /** + * 将源对象转换为目标对象。 + * + * @param obj 源对象,可能为 null。 + * @param annotationGetter 注解获取器,用于获取字段上的注解信息。 + * @return 转换后的目标对象,可能为 null。 + * @throws Exception 转换过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun convert(obj: F?, annotationGetter: AnnotationGetter): T? + + /** + * 将目标对象反向转换为源对象。 + * + * @param obj 目标对象,可能为 null。 + * @param annotationGetter 注解获取器,用于获取字段上的注解信息。 + * @return 反向转换后的源对象,可能为 null。 + * @throws Exception 转换过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun deConvert(obj: T?, annotationGetter: AnnotationGetter): F? + + /** + * 获取源类型的类型引用。 + * + * @return 源类型的 JsonTypeReference 对象。 + * @throws Exception 获取过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun getFromType(): JsonTypeReference + + /** + * 获取目标类型的类型引用。 + * + * @return 目标类型的 JsonTypeReference 对象。 + * @throws Exception 获取过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun getToType(): JsonTypeReference + + /** + * 获取源类型的原始类。 + * + * @return 源类型的 Class 对象。 + * @throws Exception 获取过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun getFromClass() = getFromType().getRawType() + + /** + * 获取目标类型的原始类。 + * + * @return 目标类型的 Class 对象。 + * @throws Exception 获取过程中可能抛出的异常。 + */ + @Throws(Exception::class) + fun getToClass() = getToType().getRawType() +} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverterUtils.kt b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverterUtils.kt new file mode 100644 index 0000000..9ea6890 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/json/converters/base/JsonConverterUtils.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JsonConverterUtils.kt + * LastUpdate 2026-02-07 22:33:09 + * UpdateUser MingLiPro + */ +@file:JvmName("JsonConverterUtils") + +package com.mingliqiye.utils.json.converters.base + + +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type + +val log = MingLiLoggerFactory.getLogger("com.mingliqiye.utils.json.converters.base.JsonConverterUtils") + +/** + * 获取给定类型的实际类对象。 + * + * @param type 类型对象,可以是Class、ParameterizedType或其他Type的实现。 + * @return 返回与给定类型对应的Class对象;如果无法解析,则返回null。 + */ +fun getClass(type: Type?): Class<*>? { + // 尝试将type直接转换为Class类型,如果失败则检查是否为ParameterizedType + val clazz: Class<*>? = type as? Class<*> ?: if (type is ParameterizedType) { + // 如果是ParameterizedType,则递归获取其原始类型 + getClass(type.rawType) + } else { + null + } + return clazz +} + +inline fun > getJsonConverter(): T = getJsonConverter(T::class.java) + +fun > getJsonConverter(clazz: Class): T { + try { + return clazz.getDeclaredMethod( + "getJsonConverter" + ).invoke(null) as T + } catch (e: Exception) { + log.error("实现于 JsonConverter<*, *> 的类 必须实现静态方法 JsonConverter<*, *> getJsonConverter()", e) + throw e + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLogger.kt similarity index 81% rename from src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt rename to src/main/kotlin/com/mingliqiye/utils/logger/MingLiLogger.kt index e75b366..a5605fc 100644 --- a/src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt +++ b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLogger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,32 +15,19 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile Loggers.kt - * LastUpdate 2025-09-18 09:30:48 + * CurrentFile MingLiLogger.kt + * LastUpdate 2026-02-06 08:27:44 * UpdateUser MingLiPro */ -@file:JvmName("Loggers") - package com.mingliqiye.utils.logger - import org.slf4j.Logger -import org.slf4j.LoggerFactory import org.slf4j.Marker -import java.util.* -enum class MingLiLoggerLevel { - TRACE, - DEBUG, - INFO, - WARN, - ERROR -} - -class MingLiLogger : Logger { +class MingLiLogger(private val name: String) : Logger { override fun getName(): String { - return "MingLiLogger" + return name } override fun isTraceEnabled(): Boolean { @@ -314,8 +301,7 @@ class MingLiLogger : Logger { override fun error(msg: String?, t: Throwable?) { msg?.let { - val message = if (t != null) "$it: ${t.message}" else it - toPrintln(message, MingLiLoggerLevel.ERROR) + toPrintln(it, MingLiLoggerLevel.ERROR) } } @@ -345,14 +331,18 @@ class MingLiLogger : Logger { fun toPrintln(message: String, level: MingLiLoggerLevel) { when (level) { - MingLiLoggerLevel.TRACE -> println("[TRACE] $message") - MingLiLoggerLevel.DEBUG -> println("[DEBUG] $message") - MingLiLoggerLevel.INFO -> println("[INFO] $message") - MingLiLoggerLevel.WARN -> println("[WARN] $message") - MingLiLoggerLevel.ERROR -> println("[ERROR] $message") + MingLiLoggerLevel.TRACE -> wirteToSteam("[TRACE] [$name] $message\n") + MingLiLoggerLevel.DEBUG -> wirteToSteam("[DEBUG] [$name] $message\n") + MingLiLoggerLevel.INFO -> wirteToSteam("[INFO] [$name] $message\n") + MingLiLoggerLevel.WARN -> wirteToSteam("[WARN] [$name] $message\n") + MingLiLoggerLevel.ERROR -> wirteToSteam("[ERROR] [$name] $message\n") } } + fun wirteToSteam(string: String) { + System.out.write(string.toByteArray()) + } + private fun format1(format: String, arg: Any?): String { return if (format.contains("{}")) { format.replaceFirst("{}", arg?.toString() ?: "null") @@ -374,48 +364,3 @@ class MingLiLogger : Logger { return result } } - -class MingLiLoggerFactory { - private var hasSLF4JImplementation: Boolean? = null - - // 线程安全的延迟初始化 - private fun checkSLF4JImplementation(): Boolean { - if (hasSLF4JImplementation == null) { - synchronized(this) { - if (hasSLF4JImplementation == null) { - hasSLF4JImplementation = try { - // 更可靠的检测方式 - ServiceLoader.load( - Class.forName("org.slf4j.spi.SLF4JServiceProvider") - ).iterator().hasNext() - } catch (e: ClassNotFoundException) { - false - } catch (e: NoClassDefFoundError) { - false - } - } - } - } - return hasSLF4JImplementation ?: false - } - - fun getLogger(name: String): Logger { - return if (checkSLF4JImplementation()) { - LoggerFactory.getLogger(name) - } else { - MingLiLogger() - } - } - - fun getLogger(clazz: Class<*>): Logger { - return if (checkSLF4JImplementation()) { - LoggerFactory.getLogger(clazz) - } else { - MingLiLogger() - } - } -} - -val mingLiLoggerFactory: MingLiLoggerFactory by lazy { MingLiLoggerFactory() } - - diff --git a/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerFactory.kt b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerFactory.kt new file mode 100644 index 0000000..b3b0834 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerFactory.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MingLiLoggerFactory.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.logger + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.lang.reflect.Method +import java.util.* + +class MingLiLoggerFactory { + + companion object { + + private var nameMethod: Method? = null + private var clazzMethod: Method? = null + + init { + try { + val clazz = Class.forName("com.mingliqiye.logger.Loggers") + nameMethod = clazz.getMethod("getLogger", String::class.java) + clazzMethod = clazz.getMethod("getLogger", Class::class.java) + } catch (e: Exception) { + } + } + + private val mingLiLoggerFactory: MingLiLoggerFactory by lazy { + MingLiLoggerFactory() + } + + + @JvmStatic + fun getLogger(name: String): Logger { + + return if (mingLiLoggerFactory.checkSLF4JImplementation()) { + if (nameMethod != null) { + nameMethod!!.invoke(null, name) as Logger + } else { + LoggerFactory.getLogger(name) + } + } else mingLiLoggerFactory.getLogger(name) + } + + @JvmStatic + fun getLogger(clazz: Class<*>): Logger { + return if (mingLiLoggerFactory.checkSLF4JImplementation()) { + if (clazzMethod != null) { + clazzMethod!!.invoke(null, clazz) as Logger + } else { + LoggerFactory.getLogger(clazz) + } + } else mingLiLoggerFactory.getLogger(clazz) + } + + inline fun getLogger() = getLogger(T::class.java) + } + + private var hasSLF4JImplementation: Boolean? = null + + // 线程安全的延迟初始化 + private fun checkSLF4JImplementation(): Boolean { + if (hasSLF4JImplementation == null) { + synchronized(this) { + if (hasSLF4JImplementation == null) { + hasSLF4JImplementation = try { + // 更可靠的检测方式 + ServiceLoader.load( + Class.forName("org.slf4j.spi.SLF4JServiceProvider") + ).iterator().hasNext() + } catch (e: ClassNotFoundException) { + false + } catch (e: NoClassDefFoundError) { + false + } + } + } + } + return hasSLF4JImplementation ?: false + } + + + @JvmName("getLogger_prc_name") + private fun getLogger(name: String): Logger = MingLiLogger(name) + + @JvmName("getLogger_prc_clazz") + private fun getLogger(clazz: Class<*>): Logger = MingLiLogger(clazz.name) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/main/Main.kt b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerLevel.kt similarity index 74% rename from src/main/kotlin/com/mingliqiye/utils/main/Main.kt rename to src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerLevel.kt index 6ff2225..5eee5ec 100644 --- a/src/main/kotlin/com/mingliqiye/utils/main/Main.kt +++ b/src/main/kotlin/com/mingliqiye/utils/logger/MingLiLoggerLevel.kt @@ -15,16 +15,17 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile Main.kt - * LastUpdate 2026-01-06 14:36:10 + * CurrentFile MingLiLoggerLevel.kt + * LastUpdate 2026-02-06 08:27:44 * UpdateUser MingLiPro */ -@file:JvmName("Main") -package com.mingliqiye.utils.main +package com.mingliqiye.utils.logger -import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration - -fun main() { - AutoConfiguration.printBanner() +enum class MingLiLoggerLevel { + TRACE, + DEBUG, + INFO, + WARN, + ERROR } diff --git a/src/main/kotlin/com/mingliqiye/utils/math/MathUtils.kt b/src/main/kotlin/com/mingliqiye/utils/math/MathUtils.kt new file mode 100644 index 0000000..fc61a27 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/math/MathUtils.kt @@ -0,0 +1,374 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MathUtils.kt + * LastUpdate 2026-02-05 10:25:32 + * UpdateUser MingLiPro + */ +@file:JvmName("MathUtils") + +package com.mingliqiye.utils.math + +import java.math.BigDecimal +import java.math.BigInteger + +/** + * BigDecimal减法运算符重载 - BigDecimal类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: BigDecimal): BigDecimal = this.subtract(value) + +/** + * BigDecimal减法运算符重载 - Long类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: Long): BigDecimal = this.subtract(BigDecimal(value)) + + +/** + * BigDecimal减法运算符重载 - Int类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: Int): BigDecimal = this.subtract(BigDecimal(value)) + +/** + * BigDecimal减法运算符重载 - Double类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: Double): BigDecimal = this.subtract(BigDecimal(value.toString())) + +/** + * BigDecimal减法运算符重载 - Float类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: Float): BigDecimal = this.subtract(BigDecimal(value.toString())) + +/** + * BigDecimal减法运算符重载 - BigInteger类型 + * @param value 被减数 + * @return 减法运算结果 + */ +operator fun BigDecimal.minus(value: BigInteger): BigDecimal = this.subtract(BigDecimal(value)) + +/** + * BigDecimal加法运算符重载 - BigDecimal类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: BigDecimal): BigDecimal = this.add(value) + +/** + * BigDecimal加法运算符重载 - Long类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: Long): BigDecimal = this.add(BigDecimal(value)) + +/** + * BigDecimal加法运算符重载 - Int类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: Int): BigDecimal = this.add(BigDecimal(value)) + +/** + * BigDecimal加法运算符重载 - Double类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: Double): BigDecimal = this.add(BigDecimal(value.toString())) + +/** + * BigDecimal加法运算符重载 - Float类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: Float): BigDecimal = this.add(BigDecimal(value.toString())) + +/** + * BigDecimal加法运算符重载 - BigInteger类型 + * @param value 加数 + * @return 加法运算结果 + */ +operator fun BigDecimal.plus(value: BigInteger): BigDecimal = this.add(BigDecimal(value)) + +/** + * BigDecimal乘法运算符重载 - BigDecimal类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: BigDecimal): BigDecimal = this.multiply(value) + +/** + * BigDecimal乘法运算符重载 - Long类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: Long): BigDecimal = this.multiply(BigDecimal(value)) + + +/** + * BigDecimal乘法运算符重载 - Int类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: Int): BigDecimal = this.multiply(BigDecimal(value)) + +/** + * BigDecimal乘法运算符重载 - Double类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: Double): BigDecimal = this.multiply(BigDecimal(value.toString())) + +/** + * BigDecimal乘法运算符重载 - Float类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: Float): BigDecimal = this.multiply(BigDecimal(value.toString())) + +/** + * BigDecimal乘法运算符重载 - BigInteger类型 + * @param value 乘数 + * @return 乘法运算结果 + */ +operator fun BigDecimal.times(value: BigInteger): BigDecimal = this.multiply(BigDecimal(value)) + +/** + * BigDecimal除法运算符重载 - BigDecimal类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div(value: BigDecimal): BigDecimal = this.divide(value) + +/** + * BigDecimal除法运算符重载 - Long类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div( + value: Long +): BigDecimal = this.divide(BigDecimal(value)) + +/** + * BigDecimal除法运算符重载 - Int类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div( + value: Int +): BigDecimal = this.divide(BigDecimal(value)) + +/** + * BigDecimal除法运算符重载 - Double类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div( + value: Double +): BigDecimal = this.divide(BigDecimal(value.toString())) + +/** + * BigDecimal除法运算符重载 - Float类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div( + value: Float +): BigDecimal = this.divide(BigDecimal(value.toString())) + +/** + * BigDecimal除法运算符重载 - BigInteger类型 + * @param value 除数 + * @return 除法运算结果 + */ +operator fun BigDecimal.div( + value: BigInteger +): BigDecimal = this.divide(BigDecimal(value)) + +/** + * BigDecimal取余运算符重载 - BigDecimal类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: BigDecimal): BigDecimal = this.remainder(value) + +/** + * BigDecimal取余运算符重载 - Long类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: Long): BigDecimal = this.remainder(BigDecimal(value)) + +/** + * BigDecimal取余运算符重载 - Int类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: Int): BigDecimal = this.remainder(BigDecimal(value)) + +/** + * BigDecimal取余运算符重载 - Double类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: Double): BigDecimal = this.remainder(BigDecimal(value.toString())) + +/** + * BigDecimal取余运算符重载 - Float类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: Float): BigDecimal = this.remainder(BigDecimal(value.toString())) + +/** + * BigDecimal取余运算符重载 - BigInteger类型 + * @param value 除数 + * @return 取余运算结果 + */ +operator fun BigDecimal.rem(value: BigInteger): BigDecimal = this.remainder(BigDecimal(value)) + +/** + * 将BigDecimal转换为去除末尾零的字符串表示 + * @return 去除末尾零后的字符串表示 + */ +fun BigDecimal.toFlexString(): String = this.stripTrailingZeros().toPlainString() + +/** + * 字符串转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun String.toBigDecimal(): BigDecimal = BigDecimal(this) + +/** + * Int转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Int.toBigDecimal(): BigDecimal = BigDecimal(this) + +/** + * Byte转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Byte.toBigDecimal(): BigDecimal = BigDecimal(this.toInt()) + +/** + * Short转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Short.toBigDecimal(): BigDecimal = BigDecimal(this.toInt()) + +/** + * Float转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Float.toBigDecimal(): BigDecimal = BigDecimal(this.toString()) + +/** + * Double转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Double.toBigDecimal(): BigDecimal = BigDecimal(this.toString()) + +/** + * Long转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun Long.toBigDecimal(): BigDecimal = BigDecimal(this) + +/** + * BigInteger转BigDecimal扩展函数 + * @return 转换后的BigDecimal对象 + */ +fun BigInteger.toBigDecimal(): BigDecimal = BigDecimal(this) + +/** + * 带精度设置的字符串转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun String.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this).setScale(scale) + +/** + * 带精度设置的Int转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Int.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this).setScale(scale) + +/** + * 带精度设置的Byte转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Byte.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this.toInt()).setScale(scale) + +/** + * 带精度设置的Short转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Short.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this.toInt()).setScale(scale) + +/** + * 带精度设置的Float转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Float.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this.toString()).setScale(scale) + +/** + * 带精度设置的Double转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Double.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this.toString()).setScale(scale) + +/** + * 带精度设置的Long转BigDecimal扩展函数 + * @param scale 小数位数 + * @return 转换后并设置精度的BigDecimal对象 + */ +fun Long.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this).setScale(scale) + +/** + * 将当前 Number 对象转换为 BigDecimal 类型。 + * + * @return 返回与当前 Number 对象等值的 BigDecimal 实例。 + */ +fun Number.toBigDecimal(): BigDecimal = BigDecimal(this.toString()) + +/** + * 将当前 Number 对象转换为 BigInteger 类型。 + * + * @return 返回与当前 Number 对象等值的 BigInteger 实例。 + */ +fun Number.toBigInteger(): BigInteger = BigInteger(this.toString()) + +/** + * 将当前 Number 对象转换为指定精度的 BigDecimal 类型。 + * + * @param scale 指定小数点后的位数(精度)。 + * @return 返回与当前 Number 对象等值且具有指定精度的 BigDecimal 实例。 + */ +fun Number.toBigDecimal(scale: Int): BigDecimal = BigDecimal(this.toString()).setScale(scale) diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/QuickBaseTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/QuickBaseTypeHandler.kt index 90d30bf..ddee32a 100644 --- a/src/main/kotlin/com/mingliqiye/utils/mybatis/QuickBaseTypeHandler.kt +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/QuickBaseTypeHandler.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile QuickBaseTypeHandler.kt - * LastUpdate 2026-01-08 07:59:47 + * LastUpdate 2026-01-28 10:01:35 * UpdateUser MingLiPro */ @@ -53,7 +53,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { ct: CallType, ci: Int?, cn: String? - ): T + ): T? /** * 抽象方法,用于将 Java 类型 T 设置到 PreparedStatement 中。 @@ -65,7 +65,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { * @throws SQLException SQL 执行异常时抛出 */ @Throws(SQLException::class) - abstract fun setValue(ps: PreparedStatement, index: Int, parameter: T, jdbcType: JdbcType?) + abstract fun setValue(ps: PreparedStatement, index: Int, parameter: T?, jdbcType: JdbcType?) /** * 实现 BaseTypeHandler 的 setNonNullParameter 方法, @@ -78,7 +78,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { * @throws SQLException SQL 执行异常时抛出 */ @Throws(SQLException::class) - override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T, jdbcType: JdbcType?) { + override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T?, jdbcType: JdbcType?) { setValue(ps, i, parameter, jdbcType) } @@ -92,7 +92,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { * @throws SQLException SQL 执行异常时抛出 */ @Throws(SQLException::class) - override fun getNullableResult(rs: ResultSet, columnName: String): T { + override fun getNullableResult(rs: ResultSet, columnName: String): T? { return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_NAME, null, columnName) } @@ -106,7 +106,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { * @throws SQLException SQL 执行异常时抛出 */ @Throws(SQLException::class) - override fun getNullableResult(rs: ResultSet, columnIndex: Int): T { + override fun getNullableResult(rs: ResultSet, columnIndex: Int): T? { return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_INDEX, columnIndex, null) } @@ -120,7 +120,7 @@ abstract class QuickBaseTypeHandler : BaseTypeHandler() { * @throws SQLException SQL 执行异常时抛出 */ @Throws(SQLException::class) - override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T { + override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T? { return getValue(QuickBaseTypeHandlerValueGetter(cs, null), CallType.CALLABLE_STATEMENT_INDEX, columnIndex, null) } } diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt index 523116b..ca64ba4 100644 --- a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile DateTimeTypeHandler.kt - * LastUpdate 2026-01-07 19:23:12 + * LastUpdate 2026-02-05 11:20:59 * UpdateUser MingLiPro */ @@ -30,6 +30,7 @@ import org.apache.ibatis.type.JdbcType import org.apache.ibatis.type.MappedTypes import java.sql.PreparedStatement import java.sql.Timestamp +import java.sql.Types.TIMESTAMP /** * DateTime类型处理器,用于在数据库和Java对象之间转换DateTime类型 @@ -42,22 +43,30 @@ class DateTimeTypeHandler : QuickBaseTypeHandler() { ct: CallType, ci: Int?, cn: String? - ): DateTime { + ): DateTime? { + val data = (when (ct) { + CallType.RESULTSET_INDEX -> vg.resultSet!!.getTimestamp(ci!!) + CallType.RESULTSET_NAME -> vg.resultSet!!.getTimestamp(cn!!) + CallType.CALLABLE_STATEMENT_INDEX -> vg.callableStatement!!.getTimestamp(ci!!) + }) + if (data == null) { + return null + } return DateTime.of( - (when (ct) { - CallType.RESULTSET_INDEX -> vg.resultSet!!.getTimestamp(ci!!) - CallType.RESULTSET_NAME -> vg.resultSet!!.getTimestamp(cn!!) - CallType.CALLABLE_STATEMENT_INDEX -> vg.callableStatement!!.getTimestamp(ci!!) - }) + data ) } override fun setValue( ps: PreparedStatement, index: Int, - parameter: DateTime, + parameter: DateTime?, jdbcType: JdbcType? ) { + if (parameter == null) { + ps.setNull(index, TIMESTAMP) + return + } ps.setTimestamp(index, Timestamp.valueOf(parameter.toLocalDateTime())) } } diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/mysql/uuid/MysqlUUIDBinaryTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/mysql/uuid/MysqlUUIDBinaryTypeHandler.kt index 14bc082..084194a 100644 --- a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/mysql/uuid/MysqlUUIDBinaryTypeHandler.kt +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/mysql/uuid/MysqlUUIDBinaryTypeHandler.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile MysqlUUIDBinaryTypeHandler.kt - * LastUpdate 2026-01-07 19:30:31 + * LastUpdate 2026-01-28 10:08:46 * UpdateUser MingLiPro */ @@ -59,19 +59,29 @@ class MysqlUUIDBinaryTypeHandler : QuickBaseTypeHandler() { override fun getValue( vg: QuickBaseTypeHandlerValueGetter, ct: CallType, ci: Int?, cn: String? - ): UUID { + ): UUID? { + + val data: ByteArray? = when (ct) { + CallType.RESULTSET_NAME -> vg.resultSet!!.getBytes(cn!!) + CallType.RESULTSET_INDEX -> vg.resultSet!!.getBytes(ci!!) + CallType.CALLABLE_STATEMENT_INDEX -> vg.resultSet!!.getBytes(ci!!) + } + if (data == null) { + return null + } + return toUUID( - when (ct) { - CallType.RESULTSET_NAME -> vg.resultSet!!.getBytes(cn!!) - CallType.RESULTSET_INDEX -> vg.resultSet!!.getBytes(ci!!) - CallType.CALLABLE_STATEMENT_INDEX -> vg.resultSet!!.getBytes(ci!!) - } - )!! + data + ) } override fun setValue( - ps: PreparedStatement, index: Int, parameter: UUID, jdbcType: JdbcType? + ps: PreparedStatement, index: Int, parameter: UUID?, jdbcType: JdbcType? ) { + if (parameter == null) { + ps.setNull(index, java.sql.Types.BINARY) + return + } ps.setBytes(index, toByteArray(parameter)) } diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/pgsql/uuid/PgsqlUUIDTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/pgsql/uuid/PgsqlUUIDTypeHandler.kt new file mode 100644 index 0000000..101a121 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/pgsql/uuid/PgsqlUUIDTypeHandler.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile PgsqlUUIDTypeHandler.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.mybatis.typehandler.pgsql.uuid + +import com.mingliqiye.utils.mybatis.CallType +import com.mingliqiye.utils.mybatis.QuickBaseTypeHandler +import com.mingliqiye.utils.mybatis.QuickBaseTypeHandlerValueGetter +import com.mingliqiye.utils.uuid.UUID +import org.apache.ibatis.type.JdbcType +import org.apache.ibatis.type.MappedTypes +import java.sql.PreparedStatement + +@MappedTypes(UUID::class) +class PgsqlUUIDTypeHandler : QuickBaseTypeHandler() { + override fun getValue( + vg: QuickBaseTypeHandlerValueGetter, ct: CallType, ci: Int?, cn: String? + ): UUID? { + val data: String? = when (ct) { + CallType.RESULTSET_INDEX -> + vg.resultSet!!.getString(ci!!) + + CallType.RESULTSET_NAME -> + vg.resultSet!!.getString(cn) + + CallType.CALLABLE_STATEMENT_INDEX -> + vg.callableStatement!!.getString(cn) + } + if (data == null) { + return null + } + return UUID.of(data) + } + + override fun setValue( + ps: PreparedStatement, index: Int, parameter: UUID?, jdbcType: JdbcType? + ) { + if (parameter == null) { + ps.setNull(index, jdbcType?.TYPE_CODE ?: JdbcType.JAVA_OBJECT.TYPE_CODE) + return + } + ps.setObject(index, parameter.getUuid()) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatisplus/BaseMapperQuery.kt b/src/main/kotlin/com/mingliqiye/utils/mybatisplus/BaseMapperQuery.kt new file mode 100644 index 0000000..5f5f6cd --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/mybatisplus/BaseMapperQuery.kt @@ -0,0 +1,156 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile BaseMapperQuery.kt + * LastUpdate 2026-02-06 13:15:11 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.mybatisplus + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper +import com.baomidou.mybatisplus.core.mapper.BaseMapper +import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper +import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper +import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper +import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper + + +@Deprecated( + "rename to FastBaseMapper", + replaceWith = ReplaceWith( + expression = "FastBaseMapper<*>", + imports = ["com.mingliqiye.utils.mybatisplus.FastBaseMapper"] + ), + level = DeprecationLevel.WARNING +) +/** + * @since 4.6.1 + * 已经重命名 [FastBaseMapper] + */ +interface BaseMapperQuery : FastBaseMapper + +/** + * 扩展[BaseMapper]接口,提供便捷的查询和更新包装器创建方法 + * 包含普通包装器、`Lambda`包装器和`Kotlin`专用包装器的创建方法 + */ +interface FastBaseMapper : BaseMapper { + /** + * 创建[QueryWrapper]实例 + * @return QueryWrapper 查询包装器实例 + */ + fun queryWrapper() = QueryWrapper() + + /** + * 创建[UpdateWrapper]实例 + * @return UpdateWrapper 更新包装器实例 + */ + fun updateWrapper() = UpdateWrapper() + + /** + * 创建[LambdaQueryWrapper]实例 + * @return LambdaQueryWrapper Lambda查询包装器实例 + */ + fun lambdaQueryWrapper() = LambdaQueryWrapper() + + /** + * 创建[LambdaUpdateWrapper]实例 + * @return LambdaUpdateWrapper Lambda更新包装器实例 + */ + fun lambdaUpdateWrapper() = LambdaUpdateWrapper() + + + companion object { + + /** + * 为[BaseMapper]创建[QueryWrapper]实例 + * @param T 范型类型,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return QueryWrapper 查询包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.queryWrapper(): QueryWrapper = QueryWrapper(T::class.java) + + /** + * 为[BaseMapper]创建[UpdateWrapper]实例 + * @param T 范型类型,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return UpdateWrapper 更新包装器实例 + */ + inline fun BaseMapper.updateWrapper(): UpdateWrapper = UpdateWrapper() + + /** + * 为[BaseMapper]创建[LambdaQueryWrapper]实例 + * @param T 范型类型,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return LambdaQueryWrapper Lambda查询包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.lambdaQueryWrapper(): LambdaQueryWrapper = + LambdaQueryWrapper(T::class.java) + + /** + * 为[BaseMapper]创建[LambdaUpdateWrapper]实例 + * @param T 范型类型,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return LambdaUpdateWrapper Lambda更新包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.lambdaUpdateWrapper(): LambdaUpdateWrapper = + LambdaUpdateWrapper(T::class.java) + + + /** + * 为[BaseMapper]创建[KtQueryWrapper]实例 + * @param T 范型类型,必须继承自Any,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return KtQueryWrapper Kotlin查询包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.ktQueryWrapper(): KtQueryWrapper = KtQueryWrapper(T::class.java) + + /** + * 为[BaseMapper]创建[KtQueryChainWrapper]实例 + * @param T 范型类型,必须继承自Any,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return KtQueryChainWrapper Kotlin查询链式包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.ktQueryChainWrapper(): KtQueryChainWrapper = + KtQueryChainWrapper(T::class.java) + + /** + * 为[BaseMapper]创建[KtUpdateWrapper]实例 + * @param T 范型类型,必须继承自Any,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return KtUpdateWrapper Kotlin更新包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.ktUpdateWrapper(): KtUpdateWrapper = + KtUpdateWrapper(T::class.java) + + /** + * 为[BaseMapper]创建[KtUpdateChainWrapper]实例 + * @param T 范型类型,必须继承自Any,通过reified获取实际类型 + * @receiver BaseMapper 基础映射器实例 + * @return KtUpdateChainWrapper Kotlin更新链式包装器实例,使用T类作为参数 + */ + inline fun BaseMapper.ktUpdateChainWrapper(): KtUpdateChainWrapper = + KtUpdateChainWrapper(T::class.java) + + + } + + +} diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt b/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt deleted file mode 100644 index 7403add..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/mybatisplus/QueryWrapper.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2026 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile QueryWrapper.kt - * LastUpdate 2026-01-14 13:00:31 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.mybatisplus - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper -import com.baomidou.mybatisplus.core.mapper.BaseMapper - -/** - * BaseMapperQuery接口扩展了BaseMapper,提供了通用的查询包装器功能 - * - * @param T 实体类类型 - */ -interface BaseMapperQuery : BaseMapper { - /** - * 创建并返回一个新的QueryWrapper实例 - * - * @return QueryWrapper 返回类型化的查询包装器实例 - */ - fun queryWrapper(): QueryWrapper { - return QueryWrapper() - } - - /** - * 创建并返回一个新的UpdateWrapper实例 - * - * @return UpdateWrapper 返回类型化的更新包装器实例 - */ - fun updateWrapper(): UpdateWrapper { - return UpdateWrapper() - } - - /** - * 创建并返回一个新的LambdaQueryWrapper实例 - * - * @return LambdaQueryWrapper 返回类型化的Lambda查询包装器实例 - */ - fun lambdaQueryWrapper(): LambdaQueryWrapper { - return LambdaQueryWrapper() - } - - /** - * 创建并返回一个新的LambdaUpdateWrapper实例 - * - * @return LambdaUpdateWrapper 返回类型化的Lambda更新包装器实例 - */ - fun lambdaUpdateWrapper(): LambdaUpdateWrapper { - return LambdaUpdateWrapper() - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/netty/ClientScheduleReconnect.kt b/src/main/kotlin/com/mingliqiye/utils/netty/ClientScheduleReconnect.kt index ee305aa..ead9f4e 100644 --- a/src/main/kotlin/com/mingliqiye/utils/netty/ClientScheduleReconnect.kt +++ b/src/main/kotlin/com/mingliqiye/utils/netty/ClientScheduleReconnect.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile ClientScheduleReconnect.kt - * LastUpdate 2026-01-08 10:45:37 + * LastUpdate 2026-01-20 08:10:15 * UpdateUser MingLiPro */ @@ -28,26 +28,128 @@ import io.netty.channel.ChannelFuture import io.netty.channel.ChannelFutureListener import java.util.concurrent.TimeUnit -abstract class ClientScheduleReconnect( - protected val bootstrap: Bootstrap, - protected var delay: Long = 10L, - protected var timeUnit: TimeUnit = TimeUnit.SECONDS -) { - protected var isStop = false - protected var channel: Channel? = null +/** + * 客户端调度重连抽象类,用于处理Netty客户端的自动重连机制 + * @param bootstrap Netty引导配置对象 + * @param delay 重连延迟时间,默认为10秒 + * @param timeUnit 延迟时间单位,默认为秒 + */ +abstract class ClientScheduleReconnect { + private val bootstrap: Bootstrap + private var delay: Long = 10L + private var timeUnit: TimeUnit = TimeUnit.SECONDS + constructor() : this(Bootstrap()) + constructor(bootstrap: Bootstrap) : this(bootstrap, 10L) + constructor(bootstrap: Bootstrap, delay: Long) : this(bootstrap, delay, TimeUnit.SECONDS) + constructor(bootstrap: Bootstrap, delay: Long, timeUnit: TimeUnit) { + this.bootstrap = bootstrap + this.delay = delay + this.timeUnit = timeUnit + } + + open fun start() { + initBootstrap(bootstrap) + connect() + } + + /** + * 获取Netty引导配置对象 + * @return Bootstrap 引导配置对象 + */ + open fun getBootstrap(): Bootstrap = bootstrap + + /** + * 获取当前连接的通道 + * @return Channel? 当前连接的通道,可能为空 + */ + open fun getChannel(): Channel? = channel + + /** + * 获取时间单位 + * @return TimeUnit 时间单位 + */ + open fun getTimeUnit(): TimeUnit = timeUnit + + /** + * 设置时间单位 + * @param timeUnit 新的时间单位 + */ + open fun setTimeUnit(timeUnit: TimeUnit) { + this.timeUnit = timeUnit + } + + /** + * 获取重连延迟时间 + * @return Long 延迟时间 + */ + open fun getDelay(): Long = delay + + /** + * 设置重连延迟时间 + * @param delay 新的延迟时间 + */ + open fun setDelay(delay: Long) { + this.delay = delay + } + + /** + * 检查是否已连接 + * @return Boolean 是否已连接 + */ + open fun isConnected(): Boolean = channel?.isActive ?: false + + private var isStop = false + private var channel: Channel? = null + + /** + * 连接成功时的日志记录回调 + * @param channel 成功连接的通道 + */ abstract fun onConnectedLog(channel: Channel) + + /** + * 连接失败时的日志记录回调 + * @param cause 连接失败的原因,可能为空 + */ abstract fun onConnectFailedLog(cause: Throwable?) + + /** + * 停止连接时的日志记录回调 + */ abstract fun onStoppedLog() + abstract fun onConnectClosed() + + /** + * 执行连接操作 + * @return ChannelFuture 连接结果的异步操作对象 + */ abstract fun doConnect(): ChannelFuture + /** + * 初始化引导配置 + * @param bootstrap 要初始化的引导配置对象 + */ + open fun initBootstrap(bootstrap: Bootstrap) { + + } + + /** + * 更新重连延迟配置 + * @param newDelay 新的延迟时间,必须大于0 + * @param newTimeUnit 新的时间单位 + * @throws IllegalArgumentException 当newDelay小于等于0时抛出 + */ open fun updateReconnectDelay(newDelay: Long, newTimeUnit: TimeUnit) { require(newDelay > 0) { "Delay must be positive" } this.delay = newDelay this.timeUnit = newTimeUnit } + /** + * 执行连接操作,设置连接完成监听器 + */ open fun connect() { doConnect().addListener(object : ChannelFutureListener { override fun operationComplete(future: ChannelFuture) { @@ -60,24 +162,33 @@ abstract class ClientScheduleReconnect( }) } - + /** + * 停止连接并标记为停止状态 + */ open fun stop() { isStop = true disConnect() } + /** + * 断开当前连接并清理通道引用 + */ open fun disConnect() { channel?.close() channel = null } - + /** + * 调度下一次重连操作 + */ open fun scheduleReconnect() { + // 检查是否已停止,如果已停止则记录日志并返回 if (isStop) { onStoppedLog() return } bootstrap.config().group().schedule({ + // 再次检查停止状态,避免在调度期间被停止 if (isStop) { onStoppedLog() return@schedule @@ -86,20 +197,27 @@ abstract class ClientScheduleReconnect( }, delay, timeUnit) } + /** + * 处理连接成功的逻辑 + * @param channel 成功连接的通道 + */ open fun onConnected(channel: Channel) { this.channel = channel onConnectedLog(channel) + // 监听通道关闭事件,以便在断开后重新调度连接 channel.closeFuture().addListener { _ -> scheduleReconnect() + onConnectClosed() } } + /** + * 处理连接失败的逻辑 + * @param cause 连接失败的原因 + */ open fun onConnectFailed(cause: Throwable?) { onConnectFailedLog(cause) scheduleReconnect() } - open fun isConnected(): Boolean { - return channel?.isActive ?: false - } } diff --git a/src/main/kotlin/com/mingliqiye/utils/netty/NamedNioEventLoopGroup.kt b/src/main/kotlin/com/mingliqiye/utils/netty/NamedNioEventLoopGroup.kt new file mode 100644 index 0000000..3c32db6 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/netty/NamedNioEventLoopGroup.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NamedNioEventLoopGroup.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.netty + +import com.mingliqiye.utils.system.availableProcessors +import io.netty.channel.nio.NioEventLoopGroup +import java.text.MessageFormat + +/** + * 命名的NIO事件循环组,继承自NioEventLoopGroup + * 用于创建具有自定义命名规则的线程池,便于线程管理和调试 + * + * @param name 线程池的名称,默认为"NioEventLoopGroup" + * @param template 线程名称的格式模板,默认为"{0}-{2}-{3}",{0} 名字 {1} 类名 {2} 线程池序号 {3} 线程池内线程的序号 + * @param nThreads 线程数量,默认为核心数的2倍 + */ +open class NamedNioEventLoopGroup( + val template: String = "{0}-{2}-{3}", + val name: String = "NioEventLoopGroup", + nThreads: Int = availableProcessors * 2 +) : + NioEventLoopGroup( + nThreads, + NamedThreadFactory( + getName = { a, b, c -> MessageFormat.format(template, name, a, b, c) } + ) + ) diff --git a/src/main/kotlin/com/mingliqiye/utils/netty/NamedThreadFactory.kt b/src/main/kotlin/com/mingliqiye/utils/netty/NamedThreadFactory.kt index 7e52a9a..6d1898c 100644 --- a/src/main/kotlin/com/mingliqiye/utils/netty/NamedThreadFactory.kt +++ b/src/main/kotlin/com/mingliqiye/utils/netty/NamedThreadFactory.kt @@ -16,17 +16,19 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile NamedThreadFactory.kt - * LastUpdate 2026-01-08 13:21:00 + * LastUpdate 2026-01-31 21:05:02 * UpdateUser MingLiPro */ package com.mingliqiye.utils.netty -import io.netty.util.concurrent.FastThreadLocalThread import java.util.concurrent.ThreadFactory import java.util.concurrent.atomic.AtomicInteger - +/** + * 命名线程工厂类,用于创建具有自定义名称的线程 + * @param getName 用于获取线程名称的回调函数接口 + */ open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter) : ThreadFactory { companion object { @@ -34,15 +36,33 @@ open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter) @JvmStatic private val allThreadPoolNumber = AtomicInteger(0) + /** + * 函数式接口,用于定义线程名称生成规则 + */ @FunctionalInterface fun interface NamedThreadFactoryNameGetter { + /** + * 获取线程名称 + * @param clazz 线程工厂类 + * @param poolNumber 线程池编号 + * @param threadNumber 线程编号 + * @return 生成的线程名称 + */ fun getName(clazz: Class, poolNumber: Int, threadNumber: Int): String } + /** + * 默认的线程名称生成器 + */ @JvmStatic val defaultGetName = NamedThreadFactoryNameGetter { clazz, poolNumber, threadNumber -> "${clazz.simpleName}-$poolNumber-$threadNumber" } + /** + * 创建命名线程工厂实例 + * @param name 线程名称前缀 + * @return NamedThreadFactory实例 + */ @JvmStatic fun of(name: String): NamedThreadFactory { return NamedThreadFactory { a, b, c -> @@ -50,24 +70,42 @@ open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter) } } + /** + * 创建命名线程工厂实例 + * @param getter 线程名称生成器,默认使用defaultGetName + * @return NamedThreadFactory实例 + */ @JvmStatic fun of(getter: NamedThreadFactoryNameGetter = defaultGetName): NamedThreadFactory { return NamedThreadFactory(getter) } } - + // 当前线程工厂的线程计数器 private val threadNumber = AtomicInteger(0) + + // 全局线程池计数器,用于标识不同的线程池 private val threadPoolNumber = allThreadPoolNumber.addAndGet(1) + /** + * 获取线程名称 + * @param clazz 线程工厂类 + * @param poolNumber 线程池编号 + * @param threadNumber 线程编号 + * @return 生成的线程名称 + */ open fun getThreadName(clazz: Class, poolNumber: Int, threadNumber: Int) = getName.getName(clazz, poolNumber, threadNumber) + /** + * 创建新线程 + * @param r 线程执行的任务 + * @return 新创建的线程对象 + */ override fun newThread(r: Runnable): Thread { - return FastThreadLocalThread( - null, - r, - getThreadName(this.javaClass, threadPoolNumber, threadNumber.addAndGet(1)) - ) + return Thread(r).let { + it.name = getThreadName(this.javaClass, threadPoolNumber, threadNumber.addAndGet(1)) + it + } } } diff --git a/src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt b/src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt index 1fc4519..bcf99ab 100644 --- a/src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile NettyUtils.kt - * LastUpdate 2026-01-07 10:00:31 + * LastUpdate 2026-01-31 20:50:41 * UpdateUser MingLiPro */ @@ -24,9 +24,15 @@ package com.mingliqiye.utils.netty +import com.mingliqiye.utils.functions.P1Function +import io.netty.bootstrap.Bootstrap +import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBuf import io.netty.buffer.Unpooled +import io.netty.channel.Channel +import io.netty.channel.ChannelInitializer import java.nio.ByteBuffer +import java.nio.charset.Charset /** * 将ByteBuffer转换为Netty的ByteBuf对象 @@ -79,3 +85,206 @@ fun ByteBuf.toByteArray(): ByteArray { fun ByteArray.toByteBuf(): ByteBuf { return Unpooled.wrappedBuffer(this) } + +/** + * 为ServerBootstrap配置子通道初始化器 + * + * 该函数用于设置ServerBootstrap的childHandler,当新的客户端连接建立时, + * 会调用提供的函数来初始化子通道 + * + * @receiver ServerBootstrap 需要配置的服务器引导程序实例 + * @param funa 用于初始化通道的回调函数,接收Channel作为参数 + * @return ServerBootstrap 返回当前实例以支持链式调用 + */ +@JvmName("channelInit") +fun ServerBootstrap.channelInitializer(funa: P1Function): ServerBootstrap { + this.childHandler(object : ChannelInitializer() { + override fun initChannel(ch: Channel) { + funa.call(ch) + } + }) + return this +} + +/** + * 为Bootstrap配置通道初始化器 + * + * 该函数用于设置Bootstrap的handler,当客户端连接建立时, + * 会调用提供的函数来初始化通道 + * + * @receiver Bootstrap 需要配置的客户端引导程序实例 + * @param funa 用于初始化通道的回调函数,接收Channel作为参数 + * @return Bootstrap 返回当前实例以支持链式调用 + */ +@JvmName("channelInit") +fun Bootstrap.channelInitializer(funa: P1Function): Bootstrap { + this.handler(object : ChannelInitializer() { + override fun initChannel(ch: Channel) { + funa.call(ch) + } + }) + return this +} + +/** + * 将字符串转换为Netty的ByteBuf对象 + * + * @receiver String 需要转换的原始字符串 + * @param charset 字符编码,默认UTF-8 + * @return ByteBuf 转换后的Netty ByteBuf对象 + */ +fun String.toByteBuf(charset: Charset = Charsets.UTF_8): ByteBuf { + return Unpooled.wrappedBuffer(this.toByteArray(charset)) +} + +/** + * 将ByteBuf转换为字符串 + * + * @receiver ByteBuf 需要转换的ByteBuf对象 + * @param charset 字符编码,默认UTF-8 + * @return String 转换后的字符串 + */ +fun ByteBuf.toString(charset: Charset = Charsets.UTF_8): String { + val bytes = this.toByteArray() + return String(bytes, charset) +} + + +/** + * 将Int转换为ByteBuf + * + * @receiver Int 需要转换的整数值 + * @return ByteBuf 转换后的Netty ByteBuf对象,包含4字节的整数数据 + */ +fun Int.toByteBuf(): ByteBuf { + val buffer = Unpooled.buffer(4) + buffer.writeInt(this) + return buffer +} + +/** + * 将Long转换为ByteBuf + * + * @receiver Long 需要转换的长整数值 + * @return ByteBuf 转换后的Netty ByteBuf对象,包含8字节的长整数数据 + */ +fun Long.toByteBuf(): ByteBuf { + val buffer = Unpooled.buffer(8) + buffer.writeLong(this) + return buffer +} + +/** + * 将ByteBuf转换为Int + * + * @receiver ByteBuf 需要转换的ByteBuf对象 + * @return Int 从ByteBuf中读取的整数值 + */ +fun ByteBuf.toInt(): Int { + return this.readInt() +} + +/** + * 将ByteBuf转换为Long + * + * @receiver ByteBuf 需要转换的ByteBuf对象 + * @return Long 从ByteBuf中读取的长整数值 + */ +fun ByteBuf.toLong(): Long { + return this.readLong() +} + +/** + * 安全地获取ByteBuf的字节数组,避免堆外内存访问异常 + * + * @receiver ByteBuf 需要转换的ByteBuf对象 + * @return ByteArray 转换后的字节数组 + */ +fun ByteBuf.safeToByteArray(): ByteArray { + return if (this.hasArray()) { + // 如果是堆内内存,直接获取数组 + this.array().copyOfRange(this.arrayOffset(), this.arrayOffset() + this.readableBytes()) + } else { + // 如果是堆外内存,使用readBytes + val array = ByteArray(this.readableBytes()) + this.getBytes(this.readerIndex(), array) + array + } +} + +/** + * 获取ByteBuf的十六进制字符串表示 + * + * @receiver ByteBuf 需要转换的ByteBuf对象 + * @return String 十六进制字符串表示 + */ +fun ByteBuf.toHexString(): String { + val array = this.safeToByteArray() + return array.joinToString("") { "%02x".format(it) } +} + +/** + * 合并多个ByteBuf为一个 + * + * @param byteBufs 需要合并的ByteBuf数组 + * @return ByteBuf 合并后的ByteBuf对象 + */ +fun combineByteBuf(vararg byteBufs: ByteBuf): ByteBuf { + val totalCapacity = byteBufs.sumOf { it.readableBytes() } + val combined = Unpooled.buffer(totalCapacity) + byteBufs.forEach { combined.writeBytes(it.duplicate()) } + return combined +} + +/** + * 安全关闭通道 + */ +fun Channel.closeSafely() { + if (isOpen) { + close() + } +} + +/** + * 检查通道是否处于活跃状态 + */ +val Channel.isActive: Boolean + get() = isOpen && isActive + +/** + * 异步写入数据到通道 + * + * @param data 需要写入的数据 + */ +fun Channel.writeAndFlushAsync(data: Any) { + writeAndFlush(data).addListener { future -> + if (!future.isSuccess) { + // 可以在这里添加错误处理逻辑 + println("Write failed: ${future.cause()}") + } + } +} + +/** + * 安全释放ByteBuf资源 + * + * @receiver ByteBuf 需要释放的ByteBuf对象 + * @return Boolean 释放操作是否成功 + */ +fun ByteBuf.releaseSafely(): Boolean { + return if (refCnt() > 0) release() else true +} + +/** + * 尝试释放ByteBuf资源,不抛出异常 + * + * @receiver ByteBuf 需要释放的ByteBuf对象 + * @return Boolean 释放操作是否成功 + */ +fun ByteBuf.tryRelease(): Boolean { + return try { + if (refCnt() > 0) release() else false + } catch (e: Exception) { + false + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/network/AddressPort.kt b/src/main/kotlin/com/mingliqiye/utils/network/AddressPort.kt deleted file mode 100644 index 88b210f..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/network/AddressPort.kt +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright 2026 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile AddressPort.kt - * LastUpdate 2026-01-06 14:03:47 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.network - -import com.mingliqiye.utils.string.join -import java.io.Serializable -import java.net.InetAddress -import java.net.InetSocketAddress -import java.net.UnknownHostException -import java.nio.ByteBuffer -import java.util.regex.Pattern - -/** - * 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。 - * 支持IPv4和IPv6地址的解析与验证。 - * - * @author MingLiPro - */ -class NetworkAddress private constructor(domip: String) : Serializable { - - /** - * IPv6标识 - */ - companion object { - const val IPV6 = 6 - - /** - * IPv4标识 - */ - const val IPV4 = 4 - - /** - * IPv4地址正则表达式 - */ - private const val IPV4REG = - "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$" - - /** - * 编译后的IPv4地址匹配模式 - */ - private val IPV4_PATTERN = Pattern.compile(IPV4REG) - - /** - * IPv6地址正则表达式 - */ - private const val IPV6REG = - "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + "|" + "^(::)$|" + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$" - - /** - * 编译后的IPv6地址匹配模式 - */ - private val IPV6_PATTERN = Pattern.compile(IPV6REG) - - /** - * 静态工厂方法,创建 NetworkAddress 实例。 - * - * @param domip 可能是IP地址或域名的字符串 - * @return 新建的 NetworkAddress 实例 - */ - @JvmStatic - fun of(domip: String): NetworkAddress { - return NetworkAddress(domip) - } - - @JvmStatic - fun ofIpv4(byteBuffer: ByteBuffer): NetworkAddress { - val byteArray = ByteArray(4) - byteBuffer.get(byteArray) - return ofIpv4(byteArray) - } - - @JvmStatic - fun ofIpv4(byteArray: ByteArray): NetworkAddress { - return of(".".join(byteArray.map { - (it.toInt() and 0xFF).toString() - })) - } - - /** - * 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。 - * - * @param inetAddress InetAddress 对象 - * @return 新建的 NetworkAddress 实例 - */ - @JvmStatic - fun of(inetAddress: InetAddress): NetworkAddress { - return NetworkAddress(inetAddress.hostAddress) - } - - /** - * 从DNS服务器解析域名获取对应的IP地址。 - * - * @param domain 域名 - * @return 解析出的第一个IP地址 - * @throws UnknownHostException 如果域名无法解析 - */ - @JvmStatic - @Throws(UnknownHostException::class) - fun getHostIp(domain: String): String { - val addresses = InetAddress.getAllByName(domain.trim()) - return addresses[0].hostAddress - } - - /** - * 检测给定字符串是否为有效的IPv4或IPv6地址。 - * - * @param ip 要检测的IP地址字符串 - * @return 4 表示IPv4,6 表示IPv6 - * @throws NetworkException 如果IP格式无效 - */ - @JvmStatic - fun testIp(ip: String?): Int { - if (ip == null) { - throw NetworkException("IP地址不能为null") - } - val trimmedIp = ip.trim() - - // 判断是否匹配IPv4格式 - if (IPV4_PATTERN.matcher(trimmedIp).matches()) { - return IPV4 - } - - // 判断是否匹配IPv6格式 - if (IPV6_PATTERN.matcher(trimmedIp).matches()) { - return IPV6 - } - - // 不符合任一格式时抛出异常 - throw NetworkException( - "[$ip] 不是有效的IPv4或IPv6地址" - ) - } - } - - /** - * IP地址类型:4 表示 IPv4,6 表示 IPv6 - */ - var iPv: Int = 0 - private set - - /** - * IP地址字符串 - */ - var ip: String? = null - private set - - /** - * 域名(如果输入的是域名) - */ - private var domain: String? = null - - /** - * 标识是否是域名解析来的IP - */ - private var isdom = false - - /** - * 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。 - * - * @param domip 可能是IP地址或域名的字符串 - */ - init { - try { - // 尝试将输入识别为IP地址 - this.iPv = testIp(domip) - this.ip = domip - } catch (e: NetworkException) { - try { - // 如果不是有效IP,则尝试作为域名解析 - val ips = getHostIp(domip) - this.iPv = testIp(ips) - this.ip = ips - this.isdom = true - this.domain = domip - } catch (ex: UnknownHostException) { - throw NetworkException(ex) - } - } - } - - /** - * 将IPv4地址转换为字节数组 - * - * @return 返回表示IPv4地址的4字节数组 - * @throws NetworkException 当当前地址不是IPv4地址时抛出异常 - */ - fun toIpv4ByteArray(): ByteArray { - // 验证地址类型是否为IPv4 - if (iPv != IPV4) { - throw NetworkException("该地址 不是IPv4地址") - } - // 将IP地址字符串按点分割,转换为整数并进行位运算处理,最后转为字节数组 - return ip!!.split(".").map { it.toInt() and 0xFF }.map { it.toByte() }.toByteArray() - } - - /** - * 将IPv4地址写入到指定的ByteBuffer中 - * - * @param byteBuffer 要写入的ByteBuffer对象,IPv4地址将以字节数组形式写入到该缓冲区 - * @return 返回写入了IPv4地址的ByteBuffer对象,便于链式调用 - */ - fun writeIpv4ToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { - return byteBuffer.put(toIpv4ByteArray()) - } - - /** - * 将当前 NetworkAddress 转换为 InetAddress 对象。 - * - * @return InetAddress 对象 - */ - fun toInetAddress(): InetAddress { - try { - return InetAddress.getByName(if (ip != null) ip else domain) - } catch (e: UnknownHostException) { - throw RuntimeException(e) - } - } - - /** - * 返回 NetworkAddress 的字符串表示形式。 - * - * @return 字符串表示 - */ - override fun toString(): String { - return if (isdom) "NetworkAddress(IP='$ip',type='$iPv',domain='$domain')" - else "NetworkAddress(IP='$ip',type='$iPv')" - } -} - - -class NetworkPort : Serializable { - val port: Int - - constructor(port: Int) { - testPort(port) - this.port = port - } - - fun toByteArray(): ByteArray { - val byteArray = ByteArray(2) - byteArray[0] = (port shr 8 and 0xFF).toByte() - byteArray[1] = (port and 0xFF).toByte() - return byteArray - } - - fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { - return byteBuffer.put(toByteArray()) - } - - companion object { - - /** - * 创建NetworkPort实例 - * @param port 端口号 - * @return NetworkPort实例 - */ - @JvmStatic - fun of(port: Int): NetworkPort { - return NetworkPort(port) - } - - /** - * 从字节数组创建NetworkPort实例 - * @param byteArray 包含端口信息的字节数组(长度至少为2) - * @return NetworkPort实例 - */ - @JvmStatic - fun of(byteArray: ByteArray): NetworkPort { - // 将字节数组的前两个字节转换为端口号 - val port = ((byteArray[0].toInt() and 0xFF) shl 8) or (byteArray[1].toInt() and 0xFF) - return of(port) - } - - /** - * 从ByteBuffer创建NetworkPort实例 - * @param byteBuffer 包含端口信息的ByteBuffer - * @return NetworkPort实例 - */ - @JvmStatic - fun of(byteBuffer: ByteBuffer): NetworkPort { - val byteArray = ByteArray(2) - byteBuffer.get(byteArray) - return of(byteArray) - } - - @JvmStatic - fun testPort(port: Int) { - // 验证端口号范围是否在0-65535之间 - if (port !in 0..65535) { - throw NetworkException("$port 不是正确的端口号") - } - } - } -} - -class NetworkException : RuntimeException { - /** - * 构造一个带有指定详细消息的网络异常 - * - * @param message 异常的详细消息 - */ - constructor(message: String?) : super(message) - - /** - * 构造一个网络异常,指定原因异常 - * - * @param e 导致此异常的原因异常 - */ - constructor(e: Exception?) : super(e) -} - -/** - * IP和端口聚集类,用于封装网络地址与端口信息。 - * 该类提供了与InetSocketAddress之间的相互转换功能。 - * - * @author MingLiPro - * @see java.net.InetSocketAddress - */ -class NetworkEndpoint private constructor( - val networkAddress: NetworkAddress, val networkPort: NetworkPort -) : Serializable { - - - companion object { - /** - * 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。 - * - * @param address InetSocketAddress对象 - * @return 新建的NetworkEndpoint实例 - * @see java.net.InetSocketAddress - */ - @JvmStatic - fun of(address: InetSocketAddress): NetworkEndpoint { - return NetworkEndpoint( - NetworkAddress.of(address.hostString), NetworkPort(address.port) - ) - } - - /** - * 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。 - * - * @param s 主机名或IP地址字符串 - * @param i 端口号 - * @return 新建的NetworkEndpoint实例 - */ - @JvmStatic - fun of(s: String, i: Int): NetworkEndpoint { - val networkAddress = NetworkAddress.of(s) - val networkPort = NetworkPort(i) - return NetworkEndpoint(networkAddress, networkPort) - } - - /** - * 从字节数组创建IPv4网络端点 - * - * @param byteArray 包含IPv4地址和端口信息的字节数组,前4个字节表示IP地址,后2个字节表示端口号 - * @return NetworkEndpoint对象,封装了IPv4地址和端口信息 - */ - @JvmStatic - fun ofIpv4(byteArray: ByteArray): NetworkEndpoint { - // 提取前4个字节作为IP地址 - val address = ByteArray(4) { - byteArray[it] - } - // 提取后2个字节作为端口号 - val portInt = ByteArray(2) { - byteArray[it + 4] - } - return NetworkEndpoint(NetworkAddress.ofIpv4(address), NetworkPort.of(portInt)) - } - - /** - * 从字节缓冲区创建IPv4网络端点实例 - * - * 该方法从给定的ByteBuffer中读取数据,构建一个包含IPv4地址和端口的网络端点对象。 - * 该方法按照协议顺序从缓冲区中读取IPv4地址数据和端口数据。 - * - * @param byteBuffer 包含IPv4地址和端口数据的字节缓冲区,缓冲区中的数据应按照先地址后端口的顺序排列 - * @return 返回一个NetworkEndpoint实例,包含从缓冲区解析出的IPv4地址和端口信息 - */ - @JvmStatic - fun ofIpv4(byteBuffer: ByteBuffer): NetworkEndpoint { - return NetworkEndpoint( - NetworkAddress.ofIpv4(byteBuffer), - NetworkPort.of(byteBuffer) - ) - } - - /** - * 根据"host:port"格式的字符串创建NetworkEndpoint实例。 - * 例如:"127.0.0.1:8080" - * - * @param s "host:port"格式的字符串 - * @return 新建的NetworkEndpoint实例 - */ - @JvmStatic - fun of(s: String): NetworkEndpoint { - val lastColonIndex = s.lastIndexOf(':') - return of( - s.take(lastColonIndex), s.substring(lastColonIndex + 1).toInt() - ) - } - } - - /** - * 将当前NetworkEndpoint转换为InetSocketAddress对象。 - * - * @return 对应的InetSocketAddress对象 - * @see InetSocketAddress - */ - fun toInetSocketAddress(): InetSocketAddress { - return InetSocketAddress( - networkAddress.toInetAddress(), networkPort.port - ) - } - - /** - * 将当前NetworkEndpoint转换为"host:port"格式的字符串。 - * 例如:"127.0.0.1:25563" - * - * @return 格式化后的字符串 - */ - fun toHostPortString(): String { - return "${networkAddress.ip}:${networkPort.port}" - } - - /** - * 返回NetworkEndpoint的详细字符串表示形式。 - * 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...) - * - * @return 包含详细信息的字符串 - */ - override fun toString(): String { - return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port})" - } - - /** - * 获取主机名或IP地址字符串。 - * - * @return 主机名或IP地址 - */ - fun host(): String { - return networkAddress.ip ?: "" - } - - /** - * 获取端口号。 - * - * @return 端口号 - */ - fun port(): Int { - return networkPort.port - } - - /** - * 将网络地址和端口转换为IPv4字节数组 - * - * 该函数将当前对象的网络地址转换为IPv4字节数组,并与端口字节数组合并, - * 生成一个包含6个字节的数组,其中前4个字节为IPv4地址,后2个字节为端口号 - * - * @return ByteArray 包含6个字节的数组,前4个字节为IPv4地址,后2个字节为端口号 - */ - fun toIpv4ByteArray(): ByteArray { - val ipv4ByteArray = networkAddress.toIpv4ByteArray() - val portByteArray = networkPort.toByteArray() - // 构建包含IPv4地址和端口的6字节数组 - val byteArray = ByteArray(6) { - if (it < 4) { - ipv4ByteArray[it] - } else { - portByteArray[it - 4] - } - } - return byteArray - } - - /** - * 将IPv4地址和端口信息写入字节缓冲区 - * - * 该函数依次将网络地址的IPv4表示和网络端口写入到指定的字节缓冲区中 - * - * @param byteBuffer 要写入数据的目标字节缓冲区 - */ - fun writeIpv4toByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { - networkAddress.writeIpv4ToByteBuffer(byteBuffer) - networkPort.writeToByteBuffer(byteBuffer) - return byteBuffer - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/network/NetworkAddress.kt b/src/main/kotlin/com/mingliqiye/utils/network/NetworkAddress.kt new file mode 100644 index 0000000..20f2f12 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/network/NetworkAddress.kt @@ -0,0 +1,247 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NetworkAddress.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.network + +import com.mingliqiye.utils.string.join +import java.io.Serializable +import java.net.InetAddress +import java.net.UnknownHostException +import java.nio.ByteBuffer +import java.util.regex.Pattern + +/** + * 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。 + * 支持IPv4和IPv6地址的解析与验证。 + * + * @author MingLiPro + */ +class NetworkAddress private constructor(domip: String) : Serializable { + + /** + * IPv6标识 + */ + companion object { + const val IPV6 = 6 + + /** + * IPv4标识 + */ + const val IPV4 = 4 + + /** + * IPv4地址正则表达式 + */ + private const val IPV4REG = + "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$" + + /** + * 编译后的IPv4地址匹配模式 + */ + private val IPV4_PATTERN = Pattern.compile(IPV4REG) + + /** + * IPv6地址正则表达式 + */ + private const val IPV6REG = + "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + "|" + "^(::)$|" + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$" + + /** + * 编译后的IPv6地址匹配模式 + */ + private val IPV6_PATTERN = Pattern.compile(IPV6REG) + + /** + * 静态工厂方法,创建 NetworkAddress 实例。 + * + * @param domip 可能是IP地址或域名的字符串 + * @return 新建的 NetworkAddress 实例 + */ + @JvmStatic + fun of(domip: String): NetworkAddress { + return NetworkAddress(domip) + } + + @JvmStatic + fun ofIpv4(byteBuffer: ByteBuffer): NetworkAddress { + val byteArray = ByteArray(4) + byteBuffer.get(byteArray) + return ofIpv4(byteArray) + } + + @JvmStatic + fun ofIpv4(byteArray: ByteArray): NetworkAddress { + return of(".".join(byteArray.map { + (it.toInt() and 0xFF).toString() + })) + } + + /** + * 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。 + * + * @param inetAddress InetAddress 对象 + * @return 新建的 NetworkAddress 实例 + */ + @JvmStatic + fun of(inetAddress: InetAddress): NetworkAddress { + return NetworkAddress(inetAddress.hostAddress) + } + + /** + * 从DNS服务器解析域名获取对应的IP地址。 + * + * @param domain 域名 + * @return 解析出的第一个IP地址 + * @throws java.net.UnknownHostException 如果域名无法解析 + */ + @JvmStatic + @Throws(UnknownHostException::class) + fun getHostIp(domain: String): String { + val addresses = InetAddress.getAllByName(domain.trim()) + return addresses[0].hostAddress + } + + /** + * 检测给定字符串是否为有效的IPv4或IPv6地址。 + * + * @param ip 要检测的IP地址字符串 + * @return 4 表示IPv4,6 表示IPv6 + * @throws NetworkException 如果IP格式无效 + */ + @JvmStatic + fun testIp(ip: String?): Int { + if (ip == null) { + throw NetworkException("IP地址不能为null") + } + val trimmedIp = ip.trim() + + // 判断是否匹配IPv4格式 + if (IPV4_PATTERN.matcher(trimmedIp).matches()) { + return IPV4 + } + + // 判断是否匹配IPv6格式 + if (IPV6_PATTERN.matcher(trimmedIp).matches()) { + return IPV6 + } + + // 不符合任一格式时抛出异常 + throw NetworkException( + "[$ip] 不是有效的IPv4或IPv6地址" + ) + } + } + + /** + * IP地址类型:4 表示 IPv4,6 表示 IPv6 + */ + var iPv: Int = 0 + private set + + /** + * IP地址字符串 + */ + var ip: String? = null + private set + + /** + * 域名(如果输入的是域名) + */ + private var domain: String? = null + + /** + * 标识是否是域名解析来的IP + */ + private var isdom = false + + /** + * 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。 + * + * @param domip 可能是IP地址或域名的字符串 + */ + init { + try { + // 尝试将输入识别为IP地址 + this.iPv = testIp(domip) + this.ip = domip + } catch (e: NetworkException) { + try { + // 如果不是有效IP,则尝试作为域名解析 + val ips = getHostIp(domip) + this.iPv = testIp(ips) + this.ip = ips + this.isdom = true + this.domain = domip + } catch (ex: UnknownHostException) { + throw NetworkException(ex) + } + } + } + + /** + * 将IPv4地址转换为字节数组 + * + * @return 返回表示IPv4地址的4字节数组 + * @throws NetworkException 当当前地址不是IPv4地址时抛出异常 + */ + fun toIpv4ByteArray(): ByteArray { + // 验证地址类型是否为IPv4 + if (iPv != IPV4) { + throw NetworkException("该地址 不是IPv4地址") + } + // 将IP地址字符串按点分割,转换为整数并进行位运算处理,最后转为字节数组 + return ip!!.split(".").map { it.toInt() and 0xFF }.map { it.toByte() }.toByteArray() + } + + /** + * 将IPv4地址写入到指定的ByteBuffer中 + * + * @param byteBuffer 要写入的ByteBuffer对象,IPv4地址将以字节数组形式写入到该缓冲区 + * @return 返回写入了IPv4地址的ByteBuffer对象,便于链式调用 + */ + fun writeIpv4ToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { + return byteBuffer.put(toIpv4ByteArray()) + } + + /** + * 将当前 NetworkAddress 转换为 InetAddress 对象。 + * + * @return InetAddress 对象 + */ + fun toInetAddress(): InetAddress { + try { + return InetAddress.getByName(if (ip != null) ip else domain) + } catch (e: UnknownHostException) { + throw RuntimeException(e) + } + } + + /** + * 返回 NetworkAddress 的字符串表示形式。 + * + * @return 字符串表示 + */ + override fun toString(): String { + return if (isdom) "NetworkAddress(IP='$ip',type='$iPv',domain='$domain')" + else "NetworkAddress(IP='$ip',type='$iPv')" + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/network/NetworkEndpoint.kt b/src/main/kotlin/com/mingliqiye/utils/network/NetworkEndpoint.kt new file mode 100644 index 0000000..1abfc71 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/network/NetworkEndpoint.kt @@ -0,0 +1,206 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NetworkEndpoint.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.network + +import java.io.Serializable +import java.net.InetSocketAddress +import java.nio.ByteBuffer + +/** + * IP和端口聚集类,用于封装网络地址与端口信息。 + * 该类提供了与InetSocketAddress之间的相互转换功能。 + * + * @author MingLiPro + * @see java.net.InetSocketAddress + */ +class NetworkEndpoint private constructor( + val networkAddress: NetworkAddress, val networkPort: NetworkPort +) : Serializable, InetSocketAddress(networkAddress.toInetAddress(), networkPort.port) { + + + companion object { + /** + * 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。 + * + * @param address InetSocketAddress对象 + * @return 新建的NetworkEndpoint实例 + * @see InetSocketAddress + */ + @JvmStatic + fun of(address: InetSocketAddress): NetworkEndpoint { + return NetworkEndpoint( + NetworkAddress.of(address.hostString), NetworkPort(address.port) + ) + } + + /** + * 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。 + * + * @param s 主机名或IP地址字符串 + * @param i 端口号 + * @return 新建的NetworkEndpoint实例 + */ + @JvmStatic + fun of(s: String, i: Int): NetworkEndpoint { + val networkAddress = NetworkAddress.of(s) + val networkPort = NetworkPort(i) + return NetworkEndpoint(networkAddress, networkPort) + } + + /** + * 从字节数组创建IPv4网络端点 + * + * @param byteArray 包含IPv4地址和端口信息的字节数组,前4个字节表示IP地址,后2个字节表示端口号 + * @return NetworkEndpoint对象,封装了IPv4地址和端口信息 + */ + @JvmStatic + fun ofIpv4(byteArray: ByteArray): NetworkEndpoint { + // 提取前4个字节作为IP地址 + val address = ByteArray(4) { + byteArray[it] + } + // 提取后2个字节作为端口号 + val portInt = ByteArray(2) { + byteArray[it + 4] + } + return NetworkEndpoint(NetworkAddress.ofIpv4(address), NetworkPort.of(portInt)) + } + + /** + * 从字节缓冲区创建IPv4网络端点实例 + * + * 该方法从给定的ByteBuffer中读取数据,构建一个包含IPv4地址和端口的网络端点对象。 + * 该方法按照协议顺序从缓冲区中读取IPv4地址数据和端口数据。 + * + * @param byteBuffer 包含IPv4地址和端口数据的字节缓冲区,缓冲区中的数据应按照先地址后端口的顺序排列 + * @return 返回一个NetworkEndpoint实例,包含从缓冲区解析出的IPv4地址和端口信息 + */ + @JvmStatic + fun ofIpv4(byteBuffer: ByteBuffer): NetworkEndpoint { + return NetworkEndpoint( + NetworkAddress.ofIpv4(byteBuffer), + NetworkPort.of(byteBuffer) + ) + } + + /** + * 根据"host:port"格式的字符串创建NetworkEndpoint实例。 + * 例如:"127.0.0.1:8080" + * + * @param s "host:port"格式的字符串 + * @return 新建的NetworkEndpoint实例 + */ + @JvmStatic + fun of(s: String): NetworkEndpoint { + val lastColonIndex = s.lastIndexOf(':') + return of( + s.take(lastColonIndex), s.substring(lastColonIndex + 1).toInt() + ) + } + } + + /** + * 将当前NetworkEndpoint转换为InetSocketAddress对象。 + * + * @return 对应的InetSocketAddress对象 + * @see InetSocketAddress + */ + fun toInetSocketAddress(): InetSocketAddress { + return InetSocketAddress( + networkAddress.toInetAddress(), networkPort.port + ) + } + + /** + * 将当前NetworkEndpoint转换为"host:port"格式的字符串。 + * 例如:"127.0.0.1:25563" + * + * @return 格式化后的字符串 + */ + fun toHostPortString(): String { + return "${networkAddress.ip}:${networkPort.port}" + } + + /** + * 返回NetworkEndpoint的详细字符串表示形式。 + * 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...) + * + * @return 包含详细信息的字符串 + */ + override fun toString(): String { + return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port})" + } + + /** + * 获取主机名或IP地址字符串。 + * + * @return 主机名或IP地址 + */ + fun host(): String { + return networkAddress.ip ?: "" + } + + /** + * 获取端口号。 + * + * @return 端口号 + */ + fun port(): Int { + return networkPort.port + } + + /** + * 将网络地址和端口转换为IPv4字节数组 + * + * 该函数将当前对象的网络地址转换为IPv4字节数组,并与端口字节数组合并, + * 生成一个包含6个字节的数组,其中前4个字节为IPv4地址,后2个字节为端口号 + * + * @return ByteArray 包含6个字节的数组,前4个字节为IPv4地址,后2个字节为端口号 + */ + fun toIpv4ByteArray(): ByteArray { + val ipv4ByteArray = networkAddress.toIpv4ByteArray() + val portByteArray = networkPort.toByteArray() + // 构建包含IPv4地址和端口的6字节数组 + val byteArray = ByteArray(6) { + if (it < 4) { + ipv4ByteArray[it] + } else { + portByteArray[it - 4] + } + } + return byteArray + } + + /** + * 将IPv4地址和端口信息写入字节缓冲区 + * + * 该函数依次将网络地址的IPv4表示和网络端口写入到指定的字节缓冲区中 + * + * @param byteBuffer 要写入数据的目标字节缓冲区 + */ + fun writeIpv4toByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { + networkAddress.writeIpv4ToByteBuffer(byteBuffer) + networkPort.writeToByteBuffer(byteBuffer) + return byteBuffer + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/network/NetworkException.kt b/src/main/kotlin/com/mingliqiye/utils/network/NetworkException.kt new file mode 100644 index 0000000..c1362f3 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/network/NetworkException.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NetworkException.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.network + +class NetworkException : RuntimeException { + /** + * 构造一个带有指定详细消息的网络异常 + * + * @param message 异常的详细消息 + */ + constructor(message: String?) : super(message) + + /** + * 构造一个网络异常,指定原因异常 + * + * @param e 导致此异常的原因异常 + */ + constructor(e: Exception?) : super(e) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/network/NetworkPort.kt b/src/main/kotlin/com/mingliqiye/utils/network/NetworkPort.kt new file mode 100644 index 0000000..5ff3368 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/network/NetworkPort.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NetworkPort.kt + * LastUpdate 2026-02-05 10:20:31 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.network + +import java.io.Serializable +import java.nio.ByteBuffer + +class NetworkPort : Serializable { + val port: Int + + constructor(port: Int) { + testPort(port) + this.port = port + } + + fun toByteArray(): ByteArray { + val byteArray = ByteArray(2) + byteArray[0] = (port shr 8 and 0xFF).toByte() + byteArray[1] = (port and 0xFF).toByte() + return byteArray + } + + fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer { + return byteBuffer.put(toByteArray()) + } + + companion object { + + /** + * 创建NetworkPort实例 + * @param port 端口号 + * @return NetworkPort实例 + */ + @JvmStatic + fun of(port: Int): NetworkPort { + return NetworkPort(port) + } + + /** + * 从字节数组创建NetworkPort实例 + * @param byteArray 包含端口信息的字节数组(长度至少为2) + * @return NetworkPort实例 + */ + @JvmStatic + fun of(byteArray: ByteArray): NetworkPort { + // 将字节数组的前两个字节转换为端口号 + val port = ((byteArray[0].toInt() and 0xFF) shl 8) or (byteArray[1].toInt() and 0xFF) + return of(port) + } + + /** + * 从ByteBuffer创建NetworkPort实例 + * @param byteBuffer 包含端口信息的ByteBuffer + * @return NetworkPort实例 + */ + @JvmStatic + fun of(byteBuffer: ByteBuffer): NetworkPort { + val byteArray = ByteArray(2) + byteBuffer.get(byteArray) + return of(byteArray) + } + + @JvmStatic + fun testPort(port: Int) { + // 验证端口号范围是否在0-65535之间 + if (port !in 0..65535) { + throw NetworkException("$port 不是正确的端口号") + } + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/objects/NullUtils.kt b/src/main/kotlin/com/mingliqiye/utils/objects/NullUtils.kt new file mode 100644 index 0000000..b367040 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/objects/NullUtils.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile NullUtils.kt + * LastUpdate 2026-02-05 10:17:02 + * UpdateUser MingLiPro + */ +@file:JvmName("NullUtils") + +package com.mingliqiye.utils.objects + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Any?.isNotNull(): Boolean { + contract { + returns(true) implies (this@isNotNull != null) + } + return !isNull() +} + +@OptIn(ExperimentalContracts::class) +fun Any?.isNull(): Boolean { + contract { + returns(false) implies (this@isNull != null) + } + return this == null +} + +fun areEquals(a: Any?, b: Any?) = (a == null && b == null) || (a == b) + +@OptIn(ExperimentalContracts::class) +fun areEqualsNoNull(a: Any?, b: Any?): Boolean { + contract { + returns(true) implies (a != null && b != null) + } + return a != null && b != null && a == b +} diff --git a/src/main/kotlin/com/mingliqiye/utils/path/OsPath.kt b/src/main/kotlin/com/mingliqiye/utils/path/OsPath.kt index f88d949..4e9dc63 100644 --- a/src/main/kotlin/com/mingliqiye/utils/path/OsPath.kt +++ b/src/main/kotlin/com/mingliqiye/utils/path/OsPath.kt @@ -28,8 +28,17 @@ import java.io.File import java.net.URI import java.nio.file.Path import java.nio.file.Paths +import java.util.* +import java.util.function.Consumer class OsPath private constructor(private val path: Path) : Path by path { + override fun forEach(action: Consumer?) { + path.forEach(action) + } + + override fun spliterator(): Spliterator { + return path.spliterator() + } companion object { @JvmStatic diff --git a/src/main/kotlin/com/mingliqiye/utils/random/RandomBytes.kt b/src/main/kotlin/com/mingliqiye/utils/random/RandomBytes.kt index cfdb33b..d4842d6 100644 --- a/src/main/kotlin/com/mingliqiye/utils/random/RandomBytes.kt +++ b/src/main/kotlin/com/mingliqiye/utils/random/RandomBytes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,13 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile RandomBytes.kt - * LastUpdate 2025-09-16 17:42:26 + * LastUpdate 2026-01-28 10:47:13 * UpdateUser MingLiPro */ @file:JvmName("RandomBytes") package com.mingliqiye.utils.random -import java.security.SecureRandom - /** * 生成指定长度的随机字节数组 * @param length 数组长度 @@ -38,6 +36,7 @@ fun randomBytes(length: Int): ByteArray { return bytes } + /** * 生成指定长度的随机字节数组 * 从给定的字节数组中随机选择字节来填充新数组 @@ -81,12 +80,8 @@ fun randomByteNoHave(from: Byte, to: Byte): Byte { return (randomValue and 0xFF).toByte() } -val secureRandom: SecureRandom by lazy { - SecureRandom.getInstanceStrong() -} - -fun randomByteSecure(size: Int): ByteArray { +fun randomByte(size: Int): ByteArray { val bytes = ByteArray(size) secureRandom.nextBytes(bytes) return bytes diff --git a/src/main/kotlin/com/mingliqiye/utils/random/RandomInt.kt b/src/main/kotlin/com/mingliqiye/utils/random/RandomInt.kt index 367f4b2..12c7fb1 100644 --- a/src/main/kotlin/com/mingliqiye/utils/random/RandomInt.kt +++ b/src/main/kotlin/com/mingliqiye/utils/random/RandomInt.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * 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,24 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile RandomInt.kt - * LastUpdate 2025-09-12 17:08:32 + * LastUpdate 2026-01-28 10:46:02 * UpdateUser MingLiPro */ @file:JvmName("RandomInt") package com.mingliqiye.utils.random -import java.util.concurrent.ThreadLocalRandom +import java.security.SecureRandom + +val secureRandom: SecureRandom by lazy { + SecureRandom.getInstanceStrong() +} + + +fun SecureRandom.nextInt(min: Int, max: Int): Int { + return min + nextInt(max - min) +} + /** * 生成指定范围内的随机整数 @@ -42,7 +52,7 @@ fun randomIntNoHave(min: Int, max: Int): Int { if (min == max) { return min } - return ThreadLocalRandom.current().nextInt(min, max) + return secureRandom.nextInt(min, max) } /** @@ -55,6 +65,3 @@ fun randomInt(min: Int, max: Int): Int { var max = max return randomIntNoHave(min, ++max) } - - - diff --git a/src/main/kotlin/com/mingliqiye/utils/random/RandomString.kt b/src/main/kotlin/com/mingliqiye/utils/random/RandomString.kt index 8b4ffbb..cea1495 100644 --- a/src/main/kotlin/com/mingliqiye/utils/random/RandomString.kt +++ b/src/main/kotlin/com/mingliqiye/utils/random/RandomString.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile RandomString.kt - * LastUpdate 2025-09-12 17:10:43 + * LastUpdate 2026-02-05 11:12:36 * UpdateUser MingLiPro */ @file:JvmName("RandomString") diff --git a/src/main/kotlin/com/mingliqiye/utils/request/Require.kt b/src/main/kotlin/com/mingliqiye/utils/request/Require.kt deleted file mode 100644 index 0e687f9..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/request/Require.kt +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2026 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile Require.kt - * LastUpdate 2026-01-10 09:01:03 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.request - -import com.mingliqiye.utils.functions.P1RFunction -import com.mingliqiye.utils.functions.RFunction - -/** - * 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常构造器 - * @param message 异常消息 - * @param exception 异常构造器函数 - * @return Require对象 - */ -fun Boolean.require(message: String, exception: P1RFunction): Require { - return Require(this, message, exception) -} - -/** - * 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常类型 - * @param message 异常消息 - * @param exception 异常类型,默认为IllegalArgumentException - * @return Require对象 - */ -fun Boolean.require( - message: String, - exception: Class = IllegalArgumentException::class.java -): Require { - return Require(this, message, exception) -} - -/** - * 条件检查工具类,用于验证条件并抛出相应异常 - * @param must 需要验证的布尔条件 - */ -class Require(private val must: Boolean) { - - /** - * 构造函数:通过函数调用结果初始化条件检查器 - * @param funs 返回布尔值的函数 - */ - constructor(funs: RFunction) : this(funs.call()) - - /** - * 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查 - * @param must 返回布尔值的函数 - * @param message 检查失败时的异常消息 - */ - constructor(must: RFunction, message: String) : this(must) { - throws(message) - } - - /** - * 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查 - * @param must 返回布尔值的函数 - * @param message 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException - */ - constructor( - must: RFunction, - message: String, - exception: Class = IllegalArgumentException::class.java - ) : this(must) { - throws(message, exception) - } - - /** - * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 - * @param must 需要验证的布尔条件 - * @param message 检查失败时的异常消息 - */ - constructor(must: Boolean, message: String) : this(must) { - throws(message) - } - - /** - * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 - * @param must 需要验证的布尔条件 - * @param message 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException - */ - constructor( - must: Boolean, message: String, exception: Class = IllegalArgumentException::class.java - ) : this(must) { - throws(message, exception) - } - - /** - * 构造函数:通过布尔值初始化条件检查器,并立即执行检查 - * @param must 需要验证的布尔条件 - * @param message 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常构造器函数 - */ - constructor( - must: Boolean, message: String, exception: P1RFunction - ) : this(must) { - throws(message, exception) - } - - companion object { - - /** - * 工厂方法:创建Require对象并指定异常消息和异常类型 - * @param must 需要验证的布尔条件 - * @param message 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException - * @return Require对象 - */ - @JvmStatic - fun require( - must: Boolean, message: String, exception: Class = IllegalArgumentException::class.java - ): Require { - return Require(must, message, exception) - } - - /** - * 工厂方法:创建Require对象并指定异常消息 - * @param must 需要验证的布尔条件 - * @param message 检查失败时的异常消息 - * @return Require对象 - */ - @JvmStatic - fun require(must: Boolean, message: String): Require { - return Require(must, message) - } - - /** - * 工厂方法:创建Require对象 - * @param must 需要验证的布尔条件 - * @return Require对象 - */ - @JvmStatic - fun require(must: Boolean): Require { - return Require(must) - } - - /** - * 工厂方法:创建Require对象并指定异常消息和异常类型 - * @param must 返回布尔值的函数 - * @param message 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException - * @return Require对象 - */ - @JvmStatic - fun require( - must: RFunction, - message: String, - exception: Class = IllegalArgumentException::class.java - ): Require { - return Require(must, message, exception) - } - - /** - * 工厂方法:创建Require对象并指定异常消息 - * @param must 返回布尔值的函数 - * @param message 检查失败时的异常消息 - * @return Require对象 - */ - @JvmStatic - fun require(must: RFunction, message: String): Require { - return Require(must, message) - } - - /** - * 工厂方法:创建Require对象 - * @param must 返回布尔值的函数 - * @return Require对象 - */ - @JvmStatic - fun require(must: RFunction): Require { - return Require(must) - } - } - - /** - * 执行条件检查,如果条件为false则抛出IllegalArgumentException - * @param message 检查失败时的异常消息 - */ - fun throws(message: String) { - if (!must) { - throw IllegalArgumentException(message) - } - } - - /** - * 执行条件检查,如果条件为false则抛出指定类型的异常 - * @param string 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常类型 - */ - fun throws(string: String, exception: Class) { - if (!must) { - throw exception.getConstructor(String::class.java).newInstance(string) - } - } - - /** - * 执行条件检查,如果条件为false则抛出由函数构造的异常 - * @param string 检查失败时的异常消息 - * @param exception 检查失败时抛出的异常构造器函数 - */ - fun throws(string: String, exception: P1RFunction) { - if (!must) { - throw exception.call(string) - } - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/require/Require.kt b/src/main/kotlin/com/mingliqiye/utils/require/Require.kt new file mode 100644 index 0000000..0533a05 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/require/Require.kt @@ -0,0 +1,207 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Require.kt + * LastUpdate 2026-02-06 08:27:44 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.require + +import com.mingliqiye.utils.exception.InternalServerErrorException +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import org.slf4j.Logger +import java.lang.reflect.Constructor +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +/** + * 工具对象,用于提供条件检查功能。 + * 支持抛出自定义异常、延迟消息构造以及日志记录等功能。 + */ +class Require(val defaultException: Class) { + + companion object { + @JvmStatic + val RequireLayz by lazy { + Require(IllegalArgumentException::class.java) + } + + @JvmStatic + val RequireHttpLayz by lazy { + Require(InternalServerErrorException::class.java) + } + + @JvmStatic + var logger: Logger? = MingLiLoggerFactory.getLogger() + + @JvmStatic + var isLogError = true + + /** + * 检查给定条件是否为真。如果为假,则使用延迟消息构造器生成异常并抛出。 + * + * @param value 需要检查的布尔值。 + * @param throwable 异常类型。 + * @param layzMessage 延迟消息构造器。 + */ + @OptIn(ExperimentalContracts::class) + fun require(value: Boolean, throwable: Class, layzMessage: RequireLayzMessageConstructor) { + contract { + returns() implies value + } + require(value, layzMessage.call(), throwable) + } + + /** + * 检查给定条件是否为真。如果为假,则使用延迟异常构造器生成异常并抛出。 + * + * @param value 需要检查的布尔值。 + * @param layzThrowable 延迟异常构造器。 + */ + @JvmStatic + @OptIn(ExperimentalContracts::class) + fun require(value: Boolean, layzThrowable: RequireLayzExceptionConstructor) { + contract { + returns() implies value + } + if (!value) throwThrowable(layzThrowable.call()) + } + + /** + * 检查给定条件是否为真。如果为假,则根据指定的异常类型和消息生成异常并抛出。 + * + * @param value 需要检查的布尔值。 + * @param message 异常消息。 + * @param throwable 异常类型。 + */ + @JvmStatic + @OptIn(ExperimentalContracts::class) + fun require(value: Boolean, message: String, throwable: Class) { + contract { + returns() implies value + } + if (!value) throwThrowable(getExceptionConstructor(throwable).newInstance(message)) + } + + /** + * 抛出指定的异常,并在启用日志记录时记录错误信息。 + * + * @param throwable 需要抛出的异常。 + */ + @JvmStatic + fun throwThrowable(throwable: Throwable) { + if (isLogError && logger != null) logger!!.error(throwable.message, throwable) + throw throwable + } + + /** + * 检查给定条件是否为真。如果为假,则根据指定的异常类型抛出异常。 + * + * @param value 需要检查的布尔值。 + * @param message 异常消息。 + * @param T 异常类型。 + */ + @OptIn(ExperimentalContracts::class) + @JvmName("__inline_Require") + inline fun require(value: Boolean, message: String) { + contract { + returns() implies value + } + require(value, message, T::class.java) + } + + /** + * 检查给定条件是否为真。如果为假,则根据指定的异常类型和延迟消息构造器生成异常并抛出。 + * + * @param value 需要检查的布尔值。 + * @param layzMessage 延迟消息构造器。 + * @param T 异常类型。 + */ + @OptIn(ExperimentalContracts::class) + @JvmName("__inline_Require") + inline fun require(value: Boolean, layzMessage: RequireLayzMessageConstructor) { + contract { + returns() implies value + } + if (!value) throwThrowable(getExceptionConstructor().newInstance(layzMessage.call())) + } + + /** + * 获取指定异常类型的构造函数(带字符串参数)。 + * + * @param T 异常类型。 + * @return 异常类型的构造函数。 + */ + @JvmName("__inline_GetExceptionConstructor") + inline fun getExceptionConstructor(): Constructor = + getExceptionConstructor(T::class.java) + + /** + * 获取指定异常类型的构造函数(带字符串参数)。 + * + * @param throwable 异常类型。 + * @return 异常类型的构造函数。 + */ + + @JvmStatic + @JvmName("__GetExceptionConstructor") + fun getExceptionConstructor(throwable: Class): Constructor = + throwable.getConstructor(String::class.java) + } + + /** + * 检查给定条件是否为真。如果为假,则抛出 [IllegalArgumentException] 异常。 + * + * @param value 需要检查的布尔值。 + */ + @OptIn(ExperimentalContracts::class) + fun require(value: Boolean) { + contract { + returns() implies value + } + require(value, "the require conditions are not met.") + } + + /** + * 检查给定条件是否为真。如果为假,则使用延迟消息构造器生成 [IllegalArgumentException] 并抛出。 + * + * @param value 需要检查的布尔值。 + * @param layzMessage 延迟消息构造器。 + */ + @OptIn(ExperimentalContracts::class) + fun requireLayzMessage(value: Boolean, layzMessage: RequireLayzMessageConstructor) { + contract { + returns() implies value + } + require(value, defaultException, layzMessage) + } + + /** + * 检查给定条件是否为真。如果为假,则抛出 [IllegalArgumentException] 异常。 + * + * @param value 需要检查的布尔值。 + * @param message 异常消息。 + */ + @OptIn(ExperimentalContracts::class) + fun require(value: Boolean, message: String) { + contract { + returns() implies value + } + if (!value) throwThrowable(getExceptionConstructor(defaultException).newInstance(message)) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/stream/StreamEmptyException.kt b/src/main/kotlin/com/mingliqiye/utils/require/RequireLayzExceptionConstructor.kt similarity index 70% rename from src/main/kotlin/com/mingliqiye/utils/stream/StreamEmptyException.kt rename to src/main/kotlin/com/mingliqiye/utils/require/RequireLayzExceptionConstructor.kt index 66e4955..977c7c6 100644 --- a/src/main/kotlin/com/mingliqiye/utils/stream/StreamEmptyException.kt +++ b/src/main/kotlin/com/mingliqiye/utils/require/RequireLayzExceptionConstructor.kt @@ -15,15 +15,14 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile StreamEmptyException.kt - * LastUpdate 2026-01-07 19:13:29 + * CurrentFile RequireLayzExceptionConstructor.kt + * LastUpdate 2026-02-05 09:36:19 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.stream +package com.mingliqiye.utils.require -class StreamEmptyException : RuntimeException { - constructor(message: String) : super(message) - - constructor(message: String, cause: Throwable) : super(message, cause) +@FunctionalInterface +fun interface RequireLayzExceptionConstructor { + fun call(): Throwable } diff --git a/src/main/kotlin/com/mingliqiye/utils/require/RequireLayzMessageConstructor.kt b/src/main/kotlin/com/mingliqiye/utils/require/RequireLayzMessageConstructor.kt new file mode 100644 index 0000000..b19741a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/require/RequireLayzMessageConstructor.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile RequireLayzMessageConstructor.kt + * LastUpdate 2026-02-05 09:36:09 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.require + +@FunctionalInterface +fun interface RequireLayzMessageConstructor { + fun call(): String +} diff --git a/src/main/kotlin/com/mingliqiye/utils/resource/ResourceUtils.kt b/src/main/kotlin/com/mingliqiye/utils/resource/ResourceUtils.kt index 4aacae0..a2e03c1 100644 --- a/src/main/kotlin/com/mingliqiye/utils/resource/ResourceUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/resource/ResourceUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,72 +16,120 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile ResourceUtils.kt - * LastUpdate 2025-09-20 10:26:47 + * LastUpdate 2026-02-05 11:09:16 * UpdateUser MingLiPro */ package com.mingliqiye.utils.resource import java.io.IOException -class ResourceUtils { - companion object { - @JvmStatic - @Throws(IOException::class) - fun getResource(resourceName: String): ByteArray { - return getResource(resourceName, ResourceUtils::class.java) - } +/** + * 工具类,用于从类路径中加载资源文件。 + */ +object ResourceUtils { - @JvmStatic - @Throws(IOException::class) - fun getResource(resourceName: String, clazz: Class<*>): ByteArray { - return clazz.getResourceAsStream(resourceName)?.use { - it.readBytes() - } ?: throw IOException("Resource not found: $resourceName") - } + /** + * 从默认类路径中加载指定名称的资源文件,并以字节数组形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @return 资源文件的内容作为字节数组。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getResource(resourceName: String): ByteArray { + return getResource(resourceName, ResourceUtils::class.java) + } + /** + * 从指定类的类路径中加载指定名称的资源文件,并以字节数组形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @param clazz 用于定位资源的类。 + * @return 资源文件的内容作为字节数组。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getResource(resourceName: String, clazz: Class<*>): ByteArray { + return clazz.getResourceAsStream(resourceName)?.use { + it.readBytes() + } ?: throw IOException("Resource not found: $resourceName") + } - @JvmStatic - @Throws(IOException::class) - fun getStringResource(resourceName: String): String { - return getStringResource(resourceName, ResourceUtils::class.java) - } + /** + * 从默认类路径中加载指定名称的资源文件,并以字符串形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @return 资源文件的内容作为字符串(使用UTF-8编码)。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getStringResource(resourceName: String): String { + return getStringResource(resourceName, ResourceUtils::class.java) + } + /** + * 从指定类的类路径中加载指定名称的资源文件,并以字符串形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @param clazz 用于定位资源的类。 + * @return 资源文件的内容作为字符串(使用UTF-8编码)。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getStringResource(resourceName: String, clazz: Class<*>): String { + return clazz.getResourceAsStream(resourceName)?.use { + it.readBytes().toString(charset = Charsets.UTF_8) + } ?: throw IOException("Resource not found: $resourceName") + } - @JvmStatic - @Throws(IOException::class) - fun getStringResource(resourceName: String, clazz: Class<*>): String { - return clazz.getResourceAsStream(resourceName)?.use { - it.readBytes().toString(charset = Charsets.UTF_8) - } ?: throw IOException("Resource not found: $resourceName") - } + /** + * 从调用者的类路径中加载指定名称的资源文件,并以字符串形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @return 资源文件的内容作为字符串(使用UTF-8编码)。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getStringResourceCallers(resourceName: String): String { + return getStringResource(resourceName, getCallerClass()) + } + /** + * 从调用者的类路径中加载指定名称的资源文件,并以字节数组形式返回。 + * + * @param resourceName 资源文件的名称(相对于类路径根目录)。 + * @return 资源文件的内容作为字节数组。 + * @throws IOException 如果资源未找到或读取失败时抛出。 + */ + @JvmStatic + @Throws(IOException::class) + fun getResourceCallers(resourceName: String): ByteArray { + return getResource(resourceName, getCallerClass()) + } - @JvmStatic - @Throws(IOException::class) - fun getStringResourceCallers(resourceName: String): String { - return getStringResource(resourceName, getCallerClass()) - } - - @JvmStatic - @Throws(IOException::class) - fun getResourceCallers(resourceName: String): ByteArray { - return getResource(resourceName, getCallerClass()) - } - - private fun getCallerClass(): Class<*> { - val stackTrace = Thread.currentThread().stackTrace - for (i in 2 until stackTrace.size) { - val className = stackTrace[i].className - try { - val clazz = Class.forName(className) - if (clazz != ResourceUtils::class.java && clazz != Companion::class.java) { - return clazz - } - } catch (e: ClassNotFoundException) { - continue + /** + * 获取当前调用栈中第一个非ResourceUtils类的调用者类。 + * + * @return 调用者类对象;如果未找到则返回ResourceUtils类本身。 + */ + private fun getCallerClass(): Class<*> { + val stackTrace = Thread.currentThread().stackTrace + for (i in 2 until stackTrace.size) { + val className = stackTrace[i].className + try { + val clazz = Class.forName(className) + if (clazz != ResourceUtils::class.java) { + return clazz } + } catch (e: ClassNotFoundException) { + continue } - return ResourceUtils::class.java } + return ResourceUtils::class.java } } diff --git a/src/main/kotlin/com/mingliqiye/utils/security/SecureUtils.kt b/src/main/kotlin/com/mingliqiye/utils/security/SecureUtils.kt index bc96628..e6bc3d0 100644 --- a/src/main/kotlin/com/mingliqiye/utils/security/SecureUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/security/SecureUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile SecureUtils.kt - * LastUpdate 2025-09-15 22:32:50 + * LastUpdate 2026-02-05 11:12:36 * UpdateUser MingLiPro */ @@ -29,27 +29,64 @@ import java.security.SecureRandom import javax.crypto.SecretKey import javax.crypto.spec.SecretKeySpec +/** + * 全局安全随机数生成器实例,用于生成加密安全的随机字节。 + */ internal val SECURE_RANDOM = SecureRandom() +/** + * 生成指定长度的加密安全随机字节数组。 + * + * @param length 需要生成的字节数组的长度。 + * @return 包含随机字节的 ByteArray。 + */ fun getRandomBytes(length: Int): ByteArray { val bytes = ByteArray(length) SECURE_RANDOM.nextBytes(bytes) return bytes } +/** + * 使用指定算法对输入数据进行哈希处理,生成密钥字节数组。 + * + * @param algorithm 哈希算法名称(如 SHA-256)。 + * @param data 输入的字节数组数据。 + * @return 经过哈希处理后的密钥字节数组。 + */ fun createSecretKey(algorithm: String, data: ByteArray): ByteArray { val md = MessageDigest.getInstance(algorithm) return md.digest(data) } +/** + * 使用指定算法对输入字符串进行哈希处理,生成密钥字节数组。 + * + * @param algorithm 哈希算法名称(如 SHA-256)。 + * @param data 输入的字符串数据。 + * @return 经过哈希处理后的密钥字节数组。 + */ fun createSecretKey(algorithm: String, data: String): ByteArray { return createSecretKey(algorithm, data.toByteArray()) } +/** + * 使用指定算法和输入字符串创建 SecretKeySpec 对象。 + * + * @param algorithm 哈希算法名称(如 AES)。 + * @param data 输入的字符串数据。 + * @return 根据输入数据和算法生成的 SecretKey 对象。 + */ fun createSecretKeySpec(algorithm: String, data: String): SecretKey { return SecretKeySpec(createSecretKey(algorithm, data), algorithm) } +/** + * 使用指定算法和输入字节数组创建 SecretKeySpec 对象。 + * + * @param algorithm 哈希算法名称(如 AES)。 + * @param data 输入的字节数组数据。 + * @return 根据输入数据和算法生成的 SecretKey 对象。 + */ fun createSecretKeySpec(algorithm: String, data: ByteArray): SecretKey { return SecretKeySpec(createSecretKey(algorithm, data), algorithm) } diff --git a/src/main/kotlin/com/mingliqiye/utils/sleep/SleepUtils.kt b/src/main/kotlin/com/mingliqiye/utils/sleep/SleepUtils.kt new file mode 100644 index 0000000..c1dd433 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/sleep/SleepUtils.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile SleepUtils.kt + * LastUpdate 2026-01-15 16:50:50 + * UpdateUser MingLiPro + */ +package com.mingliqiye.utils.sleep + +import java.util.concurrent.TimeUnit + +/** + * 等待工具类,提供多种等待和延迟执行的方式 + */ +object SleepUtils { + + /** + * 基于 Thread.sleep 的等待,单位毫秒 + * + * @param millis 等待时间(毫秒) + * @throws RuntimeException 当线程被中断时抛出 + */ + @JvmStatic + fun sleep(millis: Long) { + try { + Thread.sleep(millis) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + throw RuntimeException("Sleep interrupted", e) + } + } + + /** + * 基于 Thread.sleep 的等待,单位毫秒 + * + * @param millis 等待时间(毫秒) + * @throws RuntimeException 当线程被中断时抛出 + */ + @JvmStatic + fun sleep(millis: Int) { + try { + Thread.sleep(millis.toLong()) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + throw RuntimeException("Sleep interrupted", e) + } + } + + /** + * 基于 TimeUnit 的等待 + * + * @param timeout 等待时间 + * @param unit 时间单位 + * @throws RuntimeException 当线程被中断时抛出 + */ + @JvmStatic + fun sleep(timeout: Long, unit: TimeUnit) { + try { + unit.sleep(timeout) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + throw RuntimeException("Sleep interrupted", e) + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.kt index cdc1520..646bb14 100644 --- a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.kt +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * 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,15 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile AutoConfiguration.kt - * LastUpdate 2025-09-20 10:47:00 + * LastUpdate 2026-02-06 15:15:46 * UpdateUser MingLiPro */ package com.mingliqiye.utils.springboot.autoconfigure -import com.mingliqiye.utils.logger.mingLiLoggerFactory +import com.mingliqiye.utils.i18n.I18N +import com.mingliqiye.utils.i18n.I18N.infoTranslater +import com.mingliqiye.utils.logger.MingLiLoggerFactory import com.mingliqiye.utils.system.computerName import com.mingliqiye.utils.system.getPid import com.mingliqiye.utils.system.jdkVersion @@ -32,51 +34,76 @@ import com.mingliqiye.utils.time.Formatter import org.springframework.context.annotation.ComponentScan import java.io.IOException +/** + * 自动配置类,用于Spring Boot应用启动时加载相关组件和打印启动横幅。 + * + * 该类通过@ComponentScan注解扫描指定包下的Bean,并在初始化时打印包含系统信息的启动横幅。 + */ @org.springframework.boot.autoconfigure.AutoConfiguration @ComponentScan( "com.mingliqiye.utils.springboot.bean", "com.mingliqiye.utils.springboot.converters" ) open class AutoConfiguration { - companion object { - private const val banner = - "---------------------------------------------------------\n" + - "| $$\\ $$\\ $$\\ $$\\ $$\\ $$$$$$$$\\ $$$$$$\\ |\n" + - "| $$$\\ $$$ |$$ | $$ | $$ |\\__$$ __|$$ __$$\\ |\n" + - "| $$$$\\ $$$$ |$$ | $$ | $$ | $$ | $$ / \\__| |\n" + - "| $$\\$$\\$$ $$ |$$ | $$ | $$ | $$ | \\$$$$$$\\ |\n" + - "| $$ \\$$$ $$ |$$ | $$ | $$ | $$ | \\____$$\\ |\n" + - "| $$ |\\$ /$$ |$$ | $$ | $$ | $$ | $$\\ $$ | |\n" + - "| $$ | \\_/ $$ |$$$$$$$$\\\\$$$$$$ | $$ | \\$$$$$$ | |\n" + - "| \\__| \\__|\\________|\\______/ \\__| \\______/ |\n" - private val log = mingLiLoggerFactory.getLogger("MingliUtils-AutoConfiguration") + private val log = MingLiLoggerFactory.getLogger("MingliUtils-AutoConfiguration") + companion object { + /** + * 启动横幅字符串,包含艺术字体和占位符。 + */ + private const val BANNER = + " | $$\\ $$\\ $$\\ $$\\ $$\\ $$$$$$$$\\ $$$$$$\\ \n" + + "| $$$\\ $$$ |$$ | $$ | $$ |\\__$$ __|$$ __$$\\ \n" + + "| $$$$\\ $$$$ |$$ | $$ | $$ | $$ | $$ / \\__| \n" + + "| $$\\$$\\$$ $$ |$$ | $$ | $$ | $$ | \\$$$$$$\\ \n" + + "| $$ \\$$$ $$ |$$ | $$ | $$ | $$ | \\____$$\\ \n" + + "| $$ |\\$ /$$ |$$ | $$ | $$ | $$ | $$\\ $$ | \n" + + "| $$ | \\_/ $$ |$$$$$$$$\\\\$$$$$$ | $$ | \\$$$$$$ \n" + + "| \\__| \\__|\\________|\\______/ \\__| \\______/ \n|\n" + + /** + * 打印启动横幅,包含系统元数据(如JDK版本、进程ID、计算机名等)。 + * + * 该方法从资源文件中读取元数据,并将其格式化后追加到横幅中进行输出。 + * 如果读取资源失败,则仅打印默认横幅。 + */ fun printBanner() { - val bannerBuilder = StringBuilder(banner) + val bannerBuilder = StringBuilder(BANNER) + + // 尝试从资源文件中读取元数据并拼接到横幅中 try { val inputStream = AutoConfiguration::class.java.getResourceAsStream("/META-INF/meta-data") ?: return inputStream.use { stream -> var readlen: Int val buffer = ByteArray(1024) val metaData = StringBuilder() + + // 逐块读取资源文件内容 while (stream.read(buffer).also { readlen = it } != -1) { metaData.append(String(buffer, 0, readlen)) } + + // 解析元数据并添加额外的系统信息 val da = metaData.toString().split("\n").toMutableList() - da.add("jdkRuntime=$jdkVersion") - da.add("pid=$getPid") - da.add("computerName=$computerName") - da.add("userName=$userName") - da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true)) + da.add("${I18N.getString("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.jdkRuntime")}=$jdkVersion") + da.add("${I18N.getString("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.pid")}=$getPid") + da.add("${I18N.getString("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.computerName")}=$computerName") + da.add("${I18N.getString("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.userName")}=$userName") + da.add( + "${I18N.getString("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.time")}=" + DateTime.now() + .format(Formatter.STANDARD_DATETIME_MILLISECOUND7, false) + ) + + // 格式化每条元数据并追加到横幅中 da.forEach { s: String -> val d = s.trim { it <= ' ' }.split("=".toRegex(), 2).toTypedArray() if (d.size >= 2) { - val content = "| " + d[0] + ": " + d[1] + val content = "| -> " + I18N.getString(d[0]) + ": " + d[1] val targetLength = 56 if (content.length < targetLength) { bannerBuilder.append( String.format( - "%-" + targetLength + "s|\n", + "%-${targetLength}s\n", content ) ) @@ -89,15 +116,24 @@ open class AutoConfiguration { } } } catch (e: IOException) { + // 捕获IO异常并打印堆栈跟踪 e.printStackTrace() } + + // 输出最终构建的横幅 + println("") println(bannerBuilder.toString().trim()) - println("---------------------------------------------------------") + println("") } } + /** + * 初始化块,在类实例化时执行。 + * + * 调用printBanner方法打印启动横幅,并记录日志表示自动配置成功。 + */ init { printBanner() - log.info("MingliUtils AutoConfiguration succeed") + log.infoTranslater("com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.bean") } } diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/GsonAutoConfiguration.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/GsonAutoConfiguration.kt deleted file mode 100644 index 0dc62c0..0000000 --- a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/GsonAutoConfiguration.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * 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 - * - * 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. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile GsonAutoConfiguration.kt - * LastUpdate 2025-09-15 10:29:30 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.springboot.autoconfigure - -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.mingliqiye.utils.json.GsonJsonApi -import com.mingliqiye.utils.json.JsonApi -import com.mingliqiye.utils.json.converters.DateTimeJsonConverter -import com.mingliqiye.utils.json.converters.JsonStringConverter -import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter -import com.mingliqiye.utils.logger.mingLiLoggerFactory -import com.mingliqiye.utils.time.DateTime -import com.mingliqiye.utils.uuid.UUID -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.boot.autoconfigure.AutoConfiguration -import org.springframework.boot.autoconfigure.AutoConfigureAfter -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean -import org.springframework.boot.autoconfigure.gson.GsonBuilderCustomizer -import org.springframework.context.annotation.Bean - -@ConditionalOnClass(Gson::class) -@AutoConfiguration -@AutoConfigureAfter( - name = ["org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration", - "com.mingliqiye.utils.springboot.autoconfigure.JacksonAutoConfiguration"] -) -open class GsonAutoConfiguration { - companion object { - private val log: Logger = LoggerFactory.getLogger("MingliUtils-GsonAutoConfiguration") - - fun addTypeAdapter(gsonBuilder: GsonBuilder): GsonBuilder { - val dateTimeJsonConverter: JsonStringConverter = DateTimeJsonConverter() - val uuidJsonStringConverter: JsonStringConverter = UUIDJsonStringConverter() - - try { - return gsonBuilder - .registerTypeAdapter( - uuidJsonStringConverter.tClass, - uuidJsonStringConverter - .gsonJsonStringConverterAdapter - .gsonTypeAdapter - ) - .registerTypeAdapter( - dateTimeJsonConverter.tClass, - dateTimeJsonConverter - .gsonJsonStringConverterAdapter - .gsonTypeAdapter - ) - } finally { - log.info("MingliUtils GsonBuilder TypeAdapter add") - } - } - } - - private val log: Logger = mingLiLoggerFactory.getLogger("MingliUtils-GsonAutoConfiguration") - - @Bean - open fun mingliGsonCustomizer(): GsonBuilderCustomizer { - return GsonBuilderCustomizer { gsonBuilder: GsonBuilder -> addTypeAdapter(gsonBuilder) } - } - - @Bean - @ConditionalOnMissingBean - open fun jsonApi(gson: Gson): JsonApi { - log.info("MingliUtils-JsonApiAutoConfiguration: GsonJsonApi bean is created.") - return GsonJsonApi(gson) - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/JacksonAutoConfiguration.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/JacksonAutoConfiguration.kt index 7482e65..eadfbe4 100644 --- a/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/JacksonAutoConfiguration.kt +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/autoconfigure/JacksonAutoConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,61 +16,95 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile JacksonAutoConfiguration.kt - * LastUpdate 2025-09-15 10:29:02 + * LastUpdate 2026-02-08 01:29:21 * UpdateUser MingLiPro */ package com.mingliqiye.utils.springboot.autoconfigure import com.fasterxml.jackson.databind.ObjectMapper -import com.mingliqiye.utils.json.JacksonJsonApi -import com.mingliqiye.utils.json.JsonApi +import com.mingliqiye.utils.i18n.I18N.infoTranslater +import com.mingliqiye.utils.json.api.JSONA +import com.mingliqiye.utils.json.api.JacksonJsonApi +import com.mingliqiye.utils.json.api.base.JsonApi import com.mingliqiye.utils.json.converters.DateTimeJsonConverter -import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter -import com.mingliqiye.utils.logger.mingLiLoggerFactory +import com.mingliqiye.utils.json.converters.UUIDJsonConverter +import com.mingliqiye.utils.json.converters.base.JackSonJsonConverter.Companion.addJsonConverter +import com.mingliqiye.utils.logger.MingLiLoggerFactory import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.boot.autoconfigure.AutoConfiguration import org.springframework.boot.autoconfigure.AutoConfigureAfter import org.springframework.boot.autoconfigure.condition.ConditionalOnClass import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Primary -@ConditionalOnClass(ObjectMapper::class) -@AutoConfiguration -@AutoConfigureAfter(org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration::class) +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile JacksonAutoConfiguration.kt + * LastUpdate 2026-02-05 10:39:54 + * UpdateUser MingLiPro + */ + +/* + * JacksonAutoConfiguration 是一个 Spring Boot 自动配置类,用于配置 Jackson 相关的序列化和反序列化功能。 + * 该类在检测到 ObjectMapper 和 Spring Boot 的 JacksonAutoConfiguration 存在时自动生效, + * 并注册自定义的 JSON 转换器模块(如 UUID 和 DateTime 转换器)。 + * + * @param objectMapper 用于 JSON 序列化和反序列化的 ObjectMapper 实例。 + */ +@ConditionalOnClass(name = ["com.fasterxml.jackson.databind.ObjectMapper", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"]) +@AutoConfigureAfter(name = ["org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"]) open class JacksonAutoConfiguration(objectMapper: ObjectMapper) { - companion object { - private val log: Logger = mingLiLoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration") - - fun addModules(objectMapper: ObjectMapper): ObjectMapper { - return objectMapper - .registerModule( - DateTimeJsonConverter() - .jacksonJsonStringConverterAdapter - .jacksonModule - ) - .registerModule( - UUIDJsonStringConverter() - .jacksonJsonStringConverterAdapter - .jacksonModule - ) - } - } - - private val log: Logger = LoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration") + private val log: Logger = MingLiLoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration") + /* + * 初始化块:在类实例化时执行。 + * 注册自定义的 UUID 和 DateTime JSON 转换器模块到 ObjectMapper 中。 + */ init { - addModules(objectMapper) - log.info("MingliUtils Jackson Serializers created") + log.infoTranslater("com.mingliqiye.utils.springboot.autoconfigure.JsonApiAutoConfiguration.jacksonserializers") + objectMapper + .addJsonConverter() + .addJsonConverter() } + /* + * 创建并返回一个 JsonApi Bean 实例。 + * 该方法会在没有其他 JsonApi Bean 存在时被调用,并将创建的 JacksonJsonApi 实例设置为全局默认的 JSON API。 + * + * @param objectMapper 用于 JSON 操作的 ObjectMapper 实例。 + * @return 返回配置好的 JsonApi 实例。 + */ @Bean @Primary @ConditionalOnMissingBean open fun jsonApi(objectMapper: ObjectMapper): JsonApi { - log.info("MingliUtils-JsonApiAutoConfiguration: JacksonJsonApi bean is created.") - return JacksonJsonApi(objectMapper) + return JacksonJsonApi(objectMapper).also { + log.infoTranslater("com.mingliqiye.utils.springboot.autoconfigure.JsonApiAutoConfiguration.jsonapiconfiged") + try { + JSONA.getJsonApi() + } catch (_: NullPointerException) { + JSONA.setJsonApi(it) + log.infoTranslater( + "com.mingliqiye.utils.springboot.autoconfigure.JsonApiAutoConfiguration.jsonause", + it.javaClass.name + ) + } + } } } diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/bean/SpringBeanUtils.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/bean/SpringBeanUtils.kt index 44ae843..741d4f3 100644 --- a/src/main/kotlin/com/mingliqiye/utils/springboot/bean/SpringBeanUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/bean/SpringBeanUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile SpringBeanUtils.kt - * LastUpdate 2025-09-19 20:07:08 + * LastUpdate 2026-02-04 16:50:39 * UpdateUser MingLiPro */ @@ -39,6 +39,9 @@ class SpringBeanUtils : ApplicationContextAware { @JvmStatic private var applicationContext: ApplicationContext? = null + @Throws(BeansException::class) + inline fun getBean() = getBean(T::class.java) + /** * 根据Bean名称获取Bean实例 * @@ -48,11 +51,9 @@ class SpringBeanUtils : ApplicationContextAware { * @throws ClassCastException 当类型转换失败时抛出 */ @JvmStatic - @Throws(BeansException::class, ClassCastException::class) + @Throws(BeansException::class) @Suppress("UNCHECKED_CAST") - fun getBean(name: String): T { - return applicationContext!!.getBean(name) as T - } + fun getBean(name: String): Any = applicationContext!!.getBean(name) /** * 根据Bean类型获取Bean实例 diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/converters/DateTimeToStringConverter.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/DateTimeToStringConverter.kt new file mode 100644 index 0000000..506fe78 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/DateTimeToStringConverter.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile DateTimeToStringConverter.kt + * LastUpdate 2026-02-04 21:57:43 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.springboot.converters + +import com.mingliqiye.utils.time.DateTime +import com.mingliqiye.utils.time.Formatter +import org.springframework.core.convert.converter.Converter +import org.springframework.stereotype.Component + +@Component +class DateTimeToStringConverter : Converter { + override fun convert(source: DateTime): String { + return source.format(Formatter.STANDARD_DATETIME) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/converters/Converters.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToDateTimeConverter.kt similarity index 62% rename from src/main/kotlin/com/mingliqiye/utils/springboot/converters/Converters.kt rename to src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToDateTimeConverter.kt index 3094705..02e1da5 100644 --- a/src/main/kotlin/com/mingliqiye/utils/springboot/converters/Converters.kt +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToDateTimeConverter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile Converters.kt - * LastUpdate 2025-09-15 09:19:48 + * CurrentFile StringToDateTimeConverter.kt + * LastUpdate 2026-02-04 21:57:43 * UpdateUser MingLiPro */ @@ -24,35 +24,12 @@ package com.mingliqiye.utils.springboot.converters import com.mingliqiye.utils.time.DateTime import com.mingliqiye.utils.time.Formatter -import com.mingliqiye.utils.uuid.UUID -import com.mingliqiye.utils.uuid.UUID.Companion.of import org.springframework.core.convert.converter.Converter import org.springframework.stereotype.Component -@Component -class DateTimeToStringConverter : Converter { - override fun convert(source: DateTime): String { - return source.format(Formatter.STANDARD_DATETIME) - } -} - -@Component -class UUIDToStringConverter : Converter { - override fun convert(source: UUID): String { - return source.getString() - } -} - @Component class StringToDateTimeConverter : Converter { override fun convert(source: String): DateTime { return DateTime.parse(source, Formatter.STANDARD_DATETIME_MILLISECOUND7, true) } } - -@Component -class StringToUUIDConverter : Converter { - override fun convert(source: String): UUID { - return of(source) - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/json/converters/JsonConverter.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToUUIDConverter.kt similarity index 59% rename from src/main/kotlin/com/mingliqiye/utils/json/converters/JsonConverter.kt rename to src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToUUIDConverter.kt index 32f00f0..6e55306 100644 --- a/src/main/kotlin/com/mingliqiye/utils/json/converters/JsonConverter.kt +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/StringToUUIDConverter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,22 +15,20 @@ * * ProjectName mingli-utils * ModuleName mingli-utils.main - * CurrentFile JsonConverter.kt - * LastUpdate 2025-09-15 11:12:07 + * CurrentFile StringToUUIDConverter.kt + * LastUpdate 2026-02-04 21:58:01 * UpdateUser MingLiPro */ -package com.mingliqiye.utils.json.converters +package com.mingliqiye.utils.springboot.converters -interface JsonConverter { - fun convert(obj: F?): T? - fun deConvert(obj: T?): F? - val tClass: Class +import com.mingliqiye.utils.uuid.UUID +import org.springframework.core.convert.converter.Converter +import org.springframework.stereotype.Component - fun getStringConverter(): JsonStringConverter? { - if (this is JsonStringConverter<*>) { - return this as JsonStringConverter - } - return null +@Component +class StringToUUIDConverter : Converter { + override fun convert(source: String): UUID { + return UUID.of(source) } } diff --git a/src/main/kotlin/com/mingliqiye/utils/springboot/converters/UUIDToStringConverter.kt b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/UUIDToStringConverter.kt new file mode 100644 index 0000000..0e4fc25 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/springboot/converters/UUIDToStringConverter.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UUIDToStringConverter.kt + * LastUpdate 2026-02-04 21:57:43 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.springboot.converters + +import com.mingliqiye.utils.uuid.UUID +import org.springframework.core.convert.converter.Converter +import org.springframework.stereotype.Component + +@Component +class UUIDToStringConverter : Converter { + override fun convert(source: UUID): String { + return source.getString() + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt b/src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt index 18c387b..60792ec 100644 --- a/src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt +++ b/src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,27 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile StringUtils.kt - * LastUpdate 2025-09-18 09:26:41 + * LastUpdate 2026-02-06 08:35:07 * UpdateUser MingLiPro */ @file:JvmName("StringUtils") package com.mingliqiye.utils.string -import com.mingliqiye.utils.logger.mingLiLoggerFactory +import com.mingliqiye.utils.base.BASE16 +import com.mingliqiye.utils.i18n.I18N.warnTranslater +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import com.mingliqiye.utils.objects.isNull +import java.net.URLDecoder +import java.net.URLEncoder +import java.security.MessageDigest +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract -val log = mingLiLoggerFactory.getLogger("StringUtils") +private val log = MingLiLoggerFactory.getLogger(Class.forName("com.mingliqiye.utils.string.StringUtils")) val NULLISH_STRINGS = setOf("null", "NaN", "undefined", "None", "none") @@ -36,11 +46,18 @@ val NULLISH_STRINGS = setOf("null", "NaN", "undefined", "None", "none") * @param str 待判断的字符串 * @return `true`: 空 `false`: 非空 */ +@OptIn(ExperimentalContracts::class) @JvmName("isEmpty") fun String?.isNullish(): Boolean { - return this == null || this.isBlank() || this in NULLISH_STRINGS + contract { + returns(false) implies (this@isNullish != null) + } + return this.isNullOrBlank() || this in NULLISH_STRINGS } +@JvmName("__Formatde") +fun String.formatd(vararg args: Any) = com.mingliqiye.utils.string.format(this, *args) + /** * 格式化字符串,将字符串中的占位符{}替换为对应的参数值 * @@ -82,8 +99,19 @@ fun format(str: String, vararg args: Any?): String { // 检查参数数量 val placeholderCount = matches.count() - if (argIndex != args.size) { - log.warn("Placeholder count: $placeholderCount, Argument count: ${args.size}") + if (placeholderCount != args.size) { + log.warnTranslater( + "com.mingliqiye.utils.string.StringUtils.format.warn.placeholder", + placeholderCount, args.size + ) + log.warnTranslater("com.mingliqiye.utils.string.StringUtils.format.warn.template", str) + log.warnTranslater( + "com.mingliqiye.utils.string.StringUtils.format.warn.arguments", + ", ".join(args) { + if (it.isNull()) return@join "null:null" + "${it.javaClass.simpleName}:$it" + } + ) } return finalResult @@ -214,3 +242,65 @@ fun String.join(list: List, getstring: (T) -> String = { it.toString() }) return sb.toString() } +fun String.join(array: Array, getstring: (T) -> String = { it.toString() }): String { + // 使用StringBuilder构建结果字符串 + val sb = StringBuilder() + for (i in array.indices) { + sb.append(getstring(array[i])) + // 除了最后一个元素外,都在后面添加当前字符串作为分隔符 + if (i != array.size - 1) { + sb.append(this) + } + } + return sb.toString() +} + +fun String?.parserTemplate(template: String): List? { + if (this == null) return null + val regex: Regex = Regex( + "^" + + template + .replace("\\", "\\\\") + .replace("(", "\\(") + .replace(")", "\\)") + .replace("[", "\\[") + .replace("]", "\\]") + .replace("+", "\\+") + .replace("=", "\\=") + .replace("{}", "((?s).*)") + .toRegex() + + "$" + ) + val datas = regex.find(this)?.groupValues ?: return null + return List(datas.size - 1) { + datas[it + 1] + } +} + + +fun String.urlEncode() = URLEncoder.encode(this, Charsets.UTF_8.name()) +fun String.urlDecode() = URLDecoder.decode(this, Charsets.UTF_8.name()) + + +fun String.hmacSHA256String(keyS: String): String { + val instance = Mac.getInstance("HmacSHA256") + val key = keyS.toByteArray() + instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256")) + val bytes = instance.doFinal(this.toByteArray()) + return BASE16.encode(bytes) +} + +fun String.md5String(): String { + val instance = MessageDigest.getInstance("MD5") + instance.update(this.toByteArray()) + val bytes = instance.digest() + return BASE16.encode(bytes) +} + +fun String.hmacMd5String(keyS: String): String { + val instance = Mac.getInstance("HmacMD5") + val key = keyS.toByteArray() + instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256")) + val bytes = instance.doFinal(this.toByteArray()) + return BASE16.encode(bytes) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/system/SystemUtil.kt b/src/main/kotlin/com/mingliqiye/utils/system/SystemUtil.kt index e0299c3..2add6d8 100644 --- a/src/main/kotlin/com/mingliqiye/utils/system/SystemUtil.kt +++ b/src/main/kotlin/com/mingliqiye/utils/system/SystemUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,16 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile SystemUtil.kt - * LastUpdate 2025-09-16 17:36:11 + * LastUpdate 2026-01-31 20:47:59 * UpdateUser MingLiPro */ @file:JvmName("SystemUtils") package com.mingliqiye.utils.system -import com.mingliqiye.utils.random.randomByteSecure +import com.mingliqiye.utils.random.randomByte import java.lang.management.ManagementFactory -import java.net.Inet4Address -import java.net.InetAddress -import java.net.NetworkInterface -import java.net.SocketException +import java.net.* /** * 操作系统名称属性,延迟初始化 @@ -256,10 +253,7 @@ val computerName: String by lazy { */ val userName: String by lazy { try { - getEnvVar("USERNAME") - ?: getEnvVar("USER") - ?: System.getProperty("user.name") - ?: "unknown" + getEnvVar("USERNAME") ?: getEnvVar("USER") ?: System.getProperty("user.name") ?: "unknown" } catch (e: SecurityException) { "unknown" } catch (e: Exception) { @@ -297,11 +291,11 @@ val macAddressBytes: ByteArray by lazy { return@lazy mac } } - randomByteSecure(6) + randomByte(6) } catch (e: SocketException) { - randomByteSecure(6) + randomByte(6) } catch (e: Exception) { - randomByteSecure(6) + randomByte(6) } } @@ -375,3 +369,91 @@ val allMacAddressesStringList: Map> by lazy { entry.value.map { String.format("%02X", it) } } } + +/** + * 获取可用处理器数量的懒加载属性 + */ +val availableProcessors: Int by lazy { + Runtime.getRuntime().availableProcessors() +} + + +private var isLoadprotocol = false +private var protocol = "" + + +/** + * 判断是否为开发模式(file协议) + */ +val isDevMode: Boolean by lazy { + protocol == "file" +} + +/** + * 判断是否不为开发模式 + */ +val isNotDevMode: Boolean by lazy { + protocol != "file" +} + +/** + * 判断是否为JAR模式 + */ +val isJarMode: Boolean by lazy { + protocol == "jar" +} + +/** + * 判断是否不为JAR模式 + */ +val isNotJarMode: Boolean by lazy { + protocol != "jar" +} + +/** + * 判断是否为WAR模式 + */ +val isWarMode: Boolean by lazy { + protocol == "war" +} + +/** + * 判断是否不为WAR模式 + */ +val isNotMode: Boolean by lazy { + protocol != "war" +} + +/** + * 判断是否为JSWAR模式 + */ +val isJswarMode: Boolean by lazy { + protocol == "jswar" +} + +/** + * 判断是否不为JSWAR模式 + */ +val isNotJswarMode: Boolean by lazy { + protocol != "jswar" +} + +/** + * 加载并获取资源协议 + * @param clazz 要获取协议的类对象,默认为null + * @return 返回资源的协议字符串 + */ +fun loadProtocol(clazz: Class<*>? = null): String { + // 如果已经加载过协议且clazz为null,则直接返回已缓存的协议 + if (isLoadprotocol && clazz == null) { + return protocol + } + val resource: URL? = clazz!!.getResource( + clazz.getSimpleName() + ".class" + ) + protocol = resource!!.protocol + return protocol.let { + isLoadprotocol = true + return@let it + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/thread/ThreadEvent.kt b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadEvent.kt new file mode 100644 index 0000000..9c14cef --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadEvent.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ThreadEvent.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.thread + +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +/** + * 线程事件同步工具类,用于线程间的事件通知和等待 + */ +open class ThreadEvent { + + private var latch = CountDownLatch(1) + + @Volatile + private var data: T + + constructor(data: T) { + this.data = data + } + + /** + * 获取当前事件状态 + * + * @return 当前事件的数据值,如果未设置则返回null + */ + fun get(): T = data + + /** + * 设置事件数据并释放等待的线程 + * + * @param data 要设置的事件数据 + */ + @Synchronized + fun set(data: T) { + this.data = data + latch.countDown() + } + + /** + * 重置事件状态,重新初始化CountDownLatch + */ + @Synchronized + fun reset() { + latch = CountDownLatch(1) + } + + /** + * 等待事件被设置,阻塞当前线程直到事件被触发 + */ + fun await() { + latch.await() + } + + /** + * 等待事件被设置并获取数据 + * + * @return 事件数据,当事件被设置后返回对应的数据 + */ + fun awaitAndGet(): T { + await() + return data + } + + /** + * 在指定超时时间内等待事件被设置并获取数据 + * + * @param timeout 等待超时时间 + * @param unit 时间单位 + * @return 事件数据,如果在超时时间内事件被设置则返回数据,否则返回null + */ + fun awaitAndGet(timeout: Long, unit: TimeUnit): T? { + await(timeout, unit) + return data + } + + /** + * 在指定超时时间内等待事件被设置 + * + * @param timeout 等待超时时间 + * @param unit 时间单位 + * @return 如果在超时时间内事件被设置则返回true,否则返回false + */ + fun await(timeout: Long, unit: TimeUnit): Boolean { + return latch.await(timeout, unit) + } + + fun setAndReset(data: T) { + set(data) + reset() + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/thread/ThreadRunner.kt b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadRunner.kt new file mode 100644 index 0000000..01c0604 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadRunner.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ThreadRunner.kt + * LastUpdate 2026-02-05 11:20:59 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.thread + +import com.mingliqiye.utils.netty.NamedThreadFactory +import com.mingliqiye.utils.system.availableProcessors +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.Future + +/** + * 线程执行器工具类,用于管理线程池并提供异步任务执行功能 + */ +object ThreadRunner { + + var executorService: ExecutorService? = null + + /** + * 关闭线程池执行器 + * 首先尝试正常关闭,如果失败则强制关闭 + */ + @JvmStatic + fun close() { + try { + executorService?.shutdown() + } catch (_: Exception) { + executorService?.shutdownNow() + } + } + + /** + * 初始化线程池执行器 + * 创建固定大小的线程池,线程数量为可用处理器核心数的两倍 + * + * @param string 线程名称前缀,默认为"MingliUtilThread" + */ + @JvmStatic + fun init(string: String = "MingliUtilThread") { + executorService = Executors.newFixedThreadPool( + availableProcessors * 2, + NamedThreadFactory { clazz, poolNumber, threadNumber -> + "$string #$threadNumber" + }) + } + + /** + * 异步执行Runnable任务 + * + * @param runnable 要执行的Runnable任务 + * @return Future对象,可用于获取任务执行结果或控制任务状态 + */ + @JvmStatic + fun runThread(runnable: Runnable): Future<*> { + return executorService!!.submit(runnable) + } + + /** + * 异步执行Callable任务 + * + * @param runnable 要执行的Callable任务 + * @return Future对象,可用于获取任务执行结果或控制任务状态 + */ + @JvmStatic + fun runThread(runnable: Callable): Future { + return executorService!!.submit(runnable) + } + + /** + * 同步执行Runnable任务,阻塞等待任务完成 + * + * @param runnable 要执行的Runnable任务 + * @return 任务执行结果(通常为null) + */ + @JvmStatic + fun runThreadAwait(runnable: Runnable): Any { + return executorService!!.submit(runnable).get() + } + + /** + * 同步执行Callable任务,阻塞等待任务完成并返回结果 + * + * @param runnable 要执行的Callable任务 + * @return 任务执行结果 + */ + @JvmStatic + fun runThreadAwait(runnable: Callable): T { + return executorService!!.submit(runnable).get() + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/thread/ThreadUtils.kt b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadUtils.kt new file mode 100644 index 0000000..f942b88 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/thread/ThreadUtils.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ThreadUtils.kt + * LastUpdate 2026-01-31 20:48:19 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.thread + +/** + * 线程工具类,提供线程名称的获取和设置功能 + */ +object ThreadUtils { + /** + * 获取或设置当前线程的名称 + * + * Getter: 返回当前线程的名称 + * Setter: 设置当前线程的名称 + * + * @return 当前线程的名称字符串 + */ + @JvmStatic + var name: String + get() = Thread.currentThread().name + set(s) { + Thread.currentThread().name = s + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/time/DateTime.kt b/src/main/kotlin/com/mingliqiye/utils/time/DateTime.kt index 880e604..a274873 100644 --- a/src/main/kotlin/com/mingliqiye/utils/time/DateTime.kt +++ b/src/main/kotlin/com/mingliqiye/utils/time/DateTime.kt @@ -1,5 +1,5 @@ /* - * Copyright 2025 mingliqiye + * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile DateTime.kt - * LastUpdate 2025-09-17 19:06:39 + * LastUpdate 2026-02-04 21:54:04 * UpdateUser MingLiPro */ @@ -26,7 +26,7 @@ import com.mingliqiye.utils.jna.FILETIME_EPOCH_OFFSET import com.mingliqiye.utils.jna.NANOS_PER_100NS import com.mingliqiye.utils.jna.WinKernel32Api import com.mingliqiye.utils.jna.getWinKernel32Apis -import com.mingliqiye.utils.logger.mingLiLoggerFactory +import com.mingliqiye.utils.logger.MingLiLoggerFactory import com.mingliqiye.utils.system.isWindows import com.mingliqiye.utils.system.javaVersionAsInteger import org.slf4j.Logger @@ -40,131 +40,6 @@ import kotlin.time.ExperimentalTime import kotlin.time.Instant -/** - * 时间位移 类 - * - * @author MingLiPro - */ -class DateTimeOffset private constructor( - val offsetType: ChronoUnit, val offset: Long -) { - - companion object { - /** - * 创建一个新的DateTimeOffset实例 - * - * @param offsetType 偏移量的单位类型,指定偏移量的计算单位 - * @param offset 偏移量的数值,可以为正数、负数或零 - * @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息 - */ - @JvmStatic - fun of(offsetType: ChronoUnit, offset: Long): DateTimeOffset { - return DateTimeOffset(offsetType, offset) - } - - /** - * 创建一个 DateTimeOffset 实例 - * - * @param offset 偏移量数值 - * @param offsetType 偏移量的时间单位类型 - * @return 返回一个新的 DateTimeOffset 实例 - */ - @JvmStatic - fun of(offset: Long, offsetType: ChronoUnit): DateTimeOffset { - return DateTimeOffset(offsetType, offset) - } - } -} - - -/** - * 时间格式化枚举类 - * - * - * 定义了常用的时间格式化模式,用于日期时间的解析和格式化操作 - * 每个枚举常量包含对应的格式化字符串和字符串长度 - * - */ -enum class Formatter(private val value: String) { - /** - * 标准日期时间格式:yyyy-MM-dd HH:mm:ss - */ - STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"), - - /** - * 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS - */ - STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"), - STANDARD_DATETIME_MILLISECOUND8("yyyy-MM-dd HH:mm:ss.SSSSSSSS"), - STANDARD_DATETIME_MILLISECOUND9("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"), - - /** - * 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS - */ - STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"), - - /** - * 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS - */ - STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"), - - /** - * 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS - */ - STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"), - - /** - * 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS - */ - STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"), - - /** - * 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS - */ - STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"), - - /** - * 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S - */ - STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"), - - /** - * 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z' - */ - STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), - - /** - * 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss - */ - STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"), - - /** - * 标准日期格式:yyyy-MM-dd - */ - STANDARD_DATE("yyyy-MM-dd"), - - /** - * ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSS'000' - */ - ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"), - - /** - * 紧凑型日期时间格式:yyyyMMddHHmmss - */ - COMPACT_DATETIME("yyyyMMddHHmmss"); - - - private val len: Int = value.length - - fun getLen(): Int { - return this.len - } - - fun getValue(): String { - return this.value - } -} - /** * 时间类,用于处理日期时间的转换、格式化等操作。 * 提供了多种静态方法来创建 DateTime 实例,并支持与 Date、LocalDateTime 等类型的互转。 @@ -186,7 +61,7 @@ class DateTime private constructor( companion object { private val WIN_KERNEL_32_API: WinKernel32Api? = if (javaVersionAsInteger == 8 && isWindows) { - val log: Logger = mingLiLoggerFactory.getLogger("mingli-utils DateTime") + val log: Logger = MingLiLoggerFactory.getLogger("mingli-utils DateTime") val a = getWinKernel32Apis() if (a.size > 1) { @@ -284,11 +159,10 @@ class DateTime private constructor( timestr: String ): DateTime { - val formatterString = Formatter.STANDARD_DATETIME_MILLISECOUND9.getValue() + val formatterString = Formatter.STANDARD_DATETIME_MILLISECOUND9.value return DateTime( LocalDateTime.parse( - getFillZeroByLen(timestr, formatterString), - DateTimeFormatter.ofPattern(formatterString) + getFillZeroByLen(timestr, formatterString), DateTimeFormatter.ofPattern(formatterString) ) ) } @@ -305,7 +179,7 @@ class DateTime private constructor( fun parse( timestr: String, formatter: Formatter, fillZero: Boolean ): DateTime { - return parse(timestr, formatter.getValue(), fillZero) + return parse(timestr, formatter.value, fillZero) } /** @@ -317,7 +191,7 @@ class DateTime private constructor( */ @JvmStatic fun parse(timestr: String, formatter: Formatter): DateTime { - return parse(timestr, formatter.getValue()) + return parse(timestr, formatter.value) } /** @@ -340,23 +214,24 @@ class DateTime private constructor( * @return 补零后的时间字符串 */ private fun getFillZeroByLen(dstr: String, formats: String): String { - if (dstr.length == formats.length) { + val formatslen = formats.replace("'", "").length + if (dstr.length == formatslen) { return dstr } - if (formats.length > dstr.length) { + if (formatslen > dstr.length) { var modifiedDstr = dstr if (dstr.length == 19) { modifiedDstr += "." } val sb = StringBuilder(modifiedDstr) - for (i in 0 until formats.length - sb.length) { + for (i in 0 until formatslen - sb.length) { sb.append("0") } return sb.toString() } throw IllegalArgumentException( String.format( - "Text: '%s' len %s < %s %s", dstr, dstr.length, formats, formats.length + "Text: '%s' len %s < %s %s", dstr, dstr.length, formats, formatslen ) ) } @@ -520,6 +395,20 @@ class DateTime private constructor( ) } + /** + * 重载加法运算符,将指定的DateTimeOffset添加到当前DateTime对象 + * @param dateTimeOffset 要添加的时间偏移量 + * @return 返回相加后的新DateTime对象 + */ + operator fun plus(dateTimeOffset: DateTimeOffset): DateTime = add(dateTimeOffset) + + /** + * 重载减法运算符,从当前DateTime对象中减去指定的DateTimeOffset + * @param dateTimeOffset 要减去的时间偏移量 + * @return 返回相减后的新DateTime对象 + */ + operator fun minus(dateTimeOffset: DateTimeOffset): DateTime = sub(dateTimeOffset) + /** * 在当前时间基础上减少指定的时间偏移量。 * @@ -547,11 +436,11 @@ class DateTime private constructor( * @return 返回格式化后的时间字符串 */ fun format(formatter: Formatter): String { - return format(formatter.getValue()) + return format(formatter.value) } fun format(): String { - return format(Formatter.STANDARD_DATETIME_MILLISECOUND9.getValue(), true) + return format(Formatter.STANDARD_DATETIME_MILLISECOUND9.value, true) } /** @@ -581,7 +470,7 @@ class DateTime private constructor( * @return 返回格式化后的时间字符串 */ fun format(formatter: Formatter, repcZero: Boolean): String { - return format(formatter.getValue(), repcZero) + return format(formatter.value, repcZero) } /** @@ -668,7 +557,6 @@ class DateTime private constructor( */ fun toNanoTime(): Long { val instant = toInstant() - return try { val secondsInNanos = Math.multiplyExact(instant.epochSecond, 1_000_000_000L) Math.addExact(secondsInNanos, instant.nano.toLong()) diff --git a/src/main/kotlin/com/mingliqiye/utils/time/DateTimeOffset.kt b/src/main/kotlin/com/mingliqiye/utils/time/DateTimeOffset.kt new file mode 100644 index 0000000..15e9b7a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/time/DateTimeOffset.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile DateTimeOffset.kt + * LastUpdate 2026-02-04 21:54:04 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.time + +import java.time.temporal.ChronoUnit + +/** + * 时间位移 类 + * + * @author MingLiPro + */ +class DateTimeOffset private constructor( + val offsetType: ChronoUnit, val offset: Long +) { + + companion object { + /** + * 创建一个新的DateTimeOffset实例 + * + * @param offsetType 偏移量的单位类型,指定偏移量的计算单位 + * @param offset 偏移量的数值,可以为正数、负数或零 + * @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息 + */ + @JvmStatic + fun of(offsetType: ChronoUnit, offset: Long): DateTimeOffset { + return DateTimeOffset(offsetType, offset) + } + + /** + * 创建一个 DateTimeOffset 实例 + * + * @param offset 偏移量数值 + * @param offsetType 偏移量的时间单位类型 + * @return 返回一个新的 DateTimeOffset 实例 + */ + @JvmStatic + fun of(offset: Long, offsetType: ChronoUnit): DateTimeOffset { + return DateTimeOffset(offsetType, offset) + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/time/Formatter.kt b/src/main/kotlin/com/mingliqiye/utils/time/Formatter.kt new file mode 100644 index 0000000..ca1397b --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/time/Formatter.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Formatter.kt + * LastUpdate 2026-02-04 21:54:36 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.time + +/** + * 时间格式化枚举类 + * + * + * 定义了常用的时间格式化模式,用于日期时间的解析和格式化操作 + * 每个枚举常量包含对应的格式化字符串和字符串长度 + * + */ +enum class Formatter(val value: String) { + /** + * 标准日期时间格式:yyyy-MM-dd HH:mm:ss + */ + STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"), + NONE(""), + + /** + * 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS + */ + STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"), + STANDARD_DATETIME_MILLISECOUND8("yyyy-MM-dd HH:mm:ss.SSSSSSSS"), + STANDARD_DATETIME_MILLISECOUND9("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"), + + /** + * 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS + */ + STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"), + + /** + * 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS + */ + STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"), + + /** + * 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS + */ + STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"), + + /** + * 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS + */ + STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"), + + /** + * 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS + */ + STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"), + + /** + * 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S + */ + STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"), + + /** + * 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + */ + STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), + + /** + * 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss + */ + STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"), + + /** + * 标准日期格式:yyyy-MM-dd + */ + STANDARD_DATE("yyyy-MM-dd"), + + /** + * ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSSSSS + */ + ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSSSSS"), + + /** + * 紧凑型日期时间格式:yyyyMMddHHmmss + */ + COMPACT_DATETIME("yyyyMMddHHmmss"); + + + private val len: Int = value.replace("'", "").length + + fun getLen(): Int { + return this.len + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt b/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt index a8319b1..80831ec 100644 --- a/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt +++ b/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt @@ -16,38 +16,47 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile MysqlUUIDv1.kt - * LastUpdate 2026-01-08 08:22:14 + * LastUpdate 2026-02-06 14:52:40 * UpdateUser MingLiPro */ @file:JvmName("MysqlUUIDConvertor") package com.mingliqiye.utils.uuid +import com.mingliqiye.utils.array.copyTo +/** + * 将标准UUID字节数组转换为MySQL存储格式的字节数组 + * MySQL中UUID的存储格式与标准UUID的字节顺序不同,需要重新排列字节顺序 + * + * @param uuid 标准UUID格式的字节数组(16字节) + * @return 转换后的MySQL存储格式字节数组(16字节) + * @since 4.6.2 + */ fun uuidToMysql(uuid: ByteArray): ByteArray { - val reuuid = ByteArray(16) - reuuid[4] = uuid[0] - reuuid[5] = uuid[1] - reuuid[6] = uuid[2] - reuuid[7] = uuid[3] - reuuid[2] = uuid[4] - reuuid[3] = uuid[5] - reuuid[0] = uuid[6] - reuuid[1] = uuid[7] - System.arraycopy(uuid, 8, reuuid, 8, 8) - return reuuid + return ByteArray(16).also { + // 按照MySQL UUID存储格式重新排列字节:前4字节、中间2字节、后2字节、最后8字节 + uuid.copyTo(it, 0, 4, 4) + .copyTo(it, 4, 2, 2) + .copyTo(it, 6, 0, 2) + .copyTo(it, 8, 8, 8) + } } +/** + * 将MySQL存储格式的UUID字节数组转换回标准UUID格式 + * MySQL中UUID的存储格式与标准UUID的字节顺序不同,需要恢复原始字节顺序 + * + * @param uuid MySQL存储格式的字节数组(16字节) + * @return 转换后的标准UUID格式字节数组(16字节) + * @since 4.6.2 + */ fun mysqlToUuid(uuid: ByteArray): ByteArray { - val reuuid = ByteArray(16) - reuuid[6] = uuid[0] - reuuid[7] = uuid[1] - reuuid[4] = uuid[2] - reuuid[5] = uuid[3] - reuuid[0] = uuid[4] - reuuid[1] = uuid[5] - reuuid[2] = uuid[6] - reuuid[3] = uuid[7] - System.arraycopy(uuid, 8, reuuid, 8, 8) - return reuuid + return ByteArray(16).also { + // 按照标准UUID格式恢复字节顺序:第6-7字节、第4-5字节、第0-3字节、第8-15字节 + uuid.copyTo(it, 0, 6, 2) + .copyTo(it, 2, 4, 2) + .copyTo(it, 4, 0, 4) + .copyTo(it, 8, 8, 8) + } } diff --git a/src/main/kotlin/com/mingliqiye/utils/uuid/UUID.kt b/src/main/kotlin/com/mingliqiye/utils/uuid/UUID.kt index 4d7fc71..4ef0295 100644 --- a/src/main/kotlin/com/mingliqiye/utils/uuid/UUID.kt +++ b/src/main/kotlin/com/mingliqiye/utils/uuid/UUID.kt @@ -16,16 +16,15 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile UUID.kt - * LastUpdate 2026-01-08 13:21:00 + * LastUpdate 2026-02-06 14:33:24 * UpdateUser MingLiPro */ package com.mingliqiye.utils.uuid -import com.mingliqiye.utils.base.BASE256 -import com.mingliqiye.utils.base.BASE64 -import com.mingliqiye.utils.base.BASE91 -import com.mingliqiye.utils.random.randomByteSecure +import com.mingliqiye.utils.base.* +import com.mingliqiye.utils.io.IO.println +import com.mingliqiye.utils.random.randomByte import com.mingliqiye.utils.random.secureRandom import com.mingliqiye.utils.system.macAddressBytes import com.mingliqiye.utils.time.DateTime @@ -109,7 +108,7 @@ class UUID : Serializable { */ @JvmStatic fun getV4(): UUID { - val randomBytes = randomByteSecure(16) + val randomBytes = randomByte(16) randomBytes[6] = (randomBytes[6].toInt() and 0x0F).toByte() randomBytes[6] = (randomBytes[6].toInt() or 0x40).toByte() randomBytes[8] = (randomBytes[8].toInt() and 0x3F).toByte() @@ -192,7 +191,7 @@ class UUID : Serializable { val buffer = ByteBuffer.allocate(16) buffer.putInt((instant shr 16).toInt()) buffer.putShort((instant).toShort()) - buffer.put(randomByteSecure(2)) + buffer.put(randomByte(2)) buffer.putLong(secureRandom.nextLong()) val bytes = buffer.array() bytes[6] = (bytes[6].toInt() and 0x0F or 0x70).toByte() @@ -363,6 +362,10 @@ class UUID : Serializable { return result } + fun of(str: String, base: BaseType): UUID { + return UUID(base.baseCodec.decode(str)) + } + } /** @@ -485,6 +488,18 @@ class UUID : Serializable { } } + fun getString(uuidFormatType: UUIDFormatType): String { + return getString(isUpper = uuidFormatType.isUpper, isnotSpace = uuidFormatType.isnotSpace) + } + + fun getString(baseType: BaseType): String { + return getString(baseType.baseCodec) + } + + fun getString(baseCodec: BaseCodec): String { + return baseCodec.encode(data) + } + /** * 返回标准格式的 UUID 字符串(带连字符)。 * @@ -556,8 +571,11 @@ class UUID : Serializable { * @return 如果相等则返回 true,否则返回 false */ override fun equals(other: Any?): Boolean { + if (this === other) return true return when (other) { is UUID -> { + this.println() + other.println() this.data.contentEquals(other.data) } diff --git a/src/main/kotlin/com/mingliqiye/utils/uuid/UUIDFormatType.kt b/src/main/kotlin/com/mingliqiye/utils/uuid/UUIDFormatType.kt new file mode 100644 index 0000000..4138464 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/uuid/UUIDFormatType.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UUIDFormatType.kt + * LastUpdate 2026-02-06 14:53:47 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.uuid + +/** + * UUID格式类型枚举 + * 定义了四种不同的UUID格式化选项,包括大小写和是否包含空格的组合 + * + * @property isUpper 是否使用大写字母 + * @property isnotSpace 是否不包含空格(true表示无空格,false表示有空格) + */ +enum class UUIDFormatType(val isUpper: Boolean, val isnotSpace: Boolean) { + /** + * 大写带分隔符 + * 使用大写字母并保留空格分隔符 + */ + UPPER_SPACE(true, false), + + /** + * 小写带分隔符 + * 使用小写字母并保留空格分隔符 + */ + NO_UPPER_SPACE(false, false), + + /** + * 小写无分隔符 + * 使用小写字母且不包含空格分隔符 + */ + NO_UPPER_NO_SPACE(false, true), + + /** + * 大写无分隔符 + * 使用大写字母且不包含空格分隔符 + */ + UPPER_NO_SPACE(true, true), +} diff --git a/src/main/resources/META-INF/meta-data b/src/main/resources/META-INF/meta-data index f65167e..d5e33d9 100644 --- a/src/main/resources/META-INF/meta-data +++ b/src/main/resources/META-INF/meta-data @@ -1,7 +1,7 @@ -buildTime=$buildTime -groupId=$GROUPSID -artifactId=$ARTIFACTID -version=$VERSIONS -buildJdkVersion=$JDKVERSIONS -author=MingLiPro -website=https://mingli-utils.mingliqiye.com +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.buildTime=$buildTime +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.groupId=$GROUPSID +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.artifactId=$ARTIFACTID +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.version=$VERSIONS +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.buildJdkVersion=$JDKVERSIONS +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.author=MingLiPro +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.website=https://mingli-utils.mingliqiye.com diff --git a/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000..0ff6f7d --- /dev/null +++ b/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,23 @@ +# +# Copyright 2026 mingliqiye +# +# 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 +# +# 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. +# +# ProjectName mingli-utils +# ModuleName mingli-utils.main +# CurrentFile javax.annotation.processing.Processor +# LastUpdate 2026-02-07 09:22:22 +# UpdateUser MingLiPro +# + +com.mingliqiye.utils.annotation.processor.AutoServiceProcessor diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index db0d345..343fd55 100644 --- a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,5 +1,5 @@ # -# Copyright 2025 mingliqiye +# Copyright 2026 mingliqiye # # 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,9 @@ # ProjectName mingli-utils # ModuleName mingli-utils.main # CurrentFile org.springframework.boot.autoconfigure.AutoConfiguration.imports -# LastUpdate 2025-09-15 22:32:50 +# LastUpdate 2026-02-04 16:47:27 # UpdateUser MingLiPro # com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration com.mingliqiye.utils.springboot.autoconfigure.JacksonAutoConfiguration -com.mingliqiye.utils.springboot.autoconfigure.GsonAutoConfiguration diff --git a/src/main/resources/assets/mingli-utils/icon.png b/src/main/resources/assets/mingli-utils/icon.png new file mode 100644 index 0000000..af567d4 Binary files /dev/null and b/src/main/resources/assets/mingli-utils/icon.png differ diff --git a/src/main/resources/assets/mingli-utils/lang/en_US.json b/src/main/resources/assets/mingli-utils/lang/en_US.json new file mode 100644 index 0000000..7124897 --- /dev/null +++ b/src/main/resources/assets/mingli-utils/lang/en_US.json @@ -0,0 +1,42 @@ +{ + "com.mingliqiye.utils": { + "i18n": { + "readjson": { + "error": "Failed to load language file %s" + } + }, + "springboot.autoconfigure": { + "AutoConfiguration": { + "jdkRuntime": "JDK Runtime Environment Version", + "pid": "Process PID", + "computerName": "Computer Name", + "userName": "User Name", + "time": "Current Time", + "buildTime": "Build Time", + "groupId": "Group ID", + "artifactId": "Artifact ID", + "version": "Version", + "buildJdkVersion": "Build JDK Version", + "author": "Author", + "website": "Official Website", + "bean": "MingliUtils Auto Configuration Bean Success" + }, + "JsonApiAutoConfiguration": { + "jsonause": "JSONA Using %s", + "jsonapiconfiged": "JsonApi Bean Auto Configuration Success", + "jacksonserializers": "MingliUtils Jackson Serializers created" + } + }, + "string": { + "StringUtils": { + "format": { + "warn": { + "placeholder": "Placeholder Count: %s, Argument Count: %s", + "template": "Template: %s", + "arguments": "Arguments: [%s]" + } + } + } + } + } +} diff --git a/src/main/resources/assets/mingli-utils/lang/zh_CN.json b/src/main/resources/assets/mingli-utils/lang/zh_CN.json new file mode 100644 index 0000000..528916f --- /dev/null +++ b/src/main/resources/assets/mingli-utils/lang/zh_CN.json @@ -0,0 +1,42 @@ +{ + "com.mingliqiye.utils": { + "i18n": { + "readjson": { + "error": "加载语言文件失败 %s" + } + }, + "springboot.autoconfigure": { + "AutoConfiguration": { + "jdkRuntime": "Jdk运行环境版本", + "pid": "程序Pid", + "computerName": "计算机名", + "userName": "用户名", + "time": "当前时间", + "buildTime": "编译时间", + "groupId": "组Id", + "artifactId": "组件Id", + "version": "版本", + "buildJdkVersion": "编译Jdk版本", + "author": "作者", + "website": "官方网址", + "bean": "MingliUtils 自动配置 Bean 成功" + }, + "JsonApiAutoConfiguration": { + "jsonause": "JSONA 使用 %s", + "jsonapiconfiged": "JsonApi Bean 自动配置成功", + "jacksonserializers": "MingliUtils Jackson 序列化器注册成功" + } + }, + "string": { + "StringUtils": { + "format": { + "warn": { + "placeholder": "占位符数量: %s, 参数数量: %s", + "template": "模板: %s", + "arguments": "参数: [%s]" + } + } + } + } + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..07f4024 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "mingli-utils", + "groupsId": "${GROUPSID}", + "artifactId": "${ARTIFACTID}", + "name": "Mingli-Utils", + "version": "${VERSIONS}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/mingli-utils/icon.png", + "contact": { + "homepage": "https://git.mingliqiye.com/minglipro/mingli-utils", + "issues": "https://git.mingliqiye.com/minglipro/mingli-utils/issues", + "sources": "https://git.mingliqiye.com/minglipro/mingli-utils" + }, + "buildTime": "${buildTime}", + "jdk": { + "version": "${JDKVERSIONS}" + }, + "authors": [ + "minglipro" + ], + "depends": { + "fabricloader": "*" + }, + "description": "A Java/kotlin Utils" +} diff --git a/src/test/kotlin/com/mingliqiye/utils/BaseTest.kt b/src/test/kotlin/com/mingliqiye/utils/BaseTest.kt new file mode 100644 index 0000000..bff6822 --- /dev/null +++ b/src/test/kotlin/com/mingliqiye/utils/BaseTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.test + * CurrentFile BaseTest.kt + * LastUpdate 2026-02-08 03:05:52 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils + +import com.mingliqiye.utils.base.code.* +import com.mingliqiye.utils.uuid.UUID +import org.junit.jupiter.api.Test + + +class BaseTest { + @Test + fun testBase2() { + val uuid = UUID.getV7() + val s = Base2.encode(uuid.toBytes()) + assert(uuid == UUID.of(Base2.decode(s))) + } + + @Test + fun testBase10() { + val uuid = UUID.getV7() + val s = Base10.encode(uuid.toBytes()) + assert(uuid == UUID.of(Base10.decode(s))) + } + + @Test + fun testBase16() { + val uuid = UUID.getV7() + val s = Base16.encode(uuid.toBytes()) + assert(uuid == UUID.of(Base16.decode(s))) + } + + @Test + fun testBase91() { + val uuid = UUID.getV7() + val s = Base91.encode(uuid.toBytes()) + assert(uuid == UUID.of(Base91.decode(s))) + } + + @Test + fun testBase256() { + val uuid = UUID.getV7() + val s = Base256.encode(uuid.toBytes()) + assert(uuid == UUID.of(Base256.decode(s))) + } +} diff --git a/src/test/kotlin/com/mingliqiye/utils/JsonTest.kt b/src/test/kotlin/com/mingliqiye/utils/JsonTest.kt new file mode 100644 index 0000000..b68f222 --- /dev/null +++ b/src/test/kotlin/com/mingliqiye/utils/JsonTest.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2026 mingliqiye + * + * 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 + * + * 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. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.test + * CurrentFile JsonTest.kt + * LastUpdate 2026-02-08 02:29:27 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.mingliqiye.utils.annotation.UUIDJsonFormat +import com.mingliqiye.utils.array.toHexString +import com.mingliqiye.utils.base.BaseType +import com.mingliqiye.utils.io.IO.println +import com.mingliqiye.utils.json.api.JSONA +import com.mingliqiye.utils.json.api.JacksonJsonApi +import com.mingliqiye.utils.json.converters.DateTimeJsonConverter +import com.mingliqiye.utils.json.converters.UUIDJsonConverter +import com.mingliqiye.utils.json.converters.base.JackSonJsonConverter.Companion.addJsonConverter +import com.mingliqiye.utils.json.converters.base.getJsonConverter +import com.mingliqiye.utils.logger.MingLiLoggerFactory +import com.mingliqiye.utils.string.formatd +import com.mingliqiye.utils.uuid.UUID +import com.mingliqiye.utils.uuid.UUIDFormatType +import com.mingliqiye.utils.uuid.mysqlToUuid +import com.mingliqiye.utils.uuid.uuidToMysql +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class JsonTest { + @Test + fun testJSONA() { + + JSONA.setJsonApi( + JacksonJsonApi( + JSONA.jacksonKotlinObjectMapper() + ) + ) + JSONA.addJsonConverter() + JSONA.addJsonConverter() + + "{} {} {} {}".formatd("0", 1).println() + } + + @Test + fun testBANNER() { + val log = MingLiLoggerFactory.getLogger() + com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.printBanner() + } + + @Test + fun testMysqld() { + val v = UUID.of("c3efb797-0323-11f1-8791-3aff070ec47d") + val ba = uuidToMysql(v.toBytes()) + val ca = mysqlToUuid(ba) + assertEquals( + "11F10323C3EFB79787913AFF070EC47D", + ba.toHexString().println() + ) + assertEquals( + "C3EFB797032311F187913AFF070EC47D", + ca.toHexString().println() + ) + } + + @Test + fun testGson2() { + getJsonConverter() + getJsonConverter() + } + + @Test + fun testGson() { + + val obm = jacksonObjectMapper() + .addJsonConverter() + .addJsonConverter() + + obm.readValue>>>( + obm.writeValueAsString( + AC(c = CC(b = ZZ(b = UUID.getV7()))) + ).println() + ).println() + } +} + +data class AC( + var a: String = "AC", + @field:UUIDJsonFormat( + base = BaseType.BASE256, + value = UUIDFormatType.UPPER_NO_SPACE + ) + var uuid: UUID = UUID.getV4(), + var b: BC = BC(), + var c: T +) + +data class BC( + var a: String = "BC", +) + +data class CC( + var a: String = "BC", + var b: T +) + + +data class ZZ( + var a: String = "ZZ", + @field:UUIDJsonFormat( + base = BaseType.BASE256, + value = UUIDFormatType.UPPER_NO_SPACE + ) + var b: T +) diff --git a/src/test/resources/lang/zh_CN.json b/src/test/resources/lang/zh_CN.json new file mode 100644 index 0000000..117e973 --- /dev/null +++ b/src/test/resources/lang/zh_CN.json @@ -0,0 +1,23 @@ +{ + "a": { + "b": { + "c": { + "d": "from {} d" + } + } + }, + "b": { + "b": { + "c": { + "d": "from {} d" + } + } + }, + "c": { + "b": { + "c": { + "d": "from {} d" + } + } + } +}