Compare commits

..

3 Commits

Author SHA1 Message Date
c98977116b
Merge pull request 'master' (#15) from master into dev
Reviewed-on: #15
2026-02-08 03:19:11 +08:00
450b4e1a93
feat(utils): 添加数组工具类和国际化支持
- 添加ByteArray.toHexString和String.toHexByteArray扩展函数
- 实现多种数组类型的copyTo和copyFrom扩展方法
- 在AutoConfiguration中集成I18N国际化功能
- 添加AutoService注解及处理器用于自动服务注册
- 新增BadGatewayException HTTP状态异常类
- 更新启动横幅格式并添加国际化文本支持
2026-02-08 03:17:14 +08:00
a5a532bc82
no message 2026-02-05 11:42:52 +08:00
156 changed files with 11045 additions and 2579 deletions

View File

@ -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<JavaExec>().configureEach {
)
}
kapt {
arguments {
arg(
"kapt.kotlin.generated",
project.layout.buildDirectory.dir("generated/source/kapt/main").get().asFile.absolutePath
)
}
}
tasks.withType<org.gradle.jvm.tasks.Jar> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from("LICENSE") { into("META-INF") }
@ -126,6 +149,8 @@ tasks.withType<org.gradle.jvm.tasks.Jar> {
}
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(

View File

@ -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

View File

@ -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")

View File

@ -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
*/

File diff suppressed because it is too large Load Diff

View File

@ -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<KClass<*>> = []
)

View File

@ -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,
)

View File

@ -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)

View File

@ -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
)

View File

@ -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<TypeElement>,
roundEnv: RoundEnvironment
): Boolean {
val service = mutableMapOf<String, MutableList<String>>()
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<String>? = service[data]
if (ldata == null) {
ldata = mutableListOf()
service[data] = ldata
}
ldata.add(element.toString())
}
}
processClassAnnotation(service)
return true
}
fun processClassAnnotation(map: Map<String, MutableList<String>>) {
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()
}
}
}
}

View File

@ -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 <T> Array<T>.copyTo(dest: Array<T>, srcPos: Int, distPos: Int, len: Int): Array<T> = 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 <T> Array<T>.copyTo(srcPos: Int, distPos: Int, len: Int): Array<T> =
java.lang.reflect.Array.newInstance(this.javaClass.componentType, len).also {
System.arraycopy(this, srcPos, it, distPos, len)
}.let {
@Suppress("UNCHECKED_CAST")
it as Array<T>
}
/**
* 将源数组的指定范围复制到当前数组
*
* @param src 源数组
* @param srcPos 源数组起始位置包含
* @param distPos 当前数组起始位置包含
* @param len 要复制的元素数量
* @return 当前数组自身支持链式调用
* @throws IndexOutOfBoundsException 如果索引超出范围
* @since 4.6.1
*/
@JvmName("arrayCopyFrom")
fun <T> Array<T>.copyFrom(src: Array<T>, srcPos: Int, distPos: Int, len: Int): Array<T> = 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)
}

View File

@ -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
}
}

View File

@ -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 待编码的字节数组

View File

@ -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
}
}

View File

@ -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(

View File

@ -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编码器实例

View File

@ -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 {
/**

View File

@ -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),
}

View File

@ -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

View File

@ -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()
}

View File

@ -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 <reified T> Serializable.deepClone(): T {
inline fun <reified T> 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

View File

@ -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<T> {
*/
private val atomicReferenceData: AtomicReference<T> = 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<T> {
*
* @return 当前数据值
*/
fun get(): T? {
fun get(): T {
return atomicReferenceData.get()
}
@ -77,7 +74,7 @@ class IsChanged<T> {
* @param data 要设置的新数据值
* @return 设置前的旧数据值
*/
fun setAndGet(data: T): T? {
fun setAndGet(data: T): T {
return atomicReferenceData.getAndSet(data)
}
@ -89,7 +86,7 @@ class IsChanged<T> {
* @return 如果值发生变化返回 true否则返回 false
*/
fun setAndChanged(data: T): Boolean {
var currentData: T?
var currentData: T
do {
currentData = get()
// 如果新值与当前值相等,则认为没有变化,直接返回 false

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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()
}
// 获取文件大小
/**
* 获取文件大小

View File

@ -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> T.with(function: Function): T = function.call().let {
this
}
fun <T> T.with(function: P1Function<T>): T = function.call(this).let {
this
}
@FunctionalInterface
fun interface Function {
fun call()
}
@FunctionalInterface
fun interface P1Function<P> {
fun call(p: P)
@ -128,3 +141,597 @@ fun interface P10Function<P, P1, P2, P3, P4, P5, P6, P7, P8, P9> {
fun interface P10RFunction<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23> {
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<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, R> {
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
}

View File

@ -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<T>(private val value: T) {
/**
* 对当前值进行转换操作并返回新的Pipeline实例
* @param transformer 转换函数接收当前值并返回转换后的结果
* @return 包含转换后结果的新Pipeline实例
*/
fun <R> transform(transformer: P1RFunction<T, R>): Pipeline<R> = Pipeline(transformer.call(value))
/**
* 对当前值进行转换操作功能与transform相同提供不同的方法名选择
* @param transformer 转换函数接收当前值并返回转换后的结果
* @return 包含转换后结果的新Pipeline实例
*/
fun <R> then(transformer: P1RFunction<T, R>): Pipeline<R> = transform(transformer)
/**
* 消费当前值但不改变流水线状态用于执行副作用操作
* @param consumer 消费函数接收当前值进行消费操作
* @return 当前Pipeline实例支持链式调用
*/
fun consume(consumer: P1Function<T>): Pipeline<T> {
consumer.call(value)
return this
}
/**
* 判断当前值是否为null
* @return true表示当前值为nullfalse表示不为null
*/
fun isNull(): Boolean = (value == null)
/**
* 判断当前值是否不为null
* @return true表示当前值不为nullfalse表示为null
*/
fun isNotNull(): Boolean = (value != null)
/**
* 根据条件过滤当前值如果条件满足则保持原值否则设置为null
* @param predicate 过滤条件函数接收当前值并返回布尔值
* @return 包含过滤后结果的Pipeline实例
*/
fun filter(predicate: P1RFunction<T, Boolean>): Pipeline<T?> =
if (predicate.call(value)) Pipeline(value) else Pipeline(null)
/**
* 获取当前流水线中的值
* @return 当前流水线中存储的值
*/
fun getValue(): T = value
/**
* 安全地转换当前值允许转换结果为null
* @param transformer 转换函数可能返回null
* @return 包含转换后结果可能为null的Pipeline实例
*/
fun <R> safeTransform(transformer: P1RFunction<T, R?>): Pipeline<R?> = Pipeline(transformer.call(value))
/**
* 将当前值映射为另一个Pipeline实例
* @param mapper 映射函数接收当前值并返回Pipeline实例
* @return 映射后的Pipeline实例
*/
fun <R> flatMap(mapper: P1RFunction<T, Pipeline<R>>): Pipeline<R> = mapper.call(value)
/**
* 将当前值映射为非null结果如果当前值为null则直接返回null
* @param mapper 映射函数可能返回null
* @return 包含映射后结果的Pipeline实例
*/
fun <R> mapNotNull(mapper: P1RFunction<T, R?>): Pipeline<out R?> =
if (value != null) Pipeline(mapper.call(value)!!) else Pipeline(null)
/**
* 将当前值强制转换为指定类型
* @param type 目标类型Class对象
* @return 包含转换后类型的Pipeline实例
* @throws ClassCastException 当类型转换失败时抛出异常
*/
@Throws(ClassCastException::class)
fun <E> cast(type: Class<E>): Pipeline<E> = Pipeline(value as E)
/**
* 根据条件判断是否保留当前值条件满足时保留否则返回null
* @param predicate 条件判断函数
* @return 包含条件判断结果的Pipeline实例
*/
fun takeIf(predicate: P1RFunction<T, Boolean>): Pipeline<T?> = Pipeline(if (predicate.call(value)) value else null)
/**
* 根据条件判断是否保留当前值条件不满足时保留否则返回null
* @param predicate 条件判断函数
* @return 包含条件判断结果的Pipeline实例
*/
fun takeUnless(predicate: P1RFunction<T, Boolean>): Pipeline<T?> =
Pipeline(if (!predicate.call(value)) value else null)
/**
* 在当前值上执行指定操作并返回操作结果
* @param block 执行函数接收当前值并返回结果
* @return 包含执行结果的Pipeline实例
*/
fun <R> let(block: P1RFunction<T, R>): Pipeline<R> = Pipeline(block.call(value))
/**
* 如果当前值不为null则返回自身否则返回默认值的Pipeline实例
* @param defaultValue 默认值
* @return 当前值或默认值的Pipeline实例
*/
fun orElse(defaultValue: T): Pipeline<T> = if (value != null) this else Pipeline(defaultValue)
/**
* 如果当前值不为null则返回自身否则通过供应商函数获取默认值
* @param supplier 默认值供应商函数
* @return 当前值或供应商提供的值的Pipeline实例
*/
fun orElseGet(supplier: RFunction<T>): Pipeline<T> = 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<out Exception> = IllegalArgumentException::class.java
): Pipeline<T> {
Require.require(Objects.equals(any, value), message, exception)
return this
}
/**
* 验证当前值是否等于指定值如果不相等则抛出IllegalArgumentException异常
* @param any 比较的目标值
* @param message 错误消息
* @return 当前Pipeline实例
*/
fun require(
any: Any, message: String
): Pipeline<T> {
Require.RequireLayz.require(any == value, message)
return this
}
/**
* 使用P1RFunction验证当前值是否满足条件不满足则抛出异常
* @param must 验证条件函数
* @param message 错误消息
* @param exception 异常类型默认为IllegalArgumentException
* @return 当前Pipeline实例
*/
fun require(
must: P1RFunction<T, Boolean>,
message: String,
exception: Class<out Throwable> = IllegalArgumentException::class.java
): Pipeline<T> {
Require.require(must.call(value), message, exception)
return this
}
/**
* 使用P1RFunction验证当前值是否满足条件不满足则抛出IllegalArgumentException异常
* @param must 验证条件函数
* @param message 错误消息
* @return 当前Pipeline实例
*/
fun require(
must: P1RFunction<T, Boolean>, message: String
): Pipeline<T> {
Require.require(must.call(value), message, IllegalArgumentException::class.java)
return this
}
/**
* 对当前值执行指定操作但不改变流水线状态
* @param block 执行函数接收当前值
* @return 当前Pipeline实例
*/
fun also(block: P1Function<T>): Pipeline<T> {
block.call(value)
return this
}
/**
* 验证当前值是否满足指定条件不满足则抛出IllegalArgumentException异常
* @param predicate 验证条件函数
* @param lazyMessage 延迟错误消息生成函数默认返回"Requirement failed"
* @return 当前Pipeline实例
*/
fun require(
predicate: P1RFunction<T, Boolean>,
lazyMessage: P1RFunction<T, Any> = P1RFunction { "Requirement failed" }
): Pipeline<T> {
if (!predicate.call(value)) {
throw IllegalArgumentException(lazyMessage.call(value).toString())
}
return this
}
/**
* 使用比较器比较当前值与另一个值
* @param other 另一个比较值
* @param comparator 比较器
* @return 比较结果负数表示小于0表示相等正数表示大于
*/
fun compareWith(other: T, comparator: Comparator<in T>): Int = comparator.compare(value, other)
/**
* 使用选择器将当前值转换为可比较类型后与另一个值比较
* @param other 另一个比较值
* @param selector 选择器函数将当前值转换为可比较类型
* @return 比较结果
*/
fun <R : Comparable<R>> compareTo(other: R, selector: P1RFunction<T, R>): Int =
selector.call(value).compareTo(other)
companion object {
/**
* 创建包含指定值的Pipeline实例
* @param value 要包装的值
* @return 新的Pipeline实例
*/
@JvmStatic
fun <T> of(value: T): Pipeline<T> = Pipeline(value)
/**
* 通过供应商函数创建Pipeline实例
* @param transformer 值供应商函数
* @return 新的Pipeline实例
*/
@JvmStatic
fun <T> of(transformer: RFunction<T>): Pipeline<T> = Pipeline(transformer.call())
}
}

View File

@ -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<T>(
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 {
/**
* 创建一个成功的响应对象仅包含消息
*
* @param message 响应消息
* @return Response<Any> 成功的响应对象
*/
@JvmStatic
fun <T> ok(data: T): Response<T?> {
return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), "操作成功", data, 200)
fun ok(message: String) = Response(
time = DateTime.now(),
message = message,
data = null,
statusCode = 200
)
/**
* 创建一个成功的响应对象仅包含数据
*
* @param T 响应数据的类型
* @param data 响应数据
* @return Response<T> 成功的响应对象
*/
@JvmStatic
fun <T> okData(data: T) = Response(
time = DateTime.now(),
message = "操作成功",
data = data,
statusCode = 200
)
/**
* 创建一个成功的响应对象包含数据和消息
*
* @param T 响应数据的类型
* @param data 响应数据
* @param message 响应消息
* @return Response<T> 成功的响应对象
*/
@JvmStatic
fun <T> okData(data: T, message: String) = Response(
time = DateTime.now(),
message = message,
data = data,
statusCode = 200
)
/**
* 创建一个指定状态码的响应对象仅包含状态码
*
* @param statusCode 状态码
* @return Response<Any> 指定状态码的响应对象
*/
@JvmStatic
fun code(statusCode: Int) = Response(
time = DateTime.now(),
message = "操作成功",
data = null,
statusCode = statusCode
)
/**
* 创建一个指定状态码的响应对象包含状态码和消息
*
* @param statusCode 状态码
* @param message 响应消息
* @return Response<Any> 指定状态码的响应对象
*/
@JvmStatic
fun code(statusCode: Int, message: String) = Response(
time = DateTime.now(),
message = message,
data = null,
statusCode = statusCode
)
}
@JvmStatic
fun <T> ok(message: String): Response<T?> {
return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), message, null, 200)
}
/**
* 默认构造函数创建一个默认的成功响应对象
*/
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<T> {
// 使用 DateTimeJsonConverter 将输入的字符串反序列化为时间对象,并更新内部 time 字段
time = DateTimeJsonConverter.getJsonConverter().deConvert(dateTime, AnnotationGetter.oneGetter(timeFormat))!!
return this
}
/**
* 获取响应消息
*
* @return String 响应消息
*/
fun getMessage(): String = message
/**
* 设置响应消息
*
* @param message 响应消息
* @return Response<T> 当前响应对象用于链式调用
*/
fun setMessage(message: String): Response<T> {
this.message = message
return this
}
fun setData(data: T): Response<T?> {
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<D> 当前响应对象用于链式调用
*
*/
fun setData(data: T): Response<T> {
this.data = data
return this
}
/**
* 创建一个新的Response对象使用指定的时间
*
* @param time 新的响应时间
* @return Response<T> 新的响应对象
*/
fun withTime(time: DateTime): Response<T> =
if (this.time == time) this else Response(time, message, data, statusCode)
/**
* 创建一个新的Response对象使用指定的数据
*
* @param D 新的数据类型
* @param data 新的响应数据
* @return Response<D> 新的响应对象
*/
fun <D> withData(data: D): Response<D> =
Response(this.time, this.message, data, this.statusCode)
/**
* 创建一个新的Response对象使用指定的消息
*
* @param message 新的响应消息
* @return Response<T> 新的响应对象
*/
fun withMessage(message: String): Response<T> =
if (this.message == message) this else Response(time, message, data, statusCode)
/**
* 创建一个新的Response对象使用指定的状态码
*
* @param statusCode 新的状态码
* @return Response<T> 新的响应对象
*/
fun withStatusCode(statusCode: Int): Response<T> =
if (this.statusCode == statusCode) this else Response(time, message, data, statusCode)
/**
* 获取状态码
*
* @return Int 状态码
*/
fun getStatusCode(): Int = statusCode
/**
* 设置状态码
*
* @param statusCode 状态码
* @return Response<T> 当前响应对象用于链式调用
*/
fun setStatusCode(statusCode: Int): Response<T> {
this.statusCode = statusCode
return this
}
fun writeTimeFormat(timeFormat: DateTimeJsonFormat): Response<T> {
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()})"
}

View File

@ -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
)
}
}

View File

@ -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<Internationalization>()
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<String, MutableMap<String, String>> = 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<String, String>) {
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)
}
}
}
}

View File

@ -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,37 +16,96 @@
* 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
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
fun Any?.println() {
IO.println(this)
/**
* IO工具类提供打印功能和系统输出流重定向到日志的功能
*/
object IO {
@JvmStatic
fun ByteArray.println(): ByteArray {
this.toHexString().chunked(2).println()
return this
}
@JvmStatic
fun <T> List<T>.println(): List<T> {
println("{" + ",".join(this) + "}")
return this
}
class IO {
companion object {
@JvmStatic
fun <T> Array<T>.println(): Array<T> {
println("{" + ",".join(this) + "}")
return this
}
@JvmStatic
fun <T> 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()) {
@ -59,5 +118,122 @@ class IO {
}
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)
}
}

View File

@ -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 <T> parse(json: String, clazz: Class<T>): T {
return gson.fromJson(json, clazz)
}
override fun <T> parse(json: String, type: JsonTypeReference<T>): 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 <T, D> convert(source: T, destinationClass: Class<D>): D {
val json = gson.toJson(source)
return gson.fromJson(json, destinationClass)
}
override fun <T, D> convert(source: T, destinationType: JsonTypeReference<D>): 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)
}
}

View File

@ -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 <reified T : JsonApi> setJsonApi() {
setJsonApi(T::class.java.newInstance() as JsonApi)
}
/**
* 将JSON字符串解析为指定类型的对象
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parse(json: String, clazz: Class<T>): T = getJsonApi().parse(json, clazz)
/**
* 将JSON字符串解析为指定泛型类型对象
*
* @param json 待解析的JSON字符串
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
inline fun <reified T> parse(json: String): T {
return getJsonApi().parse(json, (object : JsonTypeReference<T>() {}))
}
/**
* 将字节数组形式的JSON解析为指定泛型类型对象
*
* @param json 待解析的JSON字节数组
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
inline fun <reified T> parse(json: ByteArray): T = getJsonApi().parse(json, object : JsonTypeReference<T>() {})
/**
* 将JSON字符串解析为指定泛型类型对象
*
* @param json 待解析的JSON字符串
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parse(json: String, type: JsonTypeReference<T>): 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 <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(path: String, clazz: Class<T>): T = getJsonApi().parseFrom(path, clazz)
/**
* 从Path对象解析JSON为指定类型的对象
*
* @param path Path对象
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(path: Path, clazz: Class<T>): T = getJsonApi().parseFrom(path, clazz)
/**
* 从File对象解析JSON为指定类型的对象
*
* @param file File对象
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(file: File, clazz: Class<T>): T = getJsonApi().parseFrom(file, clazz)
/**
* 从InputStream解析JSON为指定类型的对象
*
* @param inputStream InputStream对象
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(inputStream: InputStream, clazz: Class<T>): T = getJsonApi().parseFrom(inputStream, clazz)
/**
* 从文件路径解析JSON为指定泛型类型对象
*
* @param path 文件路径
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(path: String, type: JsonTypeReference<T>): T = getJsonApi().parseFrom(path, type)
/**
* 从Path对象解析JSON为指定泛型类型对象
*
* @param path Path对象
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(path: Path, type: JsonTypeReference<T>): T = getJsonApi().parseFrom(path, type)
/**
* 从File对象解析JSON为指定泛型类型对象
*
* @param file File对象
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(file: File, type: JsonTypeReference<T>): T = getJsonApi().parseFrom(file, type)
/**
* 从InputStream解析JSON为指定泛型类型对象
*
* @param inputStream InputStream对象
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parseFrom(inputStream: InputStream, type: JsonTypeReference<T>): T =
getJsonApi().parseFrom(inputStream, type)
/**
* 将字节数组形式的JSON解析为指定类型的对象
*
* @param json 待解析的JSON字节数组
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parse(json: ByteArray, clazz: Class<T>): T = getJsonApi().parse(json, clazz)
/**
* 将字节数组形式的JSON解析为指定泛型类型对象
*
* @param json 待解析的JSON字节数组
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
@JvmStatic
fun <T> parse(json: ByteArray, type: JsonTypeReference<T>): T = getJsonApi().parse(json, type)
/**
* 将JSON字符串解析为指定类型的对象解析失败时返回默认值
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象的Class类型
* @param defaultValue 解析失败时返回的默认值
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例或默认值
*/
@JvmStatic
fun <T> parse(json: String, clazz: Class<T>, defaultValue: T): T = getJsonApi().parse(json, clazz, defaultValue)
/**
* 将JSON字符串解析为指定泛型类型对象解析失败时返回默认值
*
* @param json 待解析的JSON字符串
* @param type 目标对象的Type类型支持泛型
* @param defaultValue 解析失败时返回的默认值
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例或默认值
*/
@JvmStatic
fun <T> parse(
json: String, type: JsonTypeReference<T>, 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 <T> 泛型参数表示List中元素的类型
* @return 解析后的List集合
*/
@JvmStatic
fun <T> parseList(json: String, elementType: Class<T>): List<T> = parse(json, listType(elementType))
/**
* 将JSON字符串解析为指定元素类型的List集合
*
* @param json 待解析的JSON字符串
* @param <T> 泛型参数表示List中元素的类型
* @return 解析后的List集合
*/
@JvmStatic
inline fun <reified T> parseList(json: String): List<T> = parse(json, listType(T::class.java))
/**
* 将JSON字符串解析为指定键值类型的Map集合
*
* @param json 待解析的JSON字符串
* @param keyType Map中键的类型
* @param valueType Map中值的类型
* @param <K> 泛型参数表示Map中键的类型
* @param <V> 泛型参数表示Map中值的类型
* @return 解析后的Map集合
*/
@JvmStatic
fun <K, V> parseMap(
json: String, keyType: Class<K>, valueType: Class<V>
): MutableMap<K, V> = getJsonApi().parseMap(json, keyType, valueType)
/**
* 将JSON字符串解析为指定键值类型的Map集合
*
* @param json 待解析的JSON字符串
* @param <K> 泛型参数表示Map中键的类型
* @param <V> 泛型参数表示Map中值的类型
* @return 解析后的Map集合
*/
@JvmStatic
inline fun <reified K, reified V> parseMap(
json: String
): MutableMap<K, V> = 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 <D> convert(source: Any, destinationClass: Class<D>): D = getJsonApi().convert(source, destinationClass)
/**
* 使用内联函数和reified类型参数将源对象转换为目标类型的对象
*
* @param T 源对象的类型
* @param D 目标对象的类型通过reified类型参数推断
* @param source 需要转换的源对象
* @return 转换后的目标类型对象
*/
@JvmStatic
inline fun <reified D> convert(source: Any): D = getJsonApi().convert(source, object : JsonTypeReference<D>() {})
/**
* 将源对象转换为目标类型的对象使用JsonTypeReference指定目标类型
*
* @param T 源对象的类型
* @param D 目标对象的类型
* @param source 需要转换的源对象
* @param destinationType 目标对象的JsonTypeReference类型引用
* @return 转换后的目标类型对象
*/
@JvmStatic
fun <D> convert(source: Any, destinationType: JsonTypeReference<D>): 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 <reified T : BaseJsonConverter<*, *>> addJsonConverter() =
addJsonConverter(T::class.java.newInstance())
inline fun <reified T> String.parseJson() = parse<T>(this)
inline fun <reified T> ByteArray.parseJson() = parse<T>(this)
inline fun <reified T> InputStream.parseJson() = this.use { parse<T>(readBytes()) }
inline fun <reified T> File.parseJson() = this.inputStream().parseJson<T>()
inline fun <reified T> Path.parseJson() = this.toFile().inputStream().parseJson<T>()
fun Any.toJson() = format(this)
fun jacksonKotlinObjectMapper(): ObjectMapper = ObjectMapper().jacksonKotlinObjectMapper()
fun ObjectMapper.jacksonKotlinObjectMapper(): ObjectMapper = this.registerModule(kotlinModule())
}

View File

@ -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 <T> parse(json: String, clazz: Class<T>): 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<JsonNode>(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<JsonNode>(
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 <D> 目标对象类型
* @return 转换后的对象
*/
override fun <T, D> convert(source: T, destinationClass: Class<D>): D {
override fun <D> convert(source: Any, destinationClass: Class<D>): 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 <D> 目标对象类型
* @return 转换后的对象
*/
override fun <T, D> convert(source: T, destinationType: JsonTypeReference<D>): D {
override fun <D> convert(source: Any, destinationType: JsonTypeReference<D>): D {
try {
return objectMapper.convertValue(
source,
objectMapper.constructType(destinationType.type)
source, objectMapper.constructType(destinationType.type)
)
}
override fun addJsonConverter(c: JsonConverter<*, *>) {
c.getStringConverter()?.let {
objectMapper.registerModule(it.jacksonJsonStringConverterAdapter.jacksonModule)
} 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)
}
}
}

View File

@ -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 <reified T> JsonApi.parse(json: String): T = parse(json, object : JsonTypeReference<T>() {})
/**
* 将JSON字节数组解析为指定泛型类型对象
*
* @param json 待解析的JSON字节数组
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
inline fun <reified T> JsonApi.parse(json: ByteArray): T = parse(json, object : JsonTypeReference<T>() {})
/**
* 将JSON字符串解析为指定泛型类型对象解析失败时返回默认值
*
* @param json 待解析的JSON字符串
* @param defect 解析失败时返回的默认值
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例或默认值
*/
inline fun <reified T> JsonApi.parse(json: String, defect: T): T =
parse(json, object : JsonTypeReference<T>() {}, defect)
/**
* 从文件路径读取JSON并解析为指定泛型类型对象
*
* @param path 文件路径
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
inline fun <reified T> JsonApi.parseFrom(path: String): T = parseFrom(path, object : JsonTypeReference<T>() {})
/**
* 从文件读取JSON并解析为指定泛型类型对象
*
* @param path 文件对象
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
inline fun <reified T> JsonApi.parseFrom(path: File): T = parseFrom(path, object : JsonTypeReference<T>() {})
/**
* 从输入流读取JSON并解析为指定泛型类型对象
*
* @param path 输入流
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
inline fun <reified T> JsonApi.parseFrom(path: InputStream): T =
parseFrom(path, object : JsonTypeReference<T>() {})
/**
* 从路径读取JSON并解析为指定泛型类型对象
*
* @param path 路径对象
* @param T 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
inline fun <reified T> JsonApi.parseFrom(path: Path): T = parseFrom(path, object : JsonTypeReference<T>() {})
/**
* 将JSON字符串解析为指定键值类型的Map集合
*
* @param json 待解析的JSON字符串
* @param K 泛型参数表示Map中键的类型
* @param V 泛型参数表示Map中值的类型
* @return 解析后的Map集合
*/
inline fun <reified K, reified V> JsonApi.parseMap(
json: String
): MutableMap<K, V> = parseMap(json, K::class.java, V::class.java)
/**
* 使用内联函数和reified类型参数将源对象转换为目标类型的对象
*
* @param T 源对象的类型
* @param D 目标对象的类型通过reified类型参数推断
* @param source 需要转换的源对象
* @return 转换后的目标类型对象
*/
@JvmStatic
inline fun <reified D> JsonApi.convert(source: Any): D = convert(source, object : JsonTypeReference<D>() {})
/**
* 添加JSON转换器到API中
*
* @param T 需要添加的JSON转换器类
*/
@JvmStatic
inline fun <reified T : BaseJsonConverter<*, *>> 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 <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(path: String, clazz: Class<T>): T {
return parseFrom(Paths.get(path), clazz)
}
@Throws(IOException::class)
/**
* 从路径读取JSON并解析为指定类型对象
*
* @param path 路径对象
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(path: Path, clazz: Class<T>): T {
return parseFrom(path.toFile(), clazz)
}
@Throws(IOException::class)
/**
* 从文件读取JSON并解析为指定类型对象
*
* @param file 文件对象
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(file: File, clazz: Class<T>): T {
Files.newInputStream(file.toPath()).use { inputStream ->
return parseFrom(inputStream, clazz)
}
}
@Throws(IOException::class)
/**
* 从输入流读取JSON并解析为指定类型对象
*
* @param inputStream 输入流
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(inputStream: InputStream, clazz: Class<T>): T {
val bytes = ByteArray(1024)
ByteArrayOutputStream().use { bos ->
@ -93,24 +225,52 @@ interface JsonApi {
}
}
@Throws(IOException::class)
/**
* 从文件路径读取JSON并解析为指定泛型类型对象
*
* @param path 文件路径
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(path: String, type: JsonTypeReference<T>): T {
return parseFrom(Paths.get(path), type)
}
@Throws(IOException::class)
/**
* 从路径读取JSON并解析为指定泛型类型对象
*
* @param path 路径对象
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(path: Path, type: JsonTypeReference<T>): T {
return parseFrom(path.toFile(), type)
}
@Throws(IOException::class)
/**
* 从文件读取JSON并解析为指定泛型类型对象
*
* @param file 文件对象
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(file: File, type: JsonTypeReference<T>): T {
Files.newInputStream(file.toPath()).use { inputStream ->
return parseFrom<T>(inputStream, type)
}
}
@Throws(IOException::class)
/**
* 从输入流读取JSON并解析为指定泛型类型对象
*
* @param inputStream 输入流
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
fun <T> parseFrom(inputStream: InputStream, type: JsonTypeReference<T>): T {
val bytes = ByteArray(1024)
ByteArrayOutputStream().use { bos ->
@ -156,10 +316,10 @@ interface JsonApi {
* @return 解析后的对象实例或默认值
</T> */
fun <T> parse(json: String, clazz: Class<T>, 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 <T> parse(
json: String,
type: JsonTypeReference<T>,
defaultValue: T
json: String, type: JsonTypeReference<T>, defaultValue: T
): T {
try {
return parse<T>(json, type)
return try {
parse<T>(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集合
</V></K> */
fun <K, V> parseMap(
json: String,
keyType: Class<K>,
valueType: Class<V>
json: String, keyType: Class<K>, valueType: Class<V>
): MutableMap<K, V> {
val mapType: JsonTypeReference<MutableMap<K, V>> = object : JsonTypeReference<MutableMap<K, V>>() {}
return parse<MutableMap<K, V>>(json, mapType)
@ -384,10 +524,9 @@ interface JsonApi {
*/
fun updateNodeValue(json: String, path: String, newValue: Any): String
fun <T, D> convert(source: T, destinationClass: Class<D>): D
fun <D> convert(source: Any, destinationClass: Class<D>): D
fun <T, D> convert(source: T, destinationType: JsonTypeReference<D>): D
fun <D> convert(source: Any, destinationType: JsonTypeReference<D>): D
fun addJsonConverter(c: JsonConverter<*, *>)
fun addJsonStringConverter(c: JsonStringConverter<*>)
fun addJsonConverter(c: BaseJsonConverter<*, *>)
}

View File

@ -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<T> : Comparable<JsonTypeReference<T>> {
* @return 类型引用实例
*/
companion object {
@JvmStatic
fun <T> of(): JsonTypeReference<T> {
inline fun <reified T> of(): JsonTypeReference<T> {
return object : JsonTypeReference<T>() {}
}
@ -116,6 +115,11 @@ abstract class JsonTypeReference<T> : Comparable<JsonTypeReference<T>> {
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<T> : Comparable<JsonTypeReference<T>> {
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<T> : Comparable<JsonTypeReference<T>> {
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<T>): Int {
return this.type.toString().compareTo(other.type.toString())
}

View File

@ -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

View File

@ -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<out Type> = paramType
override fun getActualTypeArguments(): Array<out Type> = 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 <reified T> of(): TypeReference {
return of((object : JsonTypeReference<T>() {}).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")
}
}
}

View File

@ -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<DateTime> {
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<DateTimeJsonFormat>()
// 根据注解中的格式化规则进行转换
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<DateTimeJsonFormat>()
// 根据注解中的解析规则进行转换
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<DateTime> = JsonTypeReference.of<DateTime>()
}

View File

@ -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 <T> 需要转换的对象类型
</T> */
abstract class JsonStringConverter<T> : JsonConverter<T, String> {
val fastjsonJsonStringConverterAdapter: FastjsonJsonStringConverterAdapter<JsonStringConverter<T>, T>
/**
* 获取 Fastjson 的适配器
* @return 适配器实例
*/
get() = FastjsonJsonStringConverterAdapter.of(this)
val gsonJsonStringConverterAdapter: GsonJsonStringConverterAdapter<JsonStringConverter<T>, T>
/**
* 获取 Gson 的适配器
* @return 适配器实例
*/
get() = GsonJsonStringConverterAdapter.of(this)
val jacksonJsonStringConverterAdapter: JacksonJsonStringConverterAdapter<JsonStringConverter<T>, T>
/**
* 获取 Jackson 的适配器
* @return 适配器实例
*/
get() = JacksonJsonStringConverterAdapter.of(this)
}
class JacksonJsonStringConverterAdapter<T : JsonStringConverter<TT>, TT
> private constructor(val jsonStringConverter: T) {
val jacksonJsonDeserializer: JsonDeserializer<TT?>
/**
* 获取Jackson反序列化器
*
* @return Jackson的JsonDeserializer实例
*/
get() = object : JsonDeserializer<TT?>() {
@Throws(IOException::class)
override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): TT? {
if (p.isNaN) return null
return jsonStringConverter.deConvert(p.valueAsString)
}
}
val jacksonJsonSerializer: JsonSerializer<TT?>
/**
* 获取Jackson序列化器
*
* @return Jackson的JsonSerializer实例
*/
get() = object : JsonSerializer<TT?>() {
@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<TT?>(tClass, this.jacksonJsonSerializer)
m.addDeserializer<TT?>(tClass, this.jacksonJsonDeserializer)
return m
}
companion object {
/**
*
* @param t JSON转换器实例
* @return JSON转换器的适配器
* @param <T> JSON转换器
* @param <TT> JSON转换器的泛型
**/
fun <T : JsonStringConverter<TT>, TT
> of(t: T): JacksonJsonStringConverterAdapter<T, TT> {
return JacksonJsonStringConverterAdapter(t)
}
}
}
class GsonJsonStringConverterAdapter<T : JsonStringConverter<TT>, TT
>(val jsonStringConverter: T) {
val gsonTypeAdapter: TypeAdapter<TT?>
/**
* 获取Gson类型适配器
*
* @return Gson的TypeAdapter实例
*/
get() = object : TypeAdapter<TT?>() {
@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 <T : JsonStringConverter<TT>, TT
> of(t: T): GsonJsonStringConverterAdapter<T, TT> {
return GsonJsonStringConverterAdapter(t)
}
}
}
class FastjsonJsonStringConverterAdapter<T : JsonConverter<TT, String>, TT
>(val jsonStringConverter: T) {
@Suppress("UNCHECKED_CAST")
val fastJsonObjectWriter: ObjectWriter<T>
/**
* 获取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<TT>
/**
* 获取FastJson对象读取器
*
* @return FastJson的ObjectReader实例
*/
get() = ObjectReader { reader: JSONReader?, _: Type?, _: Any?, _: Long
->
val value = reader!!.readString()
jsonStringConverter.deConvert(value)
}
companion object {
fun <T : JsonConverter<TT, String>, TT
> of(t: T): FastjsonJsonStringConverterAdapter<T, TT> {
return FastjsonJsonStringConverterAdapter(t)
}
}
}
class DateTimeJsonConverter : JsonStringConverter<DateTime>() {
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<UUID>() {
override val tClass: Class<UUID> = 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)
}
}

View File

@ -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<UUID> {
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<UUIDJsonFormat>() ?: 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<UUIDJsonFormat>() ?: 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<UUID>()
}

View File

@ -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 <T : Annotation> get(clazz: Class<T>): T?
companion object {
/**
* 使用内联函数和重ified类型参数简化注解获取操作
* 通过传入泛型参数自动推断注解类型避免手动传递Class对象
*
* @param T 注解类型必须继承自Annotation
* @return 返回对应类型的注解实例如果未找到则返回null
*/
inline fun <reified T : Annotation> AnnotationGetter.get(): T? = this.get(T::class.java)
/**
* 提供一个默认实现始终返回null
* 可用于需要空注解获取器的场景
*/
val nullGetter = object : AnnotationGetter {
/**
* 始终返回null不执行任何实际逻辑
*
* @param clazz 注解的Class对象未使用
* @return 始终返回null
*/
override fun <T : Annotation> get(clazz: Class<T>): 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 <T : Annotation> get(clazz: Class<T>): T? =
if (annotation.javaClass == clazz) annotation as T else null
}
}
}

View File

@ -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<E> : BaseJsonConverter<E, BigDecimal> {
/**
* 获取目标类型的引用信息
*
* 该方法返回一个 [JsonTypeReference] 对象表示目标类型为 [BigDecimal]
* 通过调用 [JsonTypeReference.Companion.of] 方法创建类型引用
*
* @return 目标类型 [BigDecimal] 的类型引用
* @throws Exception 如果在获取类型引用时发生异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<BigDecimal>()
}

View File

@ -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<E> : BaseJsonConverter<E, BigInteger> {
/**
* 获取目标类型的引用用于 JSON 反序列化时确定目标类型
* 该方法重写了父接口中的 [getToType] 方法并返回 `BigInteger` 类型的引用
*
* @return 返回 [JsonTypeReference] 对象表示 `BigInteger` 类型的引用
* @throws Exception 如果在获取类型引用过程中发生异常则抛出该异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<BigInteger>()
}

View File

@ -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<E> : BaseJsonConverter<E, Boolean> {
/**
* 获取目标类型的引用信息
*
* 该方法返回一个 [JsonTypeReference] 对象表示目标类型为 [Boolean]
* 此方法重写了父接口中的定义并通过 [JsonTypeReference.Companion.of] 方法获取布尔类型的引用
*
* @return [JsonTypeReference<Boolean>] 表示布尔类型的引用
* @throws Exception 如果在获取类型引用时发生异常则抛出此异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Boolean>()
}

View File

@ -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<E> : BaseJsonConverter<E, Byte> {
/**
* 获取目标类型的引用用于标识转换的目标类型为 Byte
*
* @return 返回 JsonTypeReference 类型的实例表示目标类型为 Byte
* @throws Exception 如果在获取类型引用过程中发生异常则抛出该异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Byte>()
}

View File

@ -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<F, T> : JackSonJsonConverter<F, T>

View File

@ -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<E> : BaseJsonConverter<E, Double> {
/**
* 获取目标类型的引用用于标识转换的目标类型为 Double
*
* @return 返回 JsonTypeReference<Double> 类型的实例表示目标类型为 Double
* @throws Exception 如果在获取类型引用时发生异常则抛出该异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Double>()
}

View File

@ -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<E> : BaseJsonConverter<E, Float> {
/**
* 获取目标类型的引用信息
*
* 该方法重写了父接口中的 [getToType] 方法返回 [Float] 类型的 [JsonTypeReference] 实例
* 用于标识当前转换器的目标类型为 [Float]
*
* @return [JsonTypeReference] 表示 [Float] 类型的引用信息
* @throws Exception 如果在获取类型引用时发生异常则抛出此异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Float>()
}

View File

@ -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<E> : BaseJsonConverter<E, Int> {
/**
* 获取目标类型的引用信息
*
* 该方法重写了父接口中的 [getToType] 方法返回 [Int] 类型的 [JsonTypeReference] 实例
* 用于标识当前转换器的目标类型为 [Int]
*
* @return 返回 [JsonTypeReference] 的实例表示目标类型为 [Int]
* @throws Exception 如果在获取类型引用时发生异常则抛出该异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Int>()
}

View File

@ -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<E> : BaseJsonConverter<E, Long> {
/**
* 获取目标类型的引用用于标识此转换器的目标类型为 [Long]
*
* @return 返回 [JsonTypeReference] 的实例表示目标类型为 [Long]
* @throws Exception 如果在获取类型引用时发生异常则抛出此异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Long>()
}

View File

@ -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<E> : BaseJsonConverter<E, Short> {
/**
* 获取目标类型的引用信息
*
* 该方法重写了父接口中的 [getToType] 方法返回 [Short] 类型的 [JsonTypeReference] 实例
* 通过 [JsonTypeReference.Companion.of] 方法创建类型引用
*
* @return [JsonTypeReference] 表示 [Short] 类型的引用
* @throws Exception 如果在获取类型引用过程中发生异常则抛出该异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<Short>()
}

View File

@ -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<E> : BaseJsonConverter<E, String> {
/**
* 获取目标类型的引用信息
*
* 该方法重写了父接口中的 [getToType] 方法返回一个表示 [String] 类型的 [JsonTypeReference] 实例
* 此方法可能抛出异常因此使用 [@Throws(Exception::class)] 注解标记
*
* @return 返回一个 [JsonTypeReference] 实例表示目标类型为 [String]
* @throws Exception 如果在获取类型引用时发生错误则抛出此异常
*/
@Throws(Exception::class)
override fun getToType() = JsonTypeReference.of<String>()
}

View File

@ -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<F, T>(
val property: BeanProperty? = null,
val jsonConverter: JsonConverter<F, T>
) : JsonDeserializer<F>(), 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 <T : Annotation> get(clazz: Class<T>): T? = property?.getAnnotation(clazz)
})
}
/**
* 上下文感知方法设置当前属性信息
*
* @param ctxt 反序列化上下文可选参数
* @param property 当前属性信息
* @return 返回当前反序列化器实例
*/
override fun createContextual(
ctxt: DeserializationContext?,
property: BeanProperty?
): JackJsonDeserializer<F, T> {
return JackJsonDeserializer(property, jsonConverter)
}
}

View File

@ -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<F, T>(
val property: BeanProperty?,
val jsonConverter: JsonConverter<F, T>
) : JsonSerializer<F>(), 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 <T : Annotation> get(clazz: Class<T>): 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<F> {
return JackJsonSerializer(property, jsonConverter)
}
}

View File

@ -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<F, T> : JsonConverter<F, T> {
companion object {
/**
* 扩展ObjectMapper用于注册指定类型的模块
*
* 此函数通过反射创建指定类型的实例并调用其getJacksonModule方法来获取Jackson模块
* 然后将该模块注册到当前ObjectMapper实例中
*
* @param T 必须继承自BaseJsonConverter的泛型类型
* @return 返回注册了模块后的ObjectMapper实例
*/
inline fun <reified T : BaseJsonConverter<*, *>> ObjectMapper.addJsonConverter(): ObjectMapper =
this.registerModule(getJsonConverter<T>().getJacksonModule())
@JvmStatic
fun <T : BaseJsonConverter<*, *>> ObjectMapper.addJsonConverter(clazz: Class<T>): 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))
}

View File

@ -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<F, T> {
/**
* 将源对象转换为目标对象
*
* @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<F>
/**
* 获取目标类型的类型引用
*
* @return 目标类型的 JsonTypeReference 对象
* @throws Exception 获取过程中可能抛出的异常
*/
@Throws(Exception::class)
fun getToType(): JsonTypeReference<T>
/**
* 获取源类型的原始类
*
* @return 源类型的 Class 对象
* @throws Exception 获取过程中可能抛出的异常
*/
@Throws(Exception::class)
fun getFromClass() = getFromType().getRawType()
/**
* 获取目标类型的原始类
*
* @return 目标类型的 Class 对象
* @throws Exception 获取过程中可能抛出的异常
*/
@Throws(Exception::class)
fun getToClass() = getToType().getRawType()
}

View File

@ -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 类型对象可以是ClassParameterizedType或其他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 <reified T : JsonConverter<*, *>> getJsonConverter(): T = getJsonConverter(T::class.java)
fun <T : JsonConverter<*, *>> getJsonConverter(clazz: Class<T>): T {
try {
return clazz.getDeclaredMethod(
"getJsonConverter"
).invoke(null) as T
} catch (e: Exception) {
log.error("实现于 JsonConverter<*, *> 的类 必须实现静态方法 JsonConverter<*, *> getJsonConverter()", e)
throw e
}
}

View File

@ -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() }

View File

@ -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 <reified T> 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)
}

View File

@ -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
}

View File

@ -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)

Some files were not shown because too many files have changed in this diff Show More