generated from mingliqiye/lib-tem
master #15
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils
|
||||
* CurrentFile build.gradle.kts
|
||||
* LastUpdate 2026-01-14 13:01:44
|
||||
* LastUpdate 2026-02-05 11:04:04
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -59,6 +59,10 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||
@ -67,19 +71,24 @@ java {
|
||||
dependencies {
|
||||
|
||||
implementation("org.slf4j:slf4j-api:2.0.17")
|
||||
|
||||
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
|
||||
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("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.fasterxml.jackson.core:jackson-databind:2.21.0")
|
||||
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.21.0")
|
||||
}
|
||||
|
||||
|
||||
@ -126,6 +135,8 @@ tasks.withType<org.gradle.jvm.tasks.Jar> {
|
||||
}
|
||||
val isJdk8Build = project.findProperty("buildForJdk8") == "true"
|
||||
|
||||
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven.aliyun.com/repository/public/")
|
||||
|
||||
@ -16,13 +16,13 @@
|
||||
# ProjectName mingli-utils
|
||||
# ModuleName mingli-utils
|
||||
# CurrentFile gradle.properties
|
||||
# LastUpdate 2026-01-14 13:01:41
|
||||
# LastUpdate 2026-02-05 11:06:50
|
||||
# UpdateUser MingLiPro
|
||||
#
|
||||
JDKVERSIONS=1.8
|
||||
GROUPSID=com.mingliqiye.utils
|
||||
ARTIFACTID=mingli-utils
|
||||
VERSIONS=4.3.5
|
||||
VERSIONS=4.6.0
|
||||
signing.keyId=B22AA93B
|
||||
signing.password=
|
||||
signing.secretKeyRingFile=secret.gpg
|
||||
|
||||
@ -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")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
388
src/main/kotlin/com/mingliqiye/utils/array/ArrayUtils.kt
Normal file
388
src/main/kotlin/com/mingliqiye/utils/array/ArrayUtils.kt
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* 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-01-28 08:03:28
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("ArrayUtils")
|
||||
|
||||
package com.mingliqiye.utils.array
|
||||
|
||||
/**
|
||||
* 复制数组元素到目标数组
|
||||
* @param from 源数组
|
||||
* @param to 目标数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun <T> arrayCopy(from: Array<T>, to: Array<T>, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前数组元素复制到目标数组
|
||||
* @param to 目标数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun <T> Array<T>.copyTo(to: Array<T>, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个数组到目标数组(重载版本)
|
||||
* @param from 源数组
|
||||
* @param to 目标数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun <T> arrayCopy(from: Array<T>, to: Array<T>) {
|
||||
return arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制字节数组元素到目标数组
|
||||
* @param from 源字节数组
|
||||
* @param to 目标字节数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: ByteArray, to: ByteArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前字节数组元素复制到目标数组
|
||||
* @param to 目标字节数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun ByteArray.copyTo(to: ByteArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个字节数组到目标数组(重载版本)
|
||||
* @param from 源字节数组
|
||||
* @param to 目标字节数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: ByteArray, to: ByteArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制短整型数组元素到目标数组
|
||||
* @param from 源短整型数组
|
||||
* @param to 目标短整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: ShortArray, to: ShortArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前短整型数组元素复制到目标数组
|
||||
* @param to 目标短整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun ShortArray.copyTo(to: ShortArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个短整型数组到目标数组(重载版本)
|
||||
* @param from 源短整型数组
|
||||
* @param to 目标短整型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: ShortArray, to: ShortArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整型数组元素到目标数组
|
||||
* @param from 源整型数组
|
||||
* @param to 目标整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: IntArray, to: IntArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前整型数组元素复制到目标数组
|
||||
* @param to 目标整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun IntArray.copyTo(to: IntArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个整型数组到目标数组(重载版本)
|
||||
* @param from 源整型数组
|
||||
* @param to 目标整型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: IntArray, to: IntArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制长整型数组元素到目标数组
|
||||
* @param from 源长整型数组
|
||||
* @param to 目标长整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: LongArray, to: LongArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前长整型数组元素复制到目标数组
|
||||
* @param to 目标长整型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun LongArray.copyTo(to: LongArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个长整型数组到目标数组(重载版本)
|
||||
* @param from 源长整型数组
|
||||
* @param to 目标长整型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: LongArray, to: LongArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制浮点型数组元素到目标数组
|
||||
* @param from 源浮点型数组
|
||||
* @param to 目标浮点型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: FloatArray, to: FloatArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前浮点型数组元素复制到目标数组
|
||||
* @param to 目标浮点型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun FloatArray.copyTo(to: FloatArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个浮点型数组到目标数组(重载版本)
|
||||
* @param from 源浮点型数组
|
||||
* @param to 目标浮点型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: FloatArray, to: FloatArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制双精度浮点型数组元素到目标数组
|
||||
* @param from 源双精度浮点型数组
|
||||
* @param to 目标双精度浮点型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: DoubleArray, to: DoubleArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前双精度浮点型数组元素复制到目标数组
|
||||
* @param to 目标双精度浮点型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun DoubleArray.copyTo(to: DoubleArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个双精度浮点型数组到目标数组(重载版本)
|
||||
* @param from 源双精度浮点型数组
|
||||
* @param to 目标双精度浮点型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: DoubleArray, to: DoubleArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制布尔型数组元素到目标数组
|
||||
* @param from 源布尔型数组
|
||||
* @param to 目标布尔型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(
|
||||
from: BooleanArray, to: BooleanArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos
|
||||
) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前布尔型数组元素复制到目标数组
|
||||
* @param to 目标布尔型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun BooleanArray.copyTo(to: BooleanArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个布尔型数组到目标数组(重载版本)
|
||||
* @param from 源布尔型数组
|
||||
* @param to 目标布尔型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: BooleanArray, to: BooleanArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制字符型数组元素到目标数组
|
||||
* @param from 源字符型数组
|
||||
* @param to 目标字符型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: CharArray, to: CharArray, fromPos: Int = 0, toPos: Int = 0, length: Int = from.size - fromPos) {
|
||||
System.arraycopy(from, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:将当前字符型数组元素复制到目标数组
|
||||
* @param to 目标字符型数组
|
||||
* @param fromPos 源数组起始位置,默认为0
|
||||
* @param toPos 目标数组起始位置,默认为0
|
||||
* @param length 要复制的元素数量,默认为源数组从起始位置到末尾的长度
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
* @throws ArrayStoreException 当类型不匹配时抛出
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Throws(IndexOutOfBoundsException::class, ArrayStoreException::class)
|
||||
fun CharArray.copyTo(to: CharArray, fromPos: Int = 0, toPos: Int = 0, length: Int = this.size - fromPos) {
|
||||
System.arraycopy(this, fromPos, to, toPos, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制整个字符型数组到目标数组(重载版本)
|
||||
* @param from 源字符型数组
|
||||
* @param to 目标字符型数组
|
||||
* @throws IndexOutOfBoundsException 当索引超出数组边界时抛出
|
||||
*/
|
||||
@Throws(IndexOutOfBoundsException::class)
|
||||
fun arrayCopy(from: CharArray, to: CharArray) {
|
||||
arrayCopy(from, to, 0, 0, from.size)
|
||||
}
|
||||
@ -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),
|
||||
}
|
||||
@ -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-04 21:00:48
|
||||
* 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.json.api.base.JsonApi
|
||||
import com.mingliqiye.utils.json.api.exception.JsonException
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
/**
|
||||
* 获取文件大小
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
272
src/main/kotlin/com/mingliqiye/utils/functions/Pipeline.kt
Normal file
272
src/main/kotlin/com/mingliqiye/utils/functions/Pipeline.kt
Normal 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 09:53:44
|
||||
* 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表示当前值为null,false表示不为null
|
||||
*/
|
||||
fun isNull(): Boolean = (value == null)
|
||||
|
||||
/**
|
||||
* 判断当前值是否不为null
|
||||
* @return true表示当前值不为null,false表示为null
|
||||
*/
|
||||
fun isNotNull(): Boolean = (value != null)
|
||||
|
||||
/**
|
||||
* 根据条件过滤当前值,如果条件满足则保持原值,否则设置为null
|
||||
* @param predicate 过滤条件函数,接收当前值并返回布尔值
|
||||
* @return 包含过滤后结果的Pipeline实例
|
||||
*/
|
||||
fun filter(predicate: P1RFunction<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.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())
|
||||
}
|
||||
}
|
||||
@ -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,243 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Response.kt
|
||||
* LastUpdate 2025-09-15 09:04:05
|
||||
* LastUpdate 2026-02-03 20:09:10
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.http
|
||||
|
||||
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
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun <T> ok(data: T): Response<T?> {
|
||||
return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), "操作成功", data, 200)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个成功的响应对象(仅包含消息)
|
||||
*
|
||||
* @param message 响应消息
|
||||
* @return Response<Any> 成功的响应对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun <T> ok(message: String): Response<T?> {
|
||||
return Response(DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7), message, null, 200)
|
||||
}
|
||||
fun ok(message: String) = Response(
|
||||
time = DateTime.now(),
|
||||
message = message,
|
||||
data = null,
|
||||
statusCode = 200
|
||||
)
|
||||
|
||||
/**
|
||||
* 创建一个成功的响应对象(仅包含数据)
|
||||
*
|
||||
* @param T 响应数据的类型
|
||||
* @param data 响应数据
|
||||
* @return Response<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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认构造函数,创建一个默认的成功响应对象
|
||||
*/
|
||||
constructor() : this(
|
||||
time = DateTime.now(), message = "操作成功", statusCode = 200, data = null
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* 获取响应时间
|
||||
*
|
||||
* @return DateTime 响应时间
|
||||
*/
|
||||
fun getTime(): DateTime = time
|
||||
|
||||
/**
|
||||
* 设置响应时间
|
||||
*
|
||||
* @param dateTime 响应时间
|
||||
* @return Response<T> 当前响应对象(用于链式调用)
|
||||
*/
|
||||
fun setTime(dateTime: DateTime): Response<T> {
|
||||
time = dateTime
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回响应对象的字符串表示
|
||||
*/
|
||||
override fun toString(): String =
|
||||
"Response(time=${getTime()}, message=${getMessage()}, data:[${data?.javaClass?.simpleName}]=${getData()}, statusCode=${getStatusCode()})"
|
||||
}
|
||||
|
||||
@ -0,0 +1,372 @@
|
||||
/*
|
||||
* 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 Exceptions.kt
|
||||
* LastUpdate 2026-02-05 11:12:36
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.http.exception
|
||||
|
||||
/**
|
||||
* 表示 HTTP 异常的基类,继承自 [RuntimeException]。
|
||||
*
|
||||
* @param statusCode HTTP 状态码
|
||||
* @param message 异常信息,默认为 null
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
sealed class HttpException(
|
||||
open val statusCode: Int,
|
||||
override val message: String? = null,
|
||||
override val cause: Throwable? = null
|
||||
) : RuntimeException(message, cause)
|
||||
|
||||
// 3xx - 重定向异常
|
||||
|
||||
/**
|
||||
* 表示 HTTP 300 Multiple Choices 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Multiple Choices"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class MultipleChoicesException(
|
||||
override val message: String? = "Multiple Choices",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(300, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 301 Moved Permanently 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Moved Permanently"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class MovedPermanentlyException(
|
||||
override val message: String? = "Moved Permanently",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(301, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 302 Found 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Found"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class FoundException(
|
||||
override val message: String? = "Found",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(302, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 303 See Other 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "See Other"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class SeeOtherException(
|
||||
override val message: String? = "See Other",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(303, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 304 Not Modified 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Not Modified"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class NotModifiedException(
|
||||
override val message: String? = "Not Modified",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(304, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 305 Use Proxy 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Use Proxy"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class UseProxyException(
|
||||
override val message: String? = "Use Proxy",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(305, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 307 Temporary Redirect 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Temporary Redirect"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class TemporaryRedirectException(
|
||||
override val message: String? = "Temporary Redirect",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(307, message, cause)
|
||||
|
||||
// 4xx - 客户端错误异常
|
||||
|
||||
/**
|
||||
* 表示 HTTP 400 Bad Request 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Bad Request"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class BadRequestException(
|
||||
override val message: String? = "Bad Request",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(400, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 401 Unauthorized 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Unauthorized"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class UnauthorizedException(
|
||||
override val message: String? = "Unauthorized",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(401, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 402 Payment Required 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Payment Required"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class PaymentRequiredException(
|
||||
override val message: String? = "Payment Required",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(402, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 403 Forbidden 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Forbidden"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class ForbiddenException(
|
||||
override val message: String? = "Forbidden",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(403, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 404 Not Found 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Not Found"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class NotFoundException(
|
||||
override val message: String? = "Not Found",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(404, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(405, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 406 Not Acceptable 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Not Acceptable"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class NotAcceptableException(
|
||||
override val message: String? = "Not Acceptable",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(406, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(407, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 408 Request Timeout 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Request Timeout"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class RequestTimeoutException(
|
||||
override val message: String? = "Request Timeout",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(408, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 409 Conflict 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Conflict"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class ConflictException(
|
||||
override val message: String? = "Conflict",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(409, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 410 Gone 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Gone"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class GoneException(
|
||||
override val message: String? = "Gone",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(410, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 411 Length Required 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Length Required"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class LengthRequiredException(
|
||||
override val message: String? = "Length Required",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(411, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 412 Precondition Failed 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Precondition Failed"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class PreconditionFailedException(
|
||||
override val message: String? = "Precondition Failed",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(412, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(413, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(414, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(415, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(416, message, cause)
|
||||
|
||||
// 5xx - 服务器错误异常
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(500, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 501 Not Implemented 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Not Implemented"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class NotImplementedException(
|
||||
override val message: String? = "Not Implemented",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(501, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 502 Bad Gateway 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Bad Gateway"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class BadGatewayException(
|
||||
override val message: String? = "Bad Gateway",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(502, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 503 Service Unavailable 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Service Unavailable"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class ServiceUnavailableException(
|
||||
override val message: String? = "Service Unavailable",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(503, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 HTTP 504 Gateway Timeout 异常。
|
||||
*
|
||||
* @param message 异常信息,默认为 "Gateway Timeout"
|
||||
* @param cause 异常原因,默认为 null
|
||||
*/
|
||||
class GatewayTimeoutException(
|
||||
override val message: String? = "Gateway Timeout",
|
||||
override val cause: Throwable? = null,
|
||||
) : HttpException(504, message, cause)
|
||||
|
||||
/**
|
||||
* 表示 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,
|
||||
) : HttpException(505, message, cause)
|
||||
@ -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,217 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile IO.kt
|
||||
* LastUpdate 2025-09-20 16:03:14
|
||||
* LastUpdate 2026-02-04 13:12:57
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.io
|
||||
|
||||
|
||||
fun Any?.println() {
|
||||
IO.println(this)
|
||||
}
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import com.mingliqiye.utils.string.join
|
||||
import org.slf4j.Logger
|
||||
import java.io.OutputStream
|
||||
import java.io.PrintStream
|
||||
|
||||
|
||||
class IO {
|
||||
companion object {
|
||||
/**
|
||||
* IO工具类,提供打印功能和系统输出流重定向到日志的功能
|
||||
*/
|
||||
object IO {
|
||||
|
||||
@JvmStatic
|
||||
fun print(vararg args: Any?) {
|
||||
printA(" ", *args)
|
||||
}
|
||||
@JvmStatic
|
||||
fun <T : List<*>> T.println(): T {
|
||||
println("{" + ",".join(this) + "}")
|
||||
return this
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun println(vararg args: Any?) {
|
||||
printlnA(" ", *args)
|
||||
}
|
||||
@JvmStatic
|
||||
fun <T> Array<T>.println(): Array<T> {
|
||||
println("{" + ",".join(this) + "}")
|
||||
return this
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun printlnA(sp: String, vararg args: Any?) {
|
||||
printA(" ", *args)
|
||||
@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()) {
|
||||
kotlin.io.println()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun printA(sp: String = "", vararg args: Any?) {
|
||||
if (args.isEmpty()) {
|
||||
kotlin.io.println()
|
||||
}
|
||||
val sb = StringBuilder()
|
||||
for (i in args.indices) {
|
||||
sb.append(args[i])
|
||||
if (i < args.size - 1) sb.append(sp)
|
||||
}
|
||||
kotlin.io.print(sb)
|
||||
val sb = StringBuilder()
|
||||
for (i in args.indices) {
|
||||
sb.append(args[i])
|
||||
if (i < args.size - 1) sb.append(sp)
|
||||
}
|
||||
kotlin.io.print(sb)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
/**
|
||||
* 重定向 System.out 到 INFO 级别日志
|
||||
*/
|
||||
fun redirectOutToInfo() {
|
||||
val outLogger = PrintStream(object : OutputStream() {
|
||||
private val buffer = StringBuilder()
|
||||
|
||||
override fun write(b: Int) {
|
||||
if (b == '\n'.code) {
|
||||
flushBuffer()
|
||||
} else {
|
||||
buffer.append(b.toChar())
|
||||
}
|
||||
}
|
||||
|
||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||
val str = String(b, off, len)
|
||||
if (str.contains("\n")) {
|
||||
val lines = str.split("\n")
|
||||
lines.forEachIndexed { index, line ->
|
||||
if (index == lines.size - 1 && !str.endsWith("\n")) {
|
||||
buffer.append(line)
|
||||
} else {
|
||||
buffer.append(line)
|
||||
flushBuffer()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.append(str)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flushBuffer() {
|
||||
val message = buffer.toString().trim()
|
||||
if (message.isNotBlank()) {
|
||||
outLog.info(message)
|
||||
}
|
||||
buffer.clear()
|
||||
}
|
||||
|
||||
override fun flush() {
|
||||
flushBuffer()
|
||||
super.flush()
|
||||
}
|
||||
}, true)
|
||||
|
||||
System.setOut(outLogger)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
/**
|
||||
* 重定向 System.err 到 ERROR 级别
|
||||
*/
|
||||
fun redirectErrToError() {
|
||||
val errLogger = PrintStream(object : OutputStream() {
|
||||
private val buffer = StringBuilder()
|
||||
|
||||
override fun write(b: Int) {
|
||||
if (b == '\n'.code) {
|
||||
flushBuffer()
|
||||
} else {
|
||||
buffer.append(b.toChar())
|
||||
}
|
||||
}
|
||||
|
||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||
val str = String(b, off, len)
|
||||
if (str.contains("\n")) {
|
||||
val lines = str.split("\n")
|
||||
lines.forEachIndexed { index, line ->
|
||||
if (index == lines.size - 1 && !str.endsWith("\n")) {
|
||||
buffer.append(line)
|
||||
} else {
|
||||
buffer.append(line)
|
||||
flushBuffer()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.append(str)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flushBuffer() {
|
||||
val message = buffer.toString().trim()
|
||||
if (message.isNotBlank()) {
|
||||
errLog.error(message)
|
||||
}
|
||||
buffer.clear()
|
||||
}
|
||||
|
||||
override fun flush() {
|
||||
flushBuffer()
|
||||
super.flush()
|
||||
}
|
||||
}, true)
|
||||
|
||||
System.setErr(errLogger)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
/**
|
||||
* 完全重定向(包括第三方库的输出)
|
||||
*/
|
||||
fun redirectAll() {
|
||||
redirectOutToInfo()
|
||||
redirectErrToError()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
/**
|
||||
* 恢复原始输出流
|
||||
*/
|
||||
fun restore() {
|
||||
System.setOut(originalOut)
|
||||
System.setErr(originalErr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
644
src/main/kotlin/com/mingliqiye/utils/json/api/JSONA.kt
Normal file
644
src/main/kotlin/com/mingliqiye/utils/json/api/JSONA.kt
Normal 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())
|
||||
}
|
||||
@ -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 10:31:14
|
||||
* 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.json.api.base.JsonApi
|
||||
import com.mingliqiye.utils.json.api.exception.JsonException
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,12 +63,12 @@ class JacksonJsonApi : JsonApi {
|
||||
* @param clazz 目标对象类型
|
||||
* @param <T> 泛型参数,表示目标对象类型
|
||||
* @return 解析后的对象
|
||||
* @throws JsonException 当解析失败时抛出异常
|
||||
* @throws com.mingliqiye.utils.json.api.exception.JsonException 当解析失败时抛出异常
|
||||
*/
|
||||
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 {
|
||||
return objectMapper.convertValue(source, destinationClass)
|
||||
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 {
|
||||
return objectMapper.convertValue(
|
||||
source,
|
||||
objectMapper.constructType(destinationType.type)
|
||||
)
|
||||
}
|
||||
|
||||
override fun addJsonConverter(c: JsonConverter<*, *>) {
|
||||
c.getStringConverter()?.let {
|
||||
objectMapper.registerModule(it.jacksonJsonStringConverterAdapter.jacksonModule)
|
||||
override fun <D> convert(source: Any, destinationType: JsonTypeReference<D>): D {
|
||||
try {
|
||||
return objectMapper.convertValue(
|
||||
source, objectMapper.constructType(destinationType.type)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw JsonException("Failed to update node value", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addJsonStringConverter(c: JsonStringConverter<*>) {
|
||||
addJsonConverter(c)
|
||||
override fun addJsonConverter(c: BaseJsonConverter<*, *>) {
|
||||
try {
|
||||
objectMapper.registerModule(c.getJacksonModule())
|
||||
} catch (e: Exception) {
|
||||
throw JsonException("Failed to update node value", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<*, *>)
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile JsonException.kt
|
||||
* LastUpdate 2026-02-05 11:12:36
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.json.api.exception
|
||||
|
||||
/**
|
||||
* 自定义异常类,用于处理 JSON 相关操作中出现的错误。
|
||||
*
|
||||
* 该类继承自 [RuntimeException],提供了三种构造函数以支持不同的异常场景:
|
||||
* 1. 仅包含错误信息的构造函数。
|
||||
* 2. 包含错误信息和原因(Throwable)的构造函数。
|
||||
* 3. 仅包含原因(Throwable)的构造函数。
|
||||
*/
|
||||
class JsonException : RuntimeException {
|
||||
|
||||
/**
|
||||
* 构造函数:创建一个带有指定错误信息的 [JsonException] 实例。
|
||||
*
|
||||
* @param message 错误信息描述。
|
||||
*/
|
||||
constructor(message: String) : super(message)
|
||||
|
||||
/**
|
||||
* 构造函数:创建一个带有指定错误信息和原因的 [JsonException] 实例。
|
||||
*
|
||||
* @param message 错误信息描述。
|
||||
* @param cause 导致此异常的根本原因。
|
||||
*/
|
||||
constructor(message: String, cause: Throwable) : super(message, cause)
|
||||
|
||||
/**
|
||||
* 构造函数:创建一个由指定原因引发的 [JsonException] 实例。
|
||||
*
|
||||
* @param cause 导致此异常的根本原因。
|
||||
*/
|
||||
constructor(cause: Throwable) : super(cause)
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
@ -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
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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-05 11:18:57
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.json.converters
|
||||
|
||||
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.DateTimeJsonFormat
|
||||
import com.mingliqiye.utils.time.Formatter
|
||||
|
||||
|
||||
/**
|
||||
* DateTimeJsonConverter 是一个用于处理 DateTime 类型与 JSON 字符串之间转换的类。
|
||||
* 它继承自 BaseJsonStringConverter,提供了序列化(convert)和反序列化(deConvert)的功能。
|
||||
*/
|
||||
class DateTimeJsonConverter : BaseJsonStringConverter<DateTime> {
|
||||
|
||||
/**
|
||||
* 将 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>()
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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-05 11:19:45
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.json.converters
|
||||
|
||||
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
|
||||
import com.mingliqiye.utils.uuid.UUIDJsonFormat
|
||||
|
||||
/**
|
||||
* UUIDJsonConverter 是一个用于处理 UUID 类型与 JSON 字符串之间转换的类。
|
||||
* 它继承自 BaseJsonStringConverter,并实现了 convert 和 deConvert 方法,
|
||||
* 分别用于将 UUID 对象序列化为字符串以及反序列化字符串为 UUID 对象。
|
||||
*/
|
||||
class UUIDJsonConverter : BaseJsonStringConverter<UUID> {
|
||||
|
||||
/**
|
||||
* 将 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>()
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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-05 11:12:36
|
||||
* 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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-05 11:16:12
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.json.converters.base
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.core.JsonToken
|
||||
import com.fasterxml.jackson.databind.*
|
||||
import com.fasterxml.jackson.databind.deser.ContextualDeserializer
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer
|
||||
import com.mingliqiye.utils.json.api.type.JsonTypeReference
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* BaseJsonConverter 是一个通用的 JSON 转换器接口,用于定义对象之间的双向转换逻辑。
|
||||
*
|
||||
* @param F 源类型,表示需要被转换的对象类型。
|
||||
* @param T 目标类型,表示转换后的对象类型。
|
||||
*/
|
||||
interface BaseJsonConverter<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()
|
||||
|
||||
/**
|
||||
* 创建并返回一个 Jackson 模块,该模块包含自定义的序列化器和反序列化器。
|
||||
*
|
||||
* @return 配置了自定义序列化器和反序列化器的 SimpleModule 对象。
|
||||
*/
|
||||
fun getJacksonModule(): SimpleModule {
|
||||
// 创建一个 Jackson 模块,名称由源类型和目标类型组成
|
||||
val module = SimpleModule("${getFromClass().name}To${getToClass().name}")
|
||||
|
||||
// 定义自定义序列化器
|
||||
val serializer = object : JsonSerializer<F>(), ContextualSerializer {
|
||||
var property: BeanProperty? = null
|
||||
|
||||
/**
|
||||
* 序列化方法:将源对象转换为目标对象,并根据目标对象的类型写入 JSON。
|
||||
*
|
||||
* @param value 源对象,可能为 null。
|
||||
* @param gen JSON 生成器,用于写入 JSON 数据。
|
||||
* @param provider 序列化提供者,可选参数。
|
||||
*/
|
||||
override fun serialize(
|
||||
value: F?,
|
||||
gen: JsonGenerator,
|
||||
provider: SerializerProvider?
|
||||
) {
|
||||
// 执行转换逻辑
|
||||
val data: T? = 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> {
|
||||
this.property = property
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
// 定义自定义反序列化器
|
||||
val deserializer = object : JsonDeserializer<F>(), ContextualDeserializer {
|
||||
/**
|
||||
* 反序列化方法:从 JSON 解析数据并转换回源对象。
|
||||
*
|
||||
* @param p JSON 解析器。
|
||||
* @param ctxt 反序列化上下文,可选参数。
|
||||
* @return 转换后的源对象,可能为 null。
|
||||
*/
|
||||
override fun deserialize(
|
||||
p: JsonParser,
|
||||
ctxt: DeserializationContext?
|
||||
): F? {
|
||||
// 处理 null 值情况
|
||||
if (p.currentToken == JsonToken.VALUE_NULL) return null
|
||||
|
||||
// 执行反向转换逻辑
|
||||
return deConvert(p.readValueAs(getToClass()), object : AnnotationGetter {
|
||||
override fun <T : Annotation> get(clazz: Class<T>): T? = property?.getAnnotation(clazz)
|
||||
})
|
||||
}
|
||||
|
||||
var property: BeanProperty? = null
|
||||
|
||||
/**
|
||||
* 上下文感知方法:设置当前属性信息。
|
||||
*
|
||||
* @param ctxt 反序列化上下文,可选参数。
|
||||
* @param property 当前属性信息。
|
||||
* @return 返回当前反序列化器实例。
|
||||
*/
|
||||
override fun createContextual(
|
||||
ctxt: DeserializationContext?,
|
||||
property: BeanProperty?
|
||||
): JsonDeserializer<F> {
|
||||
this.property = property
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
// 将自定义序列化器和反序列化器注册到模块中
|
||||
return module
|
||||
.addSerializer(getFromClass(), serializer)
|
||||
.addDeserializer(getFromClass(), deserializer)
|
||||
}
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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>()
|
||||
}
|
||||
@ -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 JsonConverter.kt
|
||||
* LastUpdate 2026-02-05 11:18:33
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("JsonConverter")
|
||||
|
||||
package com.mingliqiye.utils.json.converters.base
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* 获取给定类型的实际类对象。
|
||||
*
|
||||
* @param type 类型对象,可以是Class、ParameterizedType或其他Type的实现。
|
||||
* @return 返回与给定类型对应的Class对象;如果无法解析,则返回null。
|
||||
*/
|
||||
fun getClass(type: Type?): Class<*>? {
|
||||
// 尝试将type直接转换为Class类型,如果失败则检查是否为ParameterizedType
|
||||
val clazz: Class<*>? = type as? Class<*> ?: if (type is ParameterizedType) {
|
||||
// 如果是ParameterizedType,则递归获取其原始类型
|
||||
getClass(type.rawType)
|
||||
} else {
|
||||
// 其他情况返回null
|
||||
null
|
||||
}
|
||||
return clazz
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展ObjectMapper,用于注册指定类型的模块。
|
||||
*
|
||||
* 此函数通过反射创建指定类型的实例,并调用其getJacksonModule方法来获取Jackson模块,
|
||||
* 然后将该模块注册到当前ObjectMapper实例中。
|
||||
*
|
||||
* @param T 必须继承自BaseJsonConverter的泛型类型。
|
||||
* @return 返回注册了模块后的ObjectMapper实例。
|
||||
*/
|
||||
inline fun <reified T : BaseJsonConverter<*, *>> ObjectMapper.registerModule(): ObjectMapper =
|
||||
this.registerModule(T::class.java.newInstance().getJacksonModule())
|
||||
@ -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 Loggers.kt
|
||||
* LastUpdate 2025-09-18 09:30:48
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -26,9 +26,7 @@ package com.mingliqiye.utils.logger
|
||||
|
||||
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.slf4j.Marker
|
||||
import java.util.*
|
||||
|
||||
enum class MingLiLoggerLevel {
|
||||
TRACE,
|
||||
@ -38,9 +36,9 @@ enum class MingLiLoggerLevel {
|
||||
ERROR
|
||||
}
|
||||
|
||||
class MingLiLogger : Logger {
|
||||
class MingLiLogger(private val name: String) : Logger {
|
||||
override fun getName(): String {
|
||||
return "MingLiLogger"
|
||||
return name
|
||||
}
|
||||
|
||||
override fun isTraceEnabled(): Boolean {
|
||||
@ -345,14 +343,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 +376,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() }
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
374
src/main/kotlin/com/mingliqiye/utils/math/MathUtils.kt
Normal file
374
src/main/kotlin/com/mingliqiye/utils/math/MathUtils.kt
Normal 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)
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile QuickBaseTypeHandler.kt
|
||||
* LastUpdate 2026-01-08 07:59:47
|
||||
* LastUpdate 2026-01-28 10:01:35
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -53,7 +53,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
ct: CallType,
|
||||
ci: Int?,
|
||||
cn: String?
|
||||
): T
|
||||
): T?
|
||||
|
||||
/**
|
||||
* 抽象方法,用于将 Java 类型 T 设置到 PreparedStatement 中。
|
||||
@ -65,7 +65,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
abstract fun setValue(ps: PreparedStatement, index: Int, parameter: T, jdbcType: JdbcType?)
|
||||
abstract fun setValue(ps: PreparedStatement, index: Int, parameter: T?, jdbcType: JdbcType?)
|
||||
|
||||
/**
|
||||
* 实现 BaseTypeHandler 的 setNonNullParameter 方法,
|
||||
@ -78,7 +78,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T, jdbcType: JdbcType?) {
|
||||
override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T?, jdbcType: JdbcType?) {
|
||||
setValue(ps, i, parameter, jdbcType)
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnName: String): T {
|
||||
override fun getNullableResult(rs: ResultSet, columnName: String): T? {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_NAME, null, columnName)
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): T {
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): T? {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_INDEX, columnIndex, null)
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T {
|
||||
override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T? {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(cs, null), CallType.CALLABLE_STATEMENT_INDEX, columnIndex, null)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile DateTimeTypeHandler.kt
|
||||
* LastUpdate 2026-01-07 19:23:12
|
||||
* LastUpdate 2026-02-05 11:20:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -30,6 +30,7 @@ import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.Timestamp
|
||||
import java.sql.Types.TIMESTAMP
|
||||
|
||||
/**
|
||||
* DateTime类型处理器,用于在数据库和Java对象之间转换DateTime类型
|
||||
@ -42,22 +43,30 @@ class DateTimeTypeHandler : QuickBaseTypeHandler<DateTime>() {
|
||||
ct: CallType,
|
||||
ci: Int?,
|
||||
cn: String?
|
||||
): DateTime {
|
||||
): DateTime? {
|
||||
val data = (when (ct) {
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getTimestamp(ci!!)
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getTimestamp(cn!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.callableStatement!!.getTimestamp(ci!!)
|
||||
})
|
||||
if (data == null) {
|
||||
return null
|
||||
}
|
||||
return DateTime.of(
|
||||
(when (ct) {
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getTimestamp(ci!!)
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getTimestamp(cn!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.callableStatement!!.getTimestamp(ci!!)
|
||||
})
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
override fun setValue(
|
||||
ps: PreparedStatement,
|
||||
index: Int,
|
||||
parameter: DateTime,
|
||||
parameter: DateTime?,
|
||||
jdbcType: JdbcType?
|
||||
) {
|
||||
if (parameter == null) {
|
||||
ps.setNull(index, TIMESTAMP)
|
||||
return
|
||||
}
|
||||
ps.setTimestamp(index, Timestamp.valueOf(parameter.toLocalDateTime()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile MysqlUUIDBinaryTypeHandler.kt
|
||||
* LastUpdate 2026-01-07 19:30:31
|
||||
* LastUpdate 2026-01-28 10:08:46
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -59,19 +59,29 @@ class MysqlUUIDBinaryTypeHandler : QuickBaseTypeHandler<UUID>() {
|
||||
|
||||
override fun getValue(
|
||||
vg: QuickBaseTypeHandlerValueGetter, ct: CallType, ci: Int?, cn: String?
|
||||
): UUID {
|
||||
): UUID? {
|
||||
|
||||
val data: ByteArray? = when (ct) {
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getBytes(cn!!)
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
}
|
||||
if (data == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return toUUID(
|
||||
when (ct) {
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getBytes(cn!!)
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
}
|
||||
)!!
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
override fun setValue(
|
||||
ps: PreparedStatement, index: Int, parameter: UUID, jdbcType: JdbcType?
|
||||
ps: PreparedStatement, index: Int, parameter: UUID?, jdbcType: JdbcType?
|
||||
) {
|
||||
if (parameter == null) {
|
||||
ps.setNull(index, java.sql.Types.BINARY)
|
||||
return
|
||||
}
|
||||
ps.setBytes(index, toByteArray(parameter))
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile PgsqlUUIDTypeHandler.kt
|
||||
* LastUpdate 2026-02-05 11:20:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis.typehandler.pgsql.uuid
|
||||
|
||||
import com.mingliqiye.utils.mybatis.CallType
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandler
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandlerValueGetter
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.PreparedStatement
|
||||
|
||||
@MappedTypes(UUID::class)
|
||||
class PgsqlUUIDTypeHandler : QuickBaseTypeHandler<UUID>() {
|
||||
override fun getValue(
|
||||
vg: QuickBaseTypeHandlerValueGetter, ct: CallType, ci: Int?, cn: String?
|
||||
): UUID? {
|
||||
val data: String? = when (ct) {
|
||||
CallType.RESULTSET_INDEX ->
|
||||
vg.resultSet!!.getString(ci!!)
|
||||
|
||||
CallType.RESULTSET_NAME ->
|
||||
vg.resultSet!!.getString(cn)
|
||||
|
||||
CallType.CALLABLE_STATEMENT_INDEX ->
|
||||
vg.callableStatement!!.getString(cn)
|
||||
}
|
||||
if (data == null) {
|
||||
return null
|
||||
}
|
||||
return UUID.of(data)
|
||||
}
|
||||
|
||||
override fun setValue(
|
||||
ps: PreparedStatement, index: Int, parameter: UUID?, jdbcType: JdbcType?
|
||||
) {
|
||||
if (parameter == null) {
|
||||
ps.setNull(index, jdbcType?.TYPE_CODE ?: JdbcType.JAVA_OBJECT.TYPE_CODE)
|
||||
return
|
||||
}
|
||||
ps.setObject(index, parameter.getUuid())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile QueryWrapper.kt
|
||||
* LastUpdate 2026-02-03 12:03:27
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper
|
||||
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper
|
||||
|
||||
/**
|
||||
* BaseMapperQuery接口扩展了BaseMapper,提供了通用的查询包装器功能
|
||||
*
|
||||
* @param T 实体类类型
|
||||
*/
|
||||
interface BaseMapperQuery<T> : BaseMapper<T> {
|
||||
/**
|
||||
* 创建并返回一个新的QueryWrapper实例
|
||||
*
|
||||
* @return QueryWrapper<T> 返回类型化的查询包装器实例
|
||||
*/
|
||||
fun queryWrapper() = QueryWrapper<T>()
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的UpdateWrapper实例
|
||||
*
|
||||
* @return UpdateWrapper<T> 返回类型化的更新包装器实例
|
||||
*/
|
||||
fun updateWrapper() = UpdateWrapper<T>()
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaQueryWrapper实例
|
||||
*
|
||||
* @return LambdaQueryWrapper<T> 返回类型化的Lambda查询包装器实例
|
||||
*/
|
||||
fun lambdaQueryWrapper() = LambdaQueryWrapper<T>()
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaUpdateWrapper实例
|
||||
*
|
||||
* @return LambdaUpdateWrapper<T> 返回类型化的Lambda更新包装器实例
|
||||
*/
|
||||
fun lambdaUpdateWrapper() = LambdaUpdateWrapper<T>()
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的QueryWrapper实例
|
||||
*
|
||||
* @return QueryWrapper<T> 返回类型化的查询包装器实例
|
||||
*/
|
||||
inline fun <reified T> BaseMapper<T>.queryWrapper(): QueryWrapper<T> = QueryWrapper<T>()
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的UpdateWrapper实例
|
||||
*
|
||||
* @return UpdateWrapper<T> 返回类型化的更新包装器实例
|
||||
*/
|
||||
inline fun <reified T> BaseMapper<T>.updateWrapper(): UpdateWrapper<T> = UpdateWrapper<T>()
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaQueryWrapper实例
|
||||
*
|
||||
* @return LambdaQueryWrapper<T> 返回类型化的Lambda查询包装器实例
|
||||
*/
|
||||
inline fun <reified T> BaseMapper<T>.lambdaQueryWrapper(): LambdaQueryWrapper<T> =
|
||||
LambdaQueryWrapper<T>(T::class.java)
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaUpdateWrapper实例
|
||||
*
|
||||
* @return LambdaUpdateWrapper<T> 返回类型化的Lambda更新包装器实例
|
||||
*/
|
||||
inline fun <reified T> BaseMapper<T>.lambdaUpdateWrapper(): LambdaUpdateWrapper<T> =
|
||||
LambdaUpdateWrapper<T>(T::class.java)
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的KtUpdateWrapper实例
|
||||
*
|
||||
* @return KtUpdateWrapper<T> 返回类型化的Kotlin更新包装器实例
|
||||
*/
|
||||
inline fun <reified T : Any> BaseMapper<T>.ktUpdateWrapper(): KtUpdateWrapper<T> =
|
||||
KtUpdateWrapper(T::class.java)
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的KtQueryWrapper实例
|
||||
*
|
||||
* @return KtQueryWrapper<T> 返回类型化的Kotlin查询包装器实例
|
||||
*/
|
||||
inline fun <reified T : Any> BaseMapper<T>.ktQueryWrapper(): KtQueryWrapper<T> = KtQueryWrapper(T::class.java)
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的KtUpdateChainWrapper实例
|
||||
*
|
||||
* @return KtUpdateChainWrapper<T> 返回类型化的Kotlin更新链式包装器实例
|
||||
*/
|
||||
inline fun <reified T : Any> BaseMapper<T>.ktUpdateChainWrapper(): KtUpdateChainWrapper<T> =
|
||||
KtUpdateChainWrapper(T::class.java)
|
||||
}
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile QueryWrapper.kt
|
||||
* LastUpdate 2026-01-14 13:00:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
|
||||
/**
|
||||
* BaseMapperQuery接口扩展了BaseMapper,提供了通用的查询包装器功能
|
||||
*
|
||||
* @param T 实体类类型
|
||||
*/
|
||||
interface BaseMapperQuery<T> : BaseMapper<T> {
|
||||
/**
|
||||
* 创建并返回一个新的QueryWrapper实例
|
||||
*
|
||||
* @return QueryWrapper<T> 返回类型化的查询包装器实例
|
||||
*/
|
||||
fun queryWrapper(): QueryWrapper<T> {
|
||||
return QueryWrapper<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的UpdateWrapper实例
|
||||
*
|
||||
* @return UpdateWrapper<T> 返回类型化的更新包装器实例
|
||||
*/
|
||||
fun updateWrapper(): UpdateWrapper<T> {
|
||||
return UpdateWrapper<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaQueryWrapper实例
|
||||
*
|
||||
* @return LambdaQueryWrapper<T> 返回类型化的Lambda查询包装器实例
|
||||
*/
|
||||
fun lambdaQueryWrapper(): LambdaQueryWrapper<T> {
|
||||
return LambdaQueryWrapper<T>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并返回一个新的LambdaUpdateWrapper实例
|
||||
*
|
||||
* @return LambdaUpdateWrapper<T> 返回类型化的Lambda更新包装器实例
|
||||
*/
|
||||
fun lambdaUpdateWrapper(): LambdaUpdateWrapper<T> {
|
||||
return LambdaUpdateWrapper<T>()
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile ClientScheduleReconnect.kt
|
||||
* LastUpdate 2026-01-08 10:45:37
|
||||
* LastUpdate 2026-01-20 08:10:15
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -28,26 +28,128 @@ import io.netty.channel.ChannelFuture
|
||||
import io.netty.channel.ChannelFutureListener
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class ClientScheduleReconnect(
|
||||
protected val bootstrap: Bootstrap,
|
||||
protected var delay: Long = 10L,
|
||||
protected var timeUnit: TimeUnit = TimeUnit.SECONDS
|
||||
) {
|
||||
protected var isStop = false
|
||||
protected var channel: Channel? = null
|
||||
/**
|
||||
* 客户端调度重连抽象类,用于处理Netty客户端的自动重连机制
|
||||
* @param bootstrap Netty引导配置对象
|
||||
* @param delay 重连延迟时间,默认为10秒
|
||||
* @param timeUnit 延迟时间单位,默认为秒
|
||||
*/
|
||||
abstract class ClientScheduleReconnect {
|
||||
|
||||
private val bootstrap: Bootstrap
|
||||
private var delay: Long = 10L
|
||||
private var timeUnit: TimeUnit = TimeUnit.SECONDS
|
||||
|
||||
constructor() : this(Bootstrap())
|
||||
constructor(bootstrap: Bootstrap) : this(bootstrap, 10L)
|
||||
constructor(bootstrap: Bootstrap, delay: Long) : this(bootstrap, delay, TimeUnit.SECONDS)
|
||||
constructor(bootstrap: Bootstrap, delay: Long, timeUnit: TimeUnit) {
|
||||
this.bootstrap = bootstrap
|
||||
this.delay = delay
|
||||
this.timeUnit = timeUnit
|
||||
}
|
||||
|
||||
open fun start() {
|
||||
initBootstrap(bootstrap)
|
||||
connect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Netty引导配置对象
|
||||
* @return Bootstrap 引导配置对象
|
||||
*/
|
||||
open fun getBootstrap(): Bootstrap = bootstrap
|
||||
|
||||
/**
|
||||
* 获取当前连接的通道
|
||||
* @return Channel? 当前连接的通道,可能为空
|
||||
*/
|
||||
open fun getChannel(): Channel? = channel
|
||||
|
||||
/**
|
||||
* 获取时间单位
|
||||
* @return TimeUnit 时间单位
|
||||
*/
|
||||
open fun getTimeUnit(): TimeUnit = timeUnit
|
||||
|
||||
/**
|
||||
* 设置时间单位
|
||||
* @param timeUnit 新的时间单位
|
||||
*/
|
||||
open fun setTimeUnit(timeUnit: TimeUnit) {
|
||||
this.timeUnit = timeUnit
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取重连延迟时间
|
||||
* @return Long 延迟时间
|
||||
*/
|
||||
open fun getDelay(): Long = delay
|
||||
|
||||
/**
|
||||
* 设置重连延迟时间
|
||||
* @param delay 新的延迟时间
|
||||
*/
|
||||
open fun setDelay(delay: Long) {
|
||||
this.delay = delay
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已连接
|
||||
* @return Boolean 是否已连接
|
||||
*/
|
||||
open fun isConnected(): Boolean = channel?.isActive ?: false
|
||||
|
||||
private var isStop = false
|
||||
private var channel: Channel? = null
|
||||
|
||||
/**
|
||||
* 连接成功时的日志记录回调
|
||||
* @param channel 成功连接的通道
|
||||
*/
|
||||
abstract fun onConnectedLog(channel: Channel)
|
||||
|
||||
/**
|
||||
* 连接失败时的日志记录回调
|
||||
* @param cause 连接失败的原因,可能为空
|
||||
*/
|
||||
abstract fun onConnectFailedLog(cause: Throwable?)
|
||||
|
||||
/**
|
||||
* 停止连接时的日志记录回调
|
||||
*/
|
||||
abstract fun onStoppedLog()
|
||||
abstract fun onConnectClosed()
|
||||
|
||||
/**
|
||||
* 执行连接操作
|
||||
* @return ChannelFuture 连接结果的异步操作对象
|
||||
*/
|
||||
abstract fun doConnect(): ChannelFuture
|
||||
|
||||
/**
|
||||
* 初始化引导配置
|
||||
* @param bootstrap 要初始化的引导配置对象
|
||||
*/
|
||||
open fun initBootstrap(bootstrap: Bootstrap) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新重连延迟配置
|
||||
* @param newDelay 新的延迟时间,必须大于0
|
||||
* @param newTimeUnit 新的时间单位
|
||||
* @throws IllegalArgumentException 当newDelay小于等于0时抛出
|
||||
*/
|
||||
open fun updateReconnectDelay(newDelay: Long, newTimeUnit: TimeUnit) {
|
||||
require(newDelay > 0) { "Delay must be positive" }
|
||||
this.delay = newDelay
|
||||
this.timeUnit = newTimeUnit
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行连接操作,设置连接完成监听器
|
||||
*/
|
||||
open fun connect() {
|
||||
doConnect().addListener(object : ChannelFutureListener {
|
||||
override fun operationComplete(future: ChannelFuture) {
|
||||
@ -60,24 +162,33 @@ abstract class ClientScheduleReconnect(
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止连接并标记为停止状态
|
||||
*/
|
||||
open fun stop() {
|
||||
isStop = true
|
||||
disConnect()
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开当前连接并清理通道引用
|
||||
*/
|
||||
open fun disConnect() {
|
||||
channel?.close()
|
||||
channel = null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 调度下一次重连操作
|
||||
*/
|
||||
open fun scheduleReconnect() {
|
||||
// 检查是否已停止,如果已停止则记录日志并返回
|
||||
if (isStop) {
|
||||
onStoppedLog()
|
||||
return
|
||||
}
|
||||
bootstrap.config().group().schedule({
|
||||
// 再次检查停止状态,避免在调度期间被停止
|
||||
if (isStop) {
|
||||
onStoppedLog()
|
||||
return@schedule
|
||||
@ -86,20 +197,27 @@ abstract class ClientScheduleReconnect(
|
||||
}, delay, timeUnit)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理连接成功的逻辑
|
||||
* @param channel 成功连接的通道
|
||||
*/
|
||||
open fun onConnected(channel: Channel) {
|
||||
this.channel = channel
|
||||
onConnectedLog(channel)
|
||||
// 监听通道关闭事件,以便在断开后重新调度连接
|
||||
channel.closeFuture().addListener { _ ->
|
||||
scheduleReconnect()
|
||||
onConnectClosed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理连接失败的逻辑
|
||||
* @param cause 连接失败的原因
|
||||
*/
|
||||
open fun onConnectFailed(cause: Throwable?) {
|
||||
onConnectFailedLog(cause)
|
||||
scheduleReconnect()
|
||||
}
|
||||
|
||||
open fun isConnected(): Boolean {
|
||||
return channel?.isActive ?: false
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NamedNioEventLoopGroup.kt
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import com.mingliqiye.utils.system.availableProcessors
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import java.text.MessageFormat
|
||||
|
||||
/**
|
||||
* 命名的NIO事件循环组,继承自NioEventLoopGroup
|
||||
* 用于创建具有自定义命名规则的线程池,便于线程管理和调试
|
||||
*
|
||||
* @param name 线程池的名称,默认为"NioEventLoopGroup"
|
||||
* @param template 线程名称的格式模板,默认为"{0}-{2}-{3}",{0} 名字 {1} 类名 {2} 线程池序号 {3} 线程池内线程的序号
|
||||
* @param nThreads 线程数量,默认为核心数的2倍
|
||||
*/
|
||||
open class NamedNioEventLoopGroup(
|
||||
val template: String = "{0}-{2}-{3}",
|
||||
val name: String = "NioEventLoopGroup",
|
||||
nThreads: Int = availableProcessors * 2
|
||||
) :
|
||||
NioEventLoopGroup(
|
||||
nThreads,
|
||||
NamedThreadFactory(
|
||||
getName = { a, b, c -> MessageFormat.format(template, name, a, b, c) }
|
||||
)
|
||||
)
|
||||
@ -16,17 +16,19 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NamedThreadFactory.kt
|
||||
* LastUpdate 2026-01-08 13:21:00
|
||||
* LastUpdate 2026-01-31 21:05:02
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import io.netty.util.concurrent.FastThreadLocalThread
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
/**
|
||||
* 命名线程工厂类,用于创建具有自定义名称的线程
|
||||
* @param getName 用于获取线程名称的回调函数接口
|
||||
*/
|
||||
open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter) : ThreadFactory {
|
||||
|
||||
companion object {
|
||||
@ -34,15 +36,33 @@ open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter)
|
||||
@JvmStatic
|
||||
private val allThreadPoolNumber = AtomicInteger(0)
|
||||
|
||||
/**
|
||||
* 函数式接口,用于定义线程名称生成规则
|
||||
*/
|
||||
@FunctionalInterface
|
||||
fun interface NamedThreadFactoryNameGetter {
|
||||
/**
|
||||
* 获取线程名称
|
||||
* @param clazz 线程工厂类
|
||||
* @param poolNumber 线程池编号
|
||||
* @param threadNumber 线程编号
|
||||
* @return 生成的线程名称
|
||||
*/
|
||||
fun getName(clazz: Class<out NamedThreadFactory>, poolNumber: Int, threadNumber: Int): String
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的线程名称生成器
|
||||
*/
|
||||
@JvmStatic
|
||||
val defaultGetName =
|
||||
NamedThreadFactoryNameGetter { clazz, poolNumber, threadNumber -> "${clazz.simpleName}-$poolNumber-$threadNumber" }
|
||||
|
||||
/**
|
||||
* 创建命名线程工厂实例
|
||||
* @param name 线程名称前缀
|
||||
* @return NamedThreadFactory实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(name: String): NamedThreadFactory {
|
||||
return NamedThreadFactory { a, b, c ->
|
||||
@ -50,24 +70,42 @@ open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建命名线程工厂实例
|
||||
* @param getter 线程名称生成器,默认使用defaultGetName
|
||||
* @return NamedThreadFactory实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(getter: NamedThreadFactoryNameGetter = defaultGetName): NamedThreadFactory {
|
||||
return NamedThreadFactory(getter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 当前线程工厂的线程计数器
|
||||
private val threadNumber = AtomicInteger(0)
|
||||
|
||||
// 全局线程池计数器,用于标识不同的线程池
|
||||
private val threadPoolNumber = allThreadPoolNumber.addAndGet(1)
|
||||
|
||||
/**
|
||||
* 获取线程名称
|
||||
* @param clazz 线程工厂类
|
||||
* @param poolNumber 线程池编号
|
||||
* @param threadNumber 线程编号
|
||||
* @return 生成的线程名称
|
||||
*/
|
||||
open fun getThreadName(clazz: Class<out NamedThreadFactory>, poolNumber: Int, threadNumber: Int) =
|
||||
getName.getName(clazz, poolNumber, threadNumber)
|
||||
|
||||
/**
|
||||
* 创建新线程
|
||||
* @param r 线程执行的任务
|
||||
* @return 新创建的线程对象
|
||||
*/
|
||||
override fun newThread(r: Runnable): Thread {
|
||||
return FastThreadLocalThread(
|
||||
null,
|
||||
r,
|
||||
getThreadName(this.javaClass, threadPoolNumber, threadNumber.addAndGet(1))
|
||||
)
|
||||
return Thread(r).let {
|
||||
it.name = getThreadName(this.javaClass, threadPoolNumber, threadNumber.addAndGet(1))
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NettyUtils.kt
|
||||
* LastUpdate 2026-01-07 10:00:31
|
||||
* LastUpdate 2026-01-31 20:50:41
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -24,9 +24,15 @@
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import com.mingliqiye.utils.functions.P1Function
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelInitializer
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* 将ByteBuffer转换为Netty的ByteBuf对象
|
||||
@ -79,3 +85,206 @@ fun ByteBuf.toByteArray(): ByteArray {
|
||||
fun ByteArray.toByteBuf(): ByteBuf {
|
||||
return Unpooled.wrappedBuffer(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 为ServerBootstrap配置子通道初始化器
|
||||
*
|
||||
* 该函数用于设置ServerBootstrap的childHandler,当新的客户端连接建立时,
|
||||
* 会调用提供的函数来初始化子通道
|
||||
*
|
||||
* @receiver ServerBootstrap 需要配置的服务器引导程序实例
|
||||
* @param funa 用于初始化通道的回调函数,接收Channel作为参数
|
||||
* @return ServerBootstrap 返回当前实例以支持链式调用
|
||||
*/
|
||||
@JvmName("channelInit")
|
||||
fun ServerBootstrap.channelInitializer(funa: P1Function<Channel>): ServerBootstrap {
|
||||
this.childHandler(object : ChannelInitializer<Channel>() {
|
||||
override fun initChannel(ch: Channel) {
|
||||
funa.call(ch)
|
||||
}
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 为Bootstrap配置通道初始化器
|
||||
*
|
||||
* 该函数用于设置Bootstrap的handler,当客户端连接建立时,
|
||||
* 会调用提供的函数来初始化通道
|
||||
*
|
||||
* @receiver Bootstrap 需要配置的客户端引导程序实例
|
||||
* @param funa 用于初始化通道的回调函数,接收Channel作为参数
|
||||
* @return Bootstrap 返回当前实例以支持链式调用
|
||||
*/
|
||||
@JvmName("channelInit")
|
||||
fun Bootstrap.channelInitializer(funa: P1Function<Channel>): Bootstrap {
|
||||
this.handler(object : ChannelInitializer<Channel>() {
|
||||
override fun initChannel(ch: Channel) {
|
||||
funa.call(ch)
|
||||
}
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为Netty的ByteBuf对象
|
||||
*
|
||||
* @receiver String 需要转换的原始字符串
|
||||
* @param charset 字符编码,默认UTF-8
|
||||
* @return ByteBuf 转换后的Netty ByteBuf对象
|
||||
*/
|
||||
fun String.toByteBuf(charset: Charset = Charsets.UTF_8): ByteBuf {
|
||||
return Unpooled.wrappedBuffer(this.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* 将ByteBuf转换为字符串
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的ByteBuf对象
|
||||
* @param charset 字符编码,默认UTF-8
|
||||
* @return String 转换后的字符串
|
||||
*/
|
||||
fun ByteBuf.toString(charset: Charset = Charsets.UTF_8): String {
|
||||
val bytes = this.toByteArray()
|
||||
return String(bytes, charset)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将Int转换为ByteBuf
|
||||
*
|
||||
* @receiver Int 需要转换的整数值
|
||||
* @return ByteBuf 转换后的Netty ByteBuf对象,包含4字节的整数数据
|
||||
*/
|
||||
fun Int.toByteBuf(): ByteBuf {
|
||||
val buffer = Unpooled.buffer(4)
|
||||
buffer.writeInt(this)
|
||||
return buffer
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Long转换为ByteBuf
|
||||
*
|
||||
* @receiver Long 需要转换的长整数值
|
||||
* @return ByteBuf 转换后的Netty ByteBuf对象,包含8字节的长整数数据
|
||||
*/
|
||||
fun Long.toByteBuf(): ByteBuf {
|
||||
val buffer = Unpooled.buffer(8)
|
||||
buffer.writeLong(this)
|
||||
return buffer
|
||||
}
|
||||
|
||||
/**
|
||||
* 将ByteBuf转换为Int
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的ByteBuf对象
|
||||
* @return Int 从ByteBuf中读取的整数值
|
||||
*/
|
||||
fun ByteBuf.toInt(): Int {
|
||||
return this.readInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将ByteBuf转换为Long
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的ByteBuf对象
|
||||
* @return Long 从ByteBuf中读取的长整数值
|
||||
*/
|
||||
fun ByteBuf.toLong(): Long {
|
||||
return this.readLong()
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地获取ByteBuf的字节数组,避免堆外内存访问异常
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的ByteBuf对象
|
||||
* @return ByteArray 转换后的字节数组
|
||||
*/
|
||||
fun ByteBuf.safeToByteArray(): ByteArray {
|
||||
return if (this.hasArray()) {
|
||||
// 如果是堆内内存,直接获取数组
|
||||
this.array().copyOfRange(this.arrayOffset(), this.arrayOffset() + this.readableBytes())
|
||||
} else {
|
||||
// 如果是堆外内存,使用readBytes
|
||||
val array = ByteArray(this.readableBytes())
|
||||
this.getBytes(this.readerIndex(), array)
|
||||
array
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ByteBuf的十六进制字符串表示
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的ByteBuf对象
|
||||
* @return String 十六进制字符串表示
|
||||
*/
|
||||
fun ByteBuf.toHexString(): String {
|
||||
val array = this.safeToByteArray()
|
||||
return array.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并多个ByteBuf为一个
|
||||
*
|
||||
* @param byteBufs 需要合并的ByteBuf数组
|
||||
* @return ByteBuf 合并后的ByteBuf对象
|
||||
*/
|
||||
fun combineByteBuf(vararg byteBufs: ByteBuf): ByteBuf {
|
||||
val totalCapacity = byteBufs.sumOf { it.readableBytes() }
|
||||
val combined = Unpooled.buffer(totalCapacity)
|
||||
byteBufs.forEach { combined.writeBytes(it.duplicate()) }
|
||||
return combined
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全关闭通道
|
||||
*/
|
||||
fun Channel.closeSafely() {
|
||||
if (isOpen) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查通道是否处于活跃状态
|
||||
*/
|
||||
val Channel.isActive: Boolean
|
||||
get() = isOpen && isActive
|
||||
|
||||
/**
|
||||
* 异步写入数据到通道
|
||||
*
|
||||
* @param data 需要写入的数据
|
||||
*/
|
||||
fun Channel.writeAndFlushAsync(data: Any) {
|
||||
writeAndFlush(data).addListener { future ->
|
||||
if (!future.isSuccess) {
|
||||
// 可以在这里添加错误处理逻辑
|
||||
println("Write failed: ${future.cause()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全释放ByteBuf资源
|
||||
*
|
||||
* @receiver ByteBuf 需要释放的ByteBuf对象
|
||||
* @return Boolean 释放操作是否成功
|
||||
*/
|
||||
fun ByteBuf.releaseSafely(): Boolean {
|
||||
return if (refCnt() > 0) release() else true
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试释放ByteBuf资源,不抛出异常
|
||||
*
|
||||
* @receiver ByteBuf 需要释放的ByteBuf对象
|
||||
* @return Boolean 释放操作是否成功
|
||||
*/
|
||||
fun ByteBuf.tryRelease(): Boolean {
|
||||
return try {
|
||||
if (refCnt() > 0) release() else false
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,509 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile AddressPort.kt
|
||||
* LastUpdate 2026-01-06 14:03:47
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
import com.mingliqiye.utils.string.join
|
||||
import java.io.Serializable
|
||||
import java.net.InetAddress
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。
|
||||
* 支持IPv4和IPv6地址的解析与验证。
|
||||
*
|
||||
* @author MingLiPro
|
||||
*/
|
||||
class NetworkAddress private constructor(domip: String) : Serializable {
|
||||
|
||||
/**
|
||||
* IPv6标识
|
||||
*/
|
||||
companion object {
|
||||
const val IPV6 = 6
|
||||
|
||||
/**
|
||||
* IPv4标识
|
||||
*/
|
||||
const val IPV4 = 4
|
||||
|
||||
/**
|
||||
* IPv4地址正则表达式
|
||||
*/
|
||||
private const val IPV4REG =
|
||||
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"
|
||||
|
||||
/**
|
||||
* 编译后的IPv4地址匹配模式
|
||||
*/
|
||||
private val IPV4_PATTERN = Pattern.compile(IPV4REG)
|
||||
|
||||
/**
|
||||
* IPv6地址正则表达式
|
||||
*/
|
||||
private const val IPV6REG =
|
||||
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + "|" + "^(::)$|" + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$"
|
||||
|
||||
/**
|
||||
* 编译后的IPv6地址匹配模式
|
||||
*/
|
||||
private val IPV6_PATTERN = Pattern.compile(IPV6REG)
|
||||
|
||||
/**
|
||||
* 静态工厂方法,创建 NetworkAddress 实例。
|
||||
*
|
||||
* @param domip 可能是IP地址或域名的字符串
|
||||
* @return 新建的 NetworkAddress 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(domip: String): NetworkAddress {
|
||||
return NetworkAddress(domip)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkAddress {
|
||||
val byteArray = ByteArray(4)
|
||||
byteBuffer.get(byteArray)
|
||||
return ofIpv4(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkAddress {
|
||||
return of(".".join(byteArray.map {
|
||||
(it.toInt() and 0xFF).toString()
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。
|
||||
*
|
||||
* @param inetAddress InetAddress 对象
|
||||
* @return 新建的 NetworkAddress 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(inetAddress: InetAddress): NetworkAddress {
|
||||
return NetworkAddress(inetAddress.hostAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从DNS服务器解析域名获取对应的IP地址。
|
||||
*
|
||||
* @param domain 域名
|
||||
* @return 解析出的第一个IP地址
|
||||
* @throws UnknownHostException 如果域名无法解析
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(UnknownHostException::class)
|
||||
fun getHostIp(domain: String): String {
|
||||
val addresses = InetAddress.getAllByName(domain.trim())
|
||||
return addresses[0].hostAddress
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测给定字符串是否为有效的IPv4或IPv6地址。
|
||||
*
|
||||
* @param ip 要检测的IP地址字符串
|
||||
* @return 4 表示IPv4,6 表示IPv6
|
||||
* @throws NetworkException 如果IP格式无效
|
||||
*/
|
||||
@JvmStatic
|
||||
fun testIp(ip: String?): Int {
|
||||
if (ip == null) {
|
||||
throw NetworkException("IP地址不能为null")
|
||||
}
|
||||
val trimmedIp = ip.trim()
|
||||
|
||||
// 判断是否匹配IPv4格式
|
||||
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
|
||||
return IPV4
|
||||
}
|
||||
|
||||
// 判断是否匹配IPv6格式
|
||||
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
|
||||
return IPV6
|
||||
}
|
||||
|
||||
// 不符合任一格式时抛出异常
|
||||
throw NetworkException(
|
||||
"[$ip] 不是有效的IPv4或IPv6地址"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IP地址类型:4 表示 IPv4,6 表示 IPv6
|
||||
*/
|
||||
var iPv: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* IP地址字符串
|
||||
*/
|
||||
var ip: String? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* 域名(如果输入的是域名)
|
||||
*/
|
||||
private var domain: String? = null
|
||||
|
||||
/**
|
||||
* 标识是否是域名解析来的IP
|
||||
*/
|
||||
private var isdom = false
|
||||
|
||||
/**
|
||||
* 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。
|
||||
*
|
||||
* @param domip 可能是IP地址或域名的字符串
|
||||
*/
|
||||
init {
|
||||
try {
|
||||
// 尝试将输入识别为IP地址
|
||||
this.iPv = testIp(domip)
|
||||
this.ip = domip
|
||||
} catch (e: NetworkException) {
|
||||
try {
|
||||
// 如果不是有效IP,则尝试作为域名解析
|
||||
val ips = getHostIp(domip)
|
||||
this.iPv = testIp(ips)
|
||||
this.ip = ips
|
||||
this.isdom = true
|
||||
this.domain = domip
|
||||
} catch (ex: UnknownHostException) {
|
||||
throw NetworkException(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址转换为字节数组
|
||||
*
|
||||
* @return 返回表示IPv4地址的4字节数组
|
||||
* @throws NetworkException 当当前地址不是IPv4地址时抛出异常
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
// 验证地址类型是否为IPv4
|
||||
if (iPv != IPV4) {
|
||||
throw NetworkException("该地址 不是IPv4地址")
|
||||
}
|
||||
// 将IP地址字符串按点分割,转换为整数并进行位运算处理,最后转为字节数组
|
||||
return ip!!.split(".").map { it.toInt() and 0xFF }.map { it.toByte() }.toByteArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址写入到指定的ByteBuffer中
|
||||
*
|
||||
* @param byteBuffer 要写入的ByteBuffer对象,IPv4地址将以字节数组形式写入到该缓冲区
|
||||
* @return 返回写入了IPv4地址的ByteBuffer对象,便于链式调用
|
||||
*/
|
||||
fun writeIpv4ToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toIpv4ByteArray())
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前 NetworkAddress 转换为 InetAddress 对象。
|
||||
*
|
||||
* @return InetAddress 对象
|
||||
*/
|
||||
fun toInetAddress(): InetAddress {
|
||||
try {
|
||||
return InetAddress.getByName(if (ip != null) ip else domain)
|
||||
} catch (e: UnknownHostException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 NetworkAddress 的字符串表示形式。
|
||||
*
|
||||
* @return 字符串表示
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return if (isdom) "NetworkAddress(IP='$ip',type='$iPv',domain='$domain')"
|
||||
else "NetworkAddress(IP='$ip',type='$iPv')"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NetworkPort : Serializable {
|
||||
val port: Int
|
||||
|
||||
constructor(port: Int) {
|
||||
testPort(port)
|
||||
this.port = port
|
||||
}
|
||||
|
||||
fun toByteArray(): ByteArray {
|
||||
val byteArray = ByteArray(2)
|
||||
byteArray[0] = (port shr 8 and 0xFF).toByte()
|
||||
byteArray[1] = (port and 0xFF).toByte()
|
||||
return byteArray
|
||||
}
|
||||
|
||||
fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toByteArray())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 创建NetworkPort实例
|
||||
* @param port 端口号
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(port: Int): NetworkPort {
|
||||
return NetworkPort(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建NetworkPort实例
|
||||
* @param byteArray 包含端口信息的字节数组(长度至少为2)
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteArray: ByteArray): NetworkPort {
|
||||
// 将字节数组的前两个字节转换为端口号
|
||||
val port = ((byteArray[0].toInt() and 0xFF) shl 8) or (byteArray[1].toInt() and 0xFF)
|
||||
return of(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ByteBuffer创建NetworkPort实例
|
||||
* @param byteBuffer 包含端口信息的ByteBuffer
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteBuffer: ByteBuffer): NetworkPort {
|
||||
val byteArray = ByteArray(2)
|
||||
byteBuffer.get(byteArray)
|
||||
return of(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testPort(port: Int) {
|
||||
// 验证端口号范围是否在0-65535之间
|
||||
if (port !in 0..65535) {
|
||||
throw NetworkException("$port 不是正确的端口号")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkException : RuntimeException {
|
||||
/**
|
||||
* 构造一个带有指定详细消息的网络异常
|
||||
*
|
||||
* @param message 异常的详细消息
|
||||
*/
|
||||
constructor(message: String?) : super(message)
|
||||
|
||||
/**
|
||||
* 构造一个网络异常,指定原因异常
|
||||
*
|
||||
* @param e 导致此异常的原因异常
|
||||
*/
|
||||
constructor(e: Exception?) : super(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* IP和端口聚集类,用于封装网络地址与端口信息。
|
||||
* 该类提供了与InetSocketAddress之间的相互转换功能。
|
||||
*
|
||||
* @author MingLiPro
|
||||
* @see java.net.InetSocketAddress
|
||||
*/
|
||||
class NetworkEndpoint private constructor(
|
||||
val networkAddress: NetworkAddress, val networkPort: NetworkPort
|
||||
) : Serializable {
|
||||
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。
|
||||
*
|
||||
* @param address InetSocketAddress对象
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
* @see java.net.InetSocketAddress
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(address: InetSocketAddress): NetworkEndpoint {
|
||||
return NetworkEndpoint(
|
||||
NetworkAddress.of(address.hostString), NetworkPort(address.port)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。
|
||||
*
|
||||
* @param s 主机名或IP地址字符串
|
||||
* @param i 端口号
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(s: String, i: Int): NetworkEndpoint {
|
||||
val networkAddress = NetworkAddress.of(s)
|
||||
val networkPort = NetworkPort(i)
|
||||
return NetworkEndpoint(networkAddress, networkPort)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建IPv4网络端点
|
||||
*
|
||||
* @param byteArray 包含IPv4地址和端口信息的字节数组,前4个字节表示IP地址,后2个字节表示端口号
|
||||
* @return NetworkEndpoint对象,封装了IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkEndpoint {
|
||||
// 提取前4个字节作为IP地址
|
||||
val address = ByteArray(4) {
|
||||
byteArray[it]
|
||||
}
|
||||
// 提取后2个字节作为端口号
|
||||
val portInt = ByteArray(2) {
|
||||
byteArray[it + 4]
|
||||
}
|
||||
return NetworkEndpoint(NetworkAddress.ofIpv4(address), NetworkPort.of(portInt))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节缓冲区创建IPv4网络端点实例
|
||||
*
|
||||
* 该方法从给定的ByteBuffer中读取数据,构建一个包含IPv4地址和端口的网络端点对象。
|
||||
* 该方法按照协议顺序从缓冲区中读取IPv4地址数据和端口数据。
|
||||
*
|
||||
* @param byteBuffer 包含IPv4地址和端口数据的字节缓冲区,缓冲区中的数据应按照先地址后端口的顺序排列
|
||||
* @return 返回一个NetworkEndpoint实例,包含从缓冲区解析出的IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkEndpoint {
|
||||
return NetworkEndpoint(
|
||||
NetworkAddress.ofIpv4(byteBuffer),
|
||||
NetworkPort.of(byteBuffer)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据"host:port"格式的字符串创建NetworkEndpoint实例。
|
||||
* 例如:"127.0.0.1:8080"
|
||||
*
|
||||
* @param s "host:port"格式的字符串
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(s: String): NetworkEndpoint {
|
||||
val lastColonIndex = s.lastIndexOf(':')
|
||||
return of(
|
||||
s.take(lastColonIndex), s.substring(lastColonIndex + 1).toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前NetworkEndpoint转换为InetSocketAddress对象。
|
||||
*
|
||||
* @return 对应的InetSocketAddress对象
|
||||
* @see InetSocketAddress
|
||||
*/
|
||||
fun toInetSocketAddress(): InetSocketAddress {
|
||||
return InetSocketAddress(
|
||||
networkAddress.toInetAddress(), networkPort.port
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前NetworkEndpoint转换为"host:port"格式的字符串。
|
||||
* 例如:"127.0.0.1:25563"
|
||||
*
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
fun toHostPortString(): String {
|
||||
return "${networkAddress.ip}:${networkPort.port}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回NetworkEndpoint的详细字符串表示形式。
|
||||
* 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...)
|
||||
*
|
||||
* @return 包含详细信息的字符串
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port})"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机名或IP地址字符串。
|
||||
*
|
||||
* @return 主机名或IP地址
|
||||
*/
|
||||
fun host(): String {
|
||||
return networkAddress.ip ?: ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取端口号。
|
||||
*
|
||||
* @return 端口号
|
||||
*/
|
||||
fun port(): Int {
|
||||
return networkPort.port
|
||||
}
|
||||
|
||||
/**
|
||||
* 将网络地址和端口转换为IPv4字节数组
|
||||
*
|
||||
* 该函数将当前对象的网络地址转换为IPv4字节数组,并与端口字节数组合并,
|
||||
* 生成一个包含6个字节的数组,其中前4个字节为IPv4地址,后2个字节为端口号
|
||||
*
|
||||
* @return ByteArray 包含6个字节的数组,前4个字节为IPv4地址,后2个字节为端口号
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
val ipv4ByteArray = networkAddress.toIpv4ByteArray()
|
||||
val portByteArray = networkPort.toByteArray()
|
||||
// 构建包含IPv4地址和端口的6字节数组
|
||||
val byteArray = ByteArray(6) {
|
||||
if (it < 4) {
|
||||
ipv4ByteArray[it]
|
||||
} else {
|
||||
portByteArray[it - 4]
|
||||
}
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址和端口信息写入字节缓冲区
|
||||
*
|
||||
* 该函数依次将网络地址的IPv4表示和网络端口写入到指定的字节缓冲区中
|
||||
*
|
||||
* @param byteBuffer 要写入数据的目标字节缓冲区
|
||||
*/
|
||||
fun writeIpv4toByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
networkAddress.writeIpv4ToByteBuffer(byteBuffer)
|
||||
networkPort.writeToByteBuffer(byteBuffer)
|
||||
return byteBuffer
|
||||
}
|
||||
}
|
||||
247
src/main/kotlin/com/mingliqiye/utils/network/NetworkAddress.kt
Normal file
247
src/main/kotlin/com/mingliqiye/utils/network/NetworkAddress.kt
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NetworkAddress.kt
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
import com.mingliqiye.utils.string.join
|
||||
import java.io.Serializable
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。
|
||||
* 支持IPv4和IPv6地址的解析与验证。
|
||||
*
|
||||
* @author MingLiPro
|
||||
*/
|
||||
class NetworkAddress private constructor(domip: String) : Serializable {
|
||||
|
||||
/**
|
||||
* IPv6标识
|
||||
*/
|
||||
companion object {
|
||||
const val IPV6 = 6
|
||||
|
||||
/**
|
||||
* IPv4标识
|
||||
*/
|
||||
const val IPV4 = 4
|
||||
|
||||
/**
|
||||
* IPv4地址正则表达式
|
||||
*/
|
||||
private const val IPV4REG =
|
||||
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"
|
||||
|
||||
/**
|
||||
* 编译后的IPv4地址匹配模式
|
||||
*/
|
||||
private val IPV4_PATTERN = Pattern.compile(IPV4REG)
|
||||
|
||||
/**
|
||||
* IPv6地址正则表达式
|
||||
*/
|
||||
private const val IPV6REG =
|
||||
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + "|" + "^(::)$|" + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$"
|
||||
|
||||
/**
|
||||
* 编译后的IPv6地址匹配模式
|
||||
*/
|
||||
private val IPV6_PATTERN = Pattern.compile(IPV6REG)
|
||||
|
||||
/**
|
||||
* 静态工厂方法,创建 NetworkAddress 实例。
|
||||
*
|
||||
* @param domip 可能是IP地址或域名的字符串
|
||||
* @return 新建的 NetworkAddress 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(domip: String): NetworkAddress {
|
||||
return NetworkAddress(domip)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkAddress {
|
||||
val byteArray = ByteArray(4)
|
||||
byteBuffer.get(byteArray)
|
||||
return ofIpv4(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkAddress {
|
||||
return of(".".join(byteArray.map {
|
||||
(it.toInt() and 0xFF).toString()
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。
|
||||
*
|
||||
* @param inetAddress InetAddress 对象
|
||||
* @return 新建的 NetworkAddress 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(inetAddress: InetAddress): NetworkAddress {
|
||||
return NetworkAddress(inetAddress.hostAddress)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从DNS服务器解析域名获取对应的IP地址。
|
||||
*
|
||||
* @param domain 域名
|
||||
* @return 解析出的第一个IP地址
|
||||
* @throws java.net.UnknownHostException 如果域名无法解析
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(UnknownHostException::class)
|
||||
fun getHostIp(domain: String): String {
|
||||
val addresses = InetAddress.getAllByName(domain.trim())
|
||||
return addresses[0].hostAddress
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测给定字符串是否为有效的IPv4或IPv6地址。
|
||||
*
|
||||
* @param ip 要检测的IP地址字符串
|
||||
* @return 4 表示IPv4,6 表示IPv6
|
||||
* @throws NetworkException 如果IP格式无效
|
||||
*/
|
||||
@JvmStatic
|
||||
fun testIp(ip: String?): Int {
|
||||
if (ip == null) {
|
||||
throw NetworkException("IP地址不能为null")
|
||||
}
|
||||
val trimmedIp = ip.trim()
|
||||
|
||||
// 判断是否匹配IPv4格式
|
||||
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
|
||||
return IPV4
|
||||
}
|
||||
|
||||
// 判断是否匹配IPv6格式
|
||||
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
|
||||
return IPV6
|
||||
}
|
||||
|
||||
// 不符合任一格式时抛出异常
|
||||
throw NetworkException(
|
||||
"[$ip] 不是有效的IPv4或IPv6地址"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IP地址类型:4 表示 IPv4,6 表示 IPv6
|
||||
*/
|
||||
var iPv: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* IP地址字符串
|
||||
*/
|
||||
var ip: String? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* 域名(如果输入的是域名)
|
||||
*/
|
||||
private var domain: String? = null
|
||||
|
||||
/**
|
||||
* 标识是否是域名解析来的IP
|
||||
*/
|
||||
private var isdom = false
|
||||
|
||||
/**
|
||||
* 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。
|
||||
*
|
||||
* @param domip 可能是IP地址或域名的字符串
|
||||
*/
|
||||
init {
|
||||
try {
|
||||
// 尝试将输入识别为IP地址
|
||||
this.iPv = testIp(domip)
|
||||
this.ip = domip
|
||||
} catch (e: NetworkException) {
|
||||
try {
|
||||
// 如果不是有效IP,则尝试作为域名解析
|
||||
val ips = getHostIp(domip)
|
||||
this.iPv = testIp(ips)
|
||||
this.ip = ips
|
||||
this.isdom = true
|
||||
this.domain = domip
|
||||
} catch (ex: UnknownHostException) {
|
||||
throw NetworkException(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址转换为字节数组
|
||||
*
|
||||
* @return 返回表示IPv4地址的4字节数组
|
||||
* @throws NetworkException 当当前地址不是IPv4地址时抛出异常
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
// 验证地址类型是否为IPv4
|
||||
if (iPv != IPV4) {
|
||||
throw NetworkException("该地址 不是IPv4地址")
|
||||
}
|
||||
// 将IP地址字符串按点分割,转换为整数并进行位运算处理,最后转为字节数组
|
||||
return ip!!.split(".").map { it.toInt() and 0xFF }.map { it.toByte() }.toByteArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址写入到指定的ByteBuffer中
|
||||
*
|
||||
* @param byteBuffer 要写入的ByteBuffer对象,IPv4地址将以字节数组形式写入到该缓冲区
|
||||
* @return 返回写入了IPv4地址的ByteBuffer对象,便于链式调用
|
||||
*/
|
||||
fun writeIpv4ToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toIpv4ByteArray())
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前 NetworkAddress 转换为 InetAddress 对象。
|
||||
*
|
||||
* @return InetAddress 对象
|
||||
*/
|
||||
fun toInetAddress(): InetAddress {
|
||||
try {
|
||||
return InetAddress.getByName(if (ip != null) ip else domain)
|
||||
} catch (e: UnknownHostException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 NetworkAddress 的字符串表示形式。
|
||||
*
|
||||
* @return 字符串表示
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return if (isdom) "NetworkAddress(IP='$ip',type='$iPv',domain='$domain')"
|
||||
else "NetworkAddress(IP='$ip',type='$iPv')"
|
||||
}
|
||||
}
|
||||
206
src/main/kotlin/com/mingliqiye/utils/network/NetworkEndpoint.kt
Normal file
206
src/main/kotlin/com/mingliqiye/utils/network/NetworkEndpoint.kt
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NetworkEndpoint.kt
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
import java.io.Serializable
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/**
|
||||
* IP和端口聚集类,用于封装网络地址与端口信息。
|
||||
* 该类提供了与InetSocketAddress之间的相互转换功能。
|
||||
*
|
||||
* @author MingLiPro
|
||||
* @see java.net.InetSocketAddress
|
||||
*/
|
||||
class NetworkEndpoint private constructor(
|
||||
val networkAddress: NetworkAddress, val networkPort: NetworkPort
|
||||
) : Serializable, InetSocketAddress(networkAddress.toInetAddress(), networkPort.port) {
|
||||
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。
|
||||
*
|
||||
* @param address InetSocketAddress对象
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
* @see InetSocketAddress
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(address: InetSocketAddress): NetworkEndpoint {
|
||||
return NetworkEndpoint(
|
||||
NetworkAddress.of(address.hostString), NetworkPort(address.port)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。
|
||||
*
|
||||
* @param s 主机名或IP地址字符串
|
||||
* @param i 端口号
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(s: String, i: Int): NetworkEndpoint {
|
||||
val networkAddress = NetworkAddress.of(s)
|
||||
val networkPort = NetworkPort(i)
|
||||
return NetworkEndpoint(networkAddress, networkPort)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建IPv4网络端点
|
||||
*
|
||||
* @param byteArray 包含IPv4地址和端口信息的字节数组,前4个字节表示IP地址,后2个字节表示端口号
|
||||
* @return NetworkEndpoint对象,封装了IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkEndpoint {
|
||||
// 提取前4个字节作为IP地址
|
||||
val address = ByteArray(4) {
|
||||
byteArray[it]
|
||||
}
|
||||
// 提取后2个字节作为端口号
|
||||
val portInt = ByteArray(2) {
|
||||
byteArray[it + 4]
|
||||
}
|
||||
return NetworkEndpoint(NetworkAddress.ofIpv4(address), NetworkPort.of(portInt))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节缓冲区创建IPv4网络端点实例
|
||||
*
|
||||
* 该方法从给定的ByteBuffer中读取数据,构建一个包含IPv4地址和端口的网络端点对象。
|
||||
* 该方法按照协议顺序从缓冲区中读取IPv4地址数据和端口数据。
|
||||
*
|
||||
* @param byteBuffer 包含IPv4地址和端口数据的字节缓冲区,缓冲区中的数据应按照先地址后端口的顺序排列
|
||||
* @return 返回一个NetworkEndpoint实例,包含从缓冲区解析出的IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkEndpoint {
|
||||
return NetworkEndpoint(
|
||||
NetworkAddress.ofIpv4(byteBuffer),
|
||||
NetworkPort.of(byteBuffer)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据"host:port"格式的字符串创建NetworkEndpoint实例。
|
||||
* 例如:"127.0.0.1:8080"
|
||||
*
|
||||
* @param s "host:port"格式的字符串
|
||||
* @return 新建的NetworkEndpoint实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(s: String): NetworkEndpoint {
|
||||
val lastColonIndex = s.lastIndexOf(':')
|
||||
return of(
|
||||
s.take(lastColonIndex), s.substring(lastColonIndex + 1).toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前NetworkEndpoint转换为InetSocketAddress对象。
|
||||
*
|
||||
* @return 对应的InetSocketAddress对象
|
||||
* @see InetSocketAddress
|
||||
*/
|
||||
fun toInetSocketAddress(): InetSocketAddress {
|
||||
return InetSocketAddress(
|
||||
networkAddress.toInetAddress(), networkPort.port
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前NetworkEndpoint转换为"host:port"格式的字符串。
|
||||
* 例如:"127.0.0.1:25563"
|
||||
*
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
fun toHostPortString(): String {
|
||||
return "${networkAddress.ip}:${networkPort.port}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回NetworkEndpoint的详细字符串表示形式。
|
||||
* 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...)
|
||||
*
|
||||
* @return 包含详细信息的字符串
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port})"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机名或IP地址字符串。
|
||||
*
|
||||
* @return 主机名或IP地址
|
||||
*/
|
||||
fun host(): String {
|
||||
return networkAddress.ip ?: ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取端口号。
|
||||
*
|
||||
* @return 端口号
|
||||
*/
|
||||
fun port(): Int {
|
||||
return networkPort.port
|
||||
}
|
||||
|
||||
/**
|
||||
* 将网络地址和端口转换为IPv4字节数组
|
||||
*
|
||||
* 该函数将当前对象的网络地址转换为IPv4字节数组,并与端口字节数组合并,
|
||||
* 生成一个包含6个字节的数组,其中前4个字节为IPv4地址,后2个字节为端口号
|
||||
*
|
||||
* @return ByteArray 包含6个字节的数组,前4个字节为IPv4地址,后2个字节为端口号
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
val ipv4ByteArray = networkAddress.toIpv4ByteArray()
|
||||
val portByteArray = networkPort.toByteArray()
|
||||
// 构建包含IPv4地址和端口的6字节数组
|
||||
val byteArray = ByteArray(6) {
|
||||
if (it < 4) {
|
||||
ipv4ByteArray[it]
|
||||
} else {
|
||||
portByteArray[it - 4]
|
||||
}
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址和端口信息写入字节缓冲区
|
||||
*
|
||||
* 该函数依次将网络地址的IPv4表示和网络端口写入到指定的字节缓冲区中
|
||||
*
|
||||
* @param byteBuffer 要写入数据的目标字节缓冲区
|
||||
*/
|
||||
fun writeIpv4toByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
networkAddress.writeIpv4ToByteBuffer(byteBuffer)
|
||||
networkPort.writeToByteBuffer(byteBuffer)
|
||||
return byteBuffer
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NetworkException.kt
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
class NetworkException : RuntimeException {
|
||||
/**
|
||||
* 构造一个带有指定详细消息的网络异常
|
||||
*
|
||||
* @param message 异常的详细消息
|
||||
*/
|
||||
constructor(message: String?) : super(message)
|
||||
|
||||
/**
|
||||
* 构造一个网络异常,指定原因异常
|
||||
*
|
||||
* @param e 导致此异常的原因异常
|
||||
*/
|
||||
constructor(e: Exception?) : super(e)
|
||||
}
|
||||
91
src/main/kotlin/com/mingliqiye/utils/network/NetworkPort.kt
Normal file
91
src/main/kotlin/com/mingliqiye/utils/network/NetworkPort.kt
Normal 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 NetworkPort.kt
|
||||
* LastUpdate 2026-02-05 10:20:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
import java.io.Serializable
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
class NetworkPort : Serializable {
|
||||
val port: Int
|
||||
|
||||
constructor(port: Int) {
|
||||
testPort(port)
|
||||
this.port = port
|
||||
}
|
||||
|
||||
fun toByteArray(): ByteArray {
|
||||
val byteArray = ByteArray(2)
|
||||
byteArray[0] = (port shr 8 and 0xFF).toByte()
|
||||
byteArray[1] = (port and 0xFF).toByte()
|
||||
return byteArray
|
||||
}
|
||||
|
||||
fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toByteArray())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 创建NetworkPort实例
|
||||
* @param port 端口号
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(port: Int): NetworkPort {
|
||||
return NetworkPort(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建NetworkPort实例
|
||||
* @param byteArray 包含端口信息的字节数组(长度至少为2)
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteArray: ByteArray): NetworkPort {
|
||||
// 将字节数组的前两个字节转换为端口号
|
||||
val port = ((byteArray[0].toInt() and 0xFF) shl 8) or (byteArray[1].toInt() and 0xFF)
|
||||
return of(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ByteBuffer创建NetworkPort实例
|
||||
* @param byteBuffer 包含端口信息的ByteBuffer
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteBuffer: ByteBuffer): NetworkPort {
|
||||
val byteArray = ByteArray(2)
|
||||
byteBuffer.get(byteArray)
|
||||
return of(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testPort(port: Int) {
|
||||
// 验证端口号范围是否在0-65535之间
|
||||
if (port !in 0..65535) {
|
||||
throw NetworkException("$port 不是正确的端口号")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/main/kotlin/com/mingliqiye/utils/objects/NullUtils.kt
Normal file
53
src/main/kotlin/com/mingliqiye/utils/objects/NullUtils.kt
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile NullUtils.kt
|
||||
* LastUpdate 2026-02-05 10:17:02
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("NullUtils")
|
||||
|
||||
package com.mingliqiye.utils.objects
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun Any?.isNotNull(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isNotNull != null)
|
||||
}
|
||||
return !isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun Any?.isNull(): Boolean {
|
||||
contract {
|
||||
returns(false) implies (this@isNull != null)
|
||||
}
|
||||
return this == null
|
||||
}
|
||||
|
||||
fun areEquals(a: Any?, b: Any?) = (a == null && b == null) || (a == b)
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun areEqualsNoNull(a: Any?, b: Any?): Boolean {
|
||||
contract {
|
||||
returns(true) implies (a != null && b != null)
|
||||
}
|
||||
return a != null && b != null && a == b
|
||||
}
|
||||
@ -28,8 +28,17 @@ import java.io.File
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
|
||||
class OsPath private constructor(private val path: Path) : Path by path {
|
||||
override fun forEach(action: Consumer<in Path>?) {
|
||||
path.forEach(action)
|
||||
}
|
||||
|
||||
override fun spliterator(): Spliterator<Path?> {
|
||||
return path.spliterator()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,15 +16,13 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile RandomBytes.kt
|
||||
* LastUpdate 2025-09-16 17:42:26
|
||||
* LastUpdate 2026-01-28 10:47:13
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("RandomBytes")
|
||||
|
||||
package com.mingliqiye.utils.random
|
||||
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字节数组
|
||||
* @param length 数组长度
|
||||
@ -38,6 +36,7 @@ fun randomBytes(length: Int): ByteArray {
|
||||
return bytes
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字节数组
|
||||
* 从给定的字节数组中随机选择字节来填充新数组
|
||||
@ -81,12 +80,8 @@ fun randomByteNoHave(from: Byte, to: Byte): Byte {
|
||||
return (randomValue and 0xFF).toByte()
|
||||
}
|
||||
|
||||
val secureRandom: SecureRandom by lazy {
|
||||
SecureRandom.getInstanceStrong()
|
||||
}
|
||||
|
||||
|
||||
fun randomByteSecure(size: Int): ByteArray {
|
||||
fun randomByte(size: Int): ByteArray {
|
||||
val bytes = ByteArray(size)
|
||||
secureRandom.nextBytes(bytes)
|
||||
return bytes
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,14 +16,24 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile RandomInt.kt
|
||||
* LastUpdate 2025-09-12 17:08:32
|
||||
* LastUpdate 2026-01-28 10:46:02
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("RandomInt")
|
||||
|
||||
package com.mingliqiye.utils.random
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
import java.security.SecureRandom
|
||||
|
||||
val secureRandom: SecureRandom by lazy {
|
||||
SecureRandom.getInstanceStrong()
|
||||
}
|
||||
|
||||
|
||||
fun SecureRandom.nextInt(min: Int, max: Int): Int {
|
||||
return min + nextInt(max - min)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成指定范围内的随机整数
|
||||
@ -42,7 +52,7 @@ fun randomIntNoHave(min: Int, max: Int): Int {
|
||||
if (min == max) {
|
||||
return min
|
||||
}
|
||||
return ThreadLocalRandom.current().nextInt(min, max)
|
||||
return secureRandom.nextInt(min, max)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,6 +65,3 @@ fun randomInt(min: Int, max: Int): Int {
|
||||
var max = max
|
||||
return randomIntNoHave(min, ++max)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile RandomString.kt
|
||||
* LastUpdate 2025-09-12 17:10:43
|
||||
* LastUpdate 2026-02-05 11:12:36
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("RandomString")
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Require.kt
|
||||
* LastUpdate 2026-01-10 09:01:03
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.request
|
||||
|
||||
import com.mingliqiye.utils.functions.P1RFunction
|
||||
import com.mingliqiye.utils.functions.RFunction
|
||||
|
||||
/**
|
||||
* 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常构造器
|
||||
* @param message 异常消息
|
||||
* @param exception 异常构造器函数
|
||||
* @return Require对象
|
||||
*/
|
||||
fun Boolean.require(message: String, exception: P1RFunction<String, out Exception>): Require {
|
||||
return Require(this, message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展函数:基于布尔值创建Require对象,并指定异常消息和异常类型
|
||||
* @param message 异常消息
|
||||
* @param exception 异常类型,默认为IllegalArgumentException
|
||||
* @return Require对象
|
||||
*/
|
||||
fun Boolean.require(
|
||||
message: String,
|
||||
exception: Class<out Exception> = IllegalArgumentException::class.java
|
||||
): Require {
|
||||
return Require(this, message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件检查工具类,用于验证条件并抛出相应异常
|
||||
* @param must 需要验证的布尔条件
|
||||
*/
|
||||
class Require(private val must: Boolean) {
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器
|
||||
* @param funs 返回布尔值的函数
|
||||
*/
|
||||
constructor(funs: RFunction<Boolean>) : this(funs.call())
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
*/
|
||||
constructor(must: RFunction<Boolean>, message: String) : this(must) {
|
||||
throws(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过函数调用结果初始化条件检查器,并立即执行检查
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException
|
||||
*/
|
||||
constructor(
|
||||
must: RFunction<Boolean>,
|
||||
message: String,
|
||||
exception: Class<out Exception> = IllegalArgumentException::class.java
|
||||
) : this(must) {
|
||||
throws(message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过布尔值初始化条件检查器,并立即执行检查
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
*/
|
||||
constructor(must: Boolean, message: String) : this(must) {
|
||||
throws(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过布尔值初始化条件检查器,并立即执行检查
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException
|
||||
*/
|
||||
constructor(
|
||||
must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java
|
||||
) : this(must) {
|
||||
throws(message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数:通过布尔值初始化条件检查器,并立即执行检查
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常构造器函数
|
||||
*/
|
||||
constructor(
|
||||
must: Boolean, message: String, exception: P1RFunction<String, out Exception>
|
||||
) : this(must) {
|
||||
throws(message, exception)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象并指定异常消息和异常类型
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(
|
||||
must: Boolean, message: String, exception: Class<out Exception> = IllegalArgumentException::class.java
|
||||
): Require {
|
||||
return Require(must, message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象并指定异常消息
|
||||
* @param must 需要验证的布尔条件
|
||||
* @param message 检查失败时的异常消息
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(must: Boolean, message: String): Require {
|
||||
return Require(must, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象
|
||||
* @param must 需要验证的布尔条件
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(must: Boolean): Require {
|
||||
return Require(must)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象并指定异常消息和异常类型
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型,默认为IllegalArgumentException
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(
|
||||
must: RFunction<Boolean>,
|
||||
message: String,
|
||||
exception: Class<out Exception> = IllegalArgumentException::class.java
|
||||
): Require {
|
||||
return Require(must, message, exception)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象并指定异常消息
|
||||
* @param must 返回布尔值的函数
|
||||
* @param message 检查失败时的异常消息
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(must: RFunction<Boolean>, message: String): Require {
|
||||
return Require(must, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂方法:创建Require对象
|
||||
* @param must 返回布尔值的函数
|
||||
* @return Require对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun require(must: RFunction<Boolean>): Require {
|
||||
return Require(must)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行条件检查,如果条件为false则抛出IllegalArgumentException
|
||||
* @param message 检查失败时的异常消息
|
||||
*/
|
||||
fun throws(message: String) {
|
||||
if (!must) {
|
||||
throw IllegalArgumentException(message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行条件检查,如果条件为false则抛出指定类型的异常
|
||||
* @param string 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常类型
|
||||
*/
|
||||
fun throws(string: String, exception: Class<out Exception>) {
|
||||
if (!must) {
|
||||
throw exception.getConstructor(String::class.java).newInstance(string)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行条件检查,如果条件为false则抛出由函数构造的异常
|
||||
* @param string 检查失败时的异常消息
|
||||
* @param exception 检查失败时抛出的异常构造器函数
|
||||
*/
|
||||
fun throws(string: String, exception: P1RFunction<String, out Exception>) {
|
||||
if (!must) {
|
||||
throw exception.call(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
200
src/main/kotlin/com/mingliqiye/utils/require/Require.kt
Normal file
200
src/main/kotlin/com/mingliqiye/utils/require/Require.kt
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Require.kt
|
||||
* LastUpdate 2026-02-05 11:08:03
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.require
|
||||
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import org.slf4j.Logger
|
||||
import java.lang.reflect.Constructor
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/**
|
||||
* 工具对象,用于提供条件检查功能。
|
||||
* 支持抛出自定义异常、延迟消息构造以及日志记录等功能。
|
||||
*/
|
||||
object Require {
|
||||
|
||||
/**
|
||||
* 日志记录器实例,用于记录错误信息。
|
||||
*/
|
||||
@JvmStatic
|
||||
var logger: Logger? = MingLiLoggerFactory.getLogger<Require>()
|
||||
|
||||
/**
|
||||
* 控制是否在抛出异常时记录错误日志。
|
||||
*/
|
||||
@JvmStatic
|
||||
var isLogError = true
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则抛出 [IllegalArgumentException] 异常。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmStatic
|
||||
fun require(value: Boolean) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
require<IllegalArgumentException>(value, "the require conditions are not met.")
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则根据指定的异常类型抛出异常。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param message 异常消息。
|
||||
* @param T 异常类型。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmName("__inline_Require")
|
||||
inline fun <reified T : Throwable> require(value: Boolean, message: String) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
require(value, message, T::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则抛出 [IllegalArgumentException] 异常。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param message 异常消息。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun require(value: Boolean, message: String) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
if (!value) throwThrowable(getExceptionConstructor<IllegalArgumentException>().newInstance(message))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则使用延迟消息构造器生成异常并抛出。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param throwable 异常类型。
|
||||
* @param layzMessage 延迟消息构造器。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmStatic
|
||||
fun require(value: Boolean, throwable: Class<out Throwable>, layzMessage: RequireLayzMessageConstructor) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
require(value, layzMessage.call(), throwable)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则使用延迟异常构造器生成异常并抛出。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param layzThrowable 延迟异常构造器。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmStatic
|
||||
fun require(value: Boolean, layzThrowable: RequireLayzExceptionConstructor) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
if (!value) throwThrowable(layzThrowable.call())
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则使用延迟消息构造器生成 [IllegalArgumentException] 并抛出。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param layzMessage 延迟消息构造器。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmStatic
|
||||
fun requireLayzMessage(value: Boolean, layzMessage: RequireLayzMessageConstructor) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
require<IllegalArgumentException>(value, layzMessage)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则根据指定的异常类型和延迟消息构造器生成异常并抛出。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param layzMessage 延迟消息构造器。
|
||||
* @param T 异常类型。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmName("__inline_Require")
|
||||
inline fun <reified T : Throwable> require(value: Boolean, layzMessage: RequireLayzMessageConstructor) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
if (!value) throwThrowable(getExceptionConstructor<T>().newInstance(layzMessage.call()))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定条件是否为真。如果为假,则根据指定的异常类型和消息生成异常并抛出。
|
||||
*
|
||||
* @param value 需要检查的布尔值。
|
||||
* @param message 异常消息。
|
||||
* @param throwable 异常类型。
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmStatic
|
||||
fun require(value: Boolean, message: String, throwable: Class<out Throwable>) {
|
||||
contract {
|
||||
returns() implies value
|
||||
}
|
||||
if (!value) throwThrowable(getExceptionConstructor(throwable).newInstance(message))
|
||||
}
|
||||
|
||||
/**
|
||||
* 抛出指定的异常,并在启用日志记录时记录错误信息。
|
||||
*
|
||||
* @param throwable 需要抛出的异常。
|
||||
*/
|
||||
fun throwThrowable(throwable: Throwable) {
|
||||
if (isLogError && logger != null) logger!!.error(throwable.message, throwable)
|
||||
throw throwable
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定异常类型的构造函数(带字符串参数)。
|
||||
*
|
||||
* @param T 异常类型。
|
||||
* @return 异常类型的构造函数。
|
||||
*/
|
||||
@JvmName("__inline_GetExceptionConstructor")
|
||||
inline fun <reified T : Throwable> getExceptionConstructor(): Constructor<out T> =
|
||||
getExceptionConstructor(T::class.java)
|
||||
|
||||
/**
|
||||
* 获取指定异常类型的构造函数(带字符串参数)。
|
||||
*
|
||||
* @param throwable 异常类型。
|
||||
* @return 异常类型的构造函数。
|
||||
*/
|
||||
@JvmName("__GetExceptionConstructor")
|
||||
fun <T : Throwable> getExceptionConstructor(throwable: Class<out T>): Constructor<out T> =
|
||||
throwable.getConstructor(String::class.java)
|
||||
}
|
||||
@ -15,16 +15,14 @@
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Main.kt
|
||||
* LastUpdate 2026-01-06 14:36:10
|
||||
* CurrentFile RequireLayzExceptionConstructor.kt
|
||||
* LastUpdate 2026-02-05 09:36:19
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("Main")
|
||||
|
||||
package com.mingliqiye.utils.main
|
||||
package com.mingliqiye.utils.require
|
||||
|
||||
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
||||
|
||||
fun main() {
|
||||
AutoConfiguration.printBanner()
|
||||
@FunctionalInterface
|
||||
fun interface RequireLayzExceptionConstructor {
|
||||
fun call(): Throwable
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile RequireLayzMessageConstructor.kt
|
||||
* LastUpdate 2026-02-05 09:36:09
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.require
|
||||
|
||||
@FunctionalInterface
|
||||
fun interface RequireLayzMessageConstructor {
|
||||
fun call(): String
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,72 +16,120 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile ResourceUtils.kt
|
||||
* LastUpdate 2025-09-20 10:26:47
|
||||
* LastUpdate 2026-02-05 11:09:16
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
package com.mingliqiye.utils.resource
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
class ResourceUtils {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResource(resourceName: String): ByteArray {
|
||||
return getResource(resourceName, ResourceUtils::class.java)
|
||||
}
|
||||
/**
|
||||
* 工具类,用于从类路径中加载资源文件。
|
||||
*/
|
||||
object ResourceUtils {
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResource(resourceName: String, clazz: Class<*>): ByteArray {
|
||||
return clazz.getResourceAsStream(resourceName)?.use {
|
||||
it.readBytes()
|
||||
} ?: throw IOException("Resource not found: $resourceName")
|
||||
}
|
||||
/**
|
||||
* 从默认类路径中加载指定名称的资源文件,并以字节数组形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @return 资源文件的内容作为字节数组。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResource(resourceName: String): ByteArray {
|
||||
return getResource(resourceName, ResourceUtils::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定类的类路径中加载指定名称的资源文件,并以字节数组形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @param clazz 用于定位资源的类。
|
||||
* @return 资源文件的内容作为字节数组。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResource(resourceName: String, clazz: Class<*>): ByteArray {
|
||||
return clazz.getResourceAsStream(resourceName)?.use {
|
||||
it.readBytes()
|
||||
} ?: throw IOException("Resource not found: $resourceName")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResource(resourceName: String): String {
|
||||
return getStringResource(resourceName, ResourceUtils::class.java)
|
||||
}
|
||||
/**
|
||||
* 从默认类路径中加载指定名称的资源文件,并以字符串形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @return 资源文件的内容作为字符串(使用UTF-8编码)。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResource(resourceName: String): String {
|
||||
return getStringResource(resourceName, ResourceUtils::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定类的类路径中加载指定名称的资源文件,并以字符串形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @param clazz 用于定位资源的类。
|
||||
* @return 资源文件的内容作为字符串(使用UTF-8编码)。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResource(resourceName: String, clazz: Class<*>): String {
|
||||
return clazz.getResourceAsStream(resourceName)?.use {
|
||||
it.readBytes().toString(charset = Charsets.UTF_8)
|
||||
} ?: throw IOException("Resource not found: $resourceName")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResource(resourceName: String, clazz: Class<*>): String {
|
||||
return clazz.getResourceAsStream(resourceName)?.use {
|
||||
it.readBytes().toString(charset = Charsets.UTF_8)
|
||||
} ?: throw IOException("Resource not found: $resourceName")
|
||||
}
|
||||
/**
|
||||
* 从调用者的类路径中加载指定名称的资源文件,并以字符串形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @return 资源文件的内容作为字符串(使用UTF-8编码)。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResourceCallers(resourceName: String): String {
|
||||
return getStringResource(resourceName, getCallerClass())
|
||||
}
|
||||
|
||||
/**
|
||||
* 从调用者的类路径中加载指定名称的资源文件,并以字节数组形式返回。
|
||||
*
|
||||
* @param resourceName 资源文件的名称(相对于类路径根目录)。
|
||||
* @return 资源文件的内容作为字节数组。
|
||||
* @throws IOException 如果资源未找到或读取失败时抛出。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResourceCallers(resourceName: String): ByteArray {
|
||||
return getResource(resourceName, getCallerClass())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getStringResourceCallers(resourceName: String): String {
|
||||
return getStringResource(resourceName, getCallerClass())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun getResourceCallers(resourceName: String): ByteArray {
|
||||
return getResource(resourceName, getCallerClass())
|
||||
}
|
||||
|
||||
private fun getCallerClass(): Class<*> {
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
for (i in 2 until stackTrace.size) {
|
||||
val className = stackTrace[i].className
|
||||
try {
|
||||
val clazz = Class.forName(className)
|
||||
if (clazz != ResourceUtils::class.java && clazz != Companion::class.java) {
|
||||
return clazz
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
continue
|
||||
/**
|
||||
* 获取当前调用栈中第一个非ResourceUtils类的调用者类。
|
||||
*
|
||||
* @return 调用者类对象;如果未找到则返回ResourceUtils类本身。
|
||||
*/
|
||||
private fun getCallerClass(): Class<*> {
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
for (i in 2 until stackTrace.size) {
|
||||
val className = stackTrace[i].className
|
||||
try {
|
||||
val clazz = Class.forName(className)
|
||||
if (clazz != ResourceUtils::class.java) {
|
||||
return clazz
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
continue
|
||||
}
|
||||
return ResourceUtils::class.java
|
||||
}
|
||||
return ResourceUtils::class.java
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile SecureUtils.kt
|
||||
* LastUpdate 2025-09-15 22:32:50
|
||||
* LastUpdate 2026-02-05 11:12:36
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -29,27 +29,64 @@ import java.security.SecureRandom
|
||||
import javax.crypto.SecretKey
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
/**
|
||||
* 全局安全随机数生成器实例,用于生成加密安全的随机字节。
|
||||
*/
|
||||
internal val SECURE_RANDOM = SecureRandom()
|
||||
|
||||
/**
|
||||
* 生成指定长度的加密安全随机字节数组。
|
||||
*
|
||||
* @param length 需要生成的字节数组的长度。
|
||||
* @return 包含随机字节的 ByteArray。
|
||||
*/
|
||||
fun getRandomBytes(length: Int): ByteArray {
|
||||
val bytes = ByteArray(length)
|
||||
SECURE_RANDOM.nextBytes(bytes)
|
||||
return bytes
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定算法对输入数据进行哈希处理,生成密钥字节数组。
|
||||
*
|
||||
* @param algorithm 哈希算法名称(如 SHA-256)。
|
||||
* @param data 输入的字节数组数据。
|
||||
* @return 经过哈希处理后的密钥字节数组。
|
||||
*/
|
||||
fun createSecretKey(algorithm: String, data: ByteArray): ByteArray {
|
||||
val md = MessageDigest.getInstance(algorithm)
|
||||
return md.digest(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定算法对输入字符串进行哈希处理,生成密钥字节数组。
|
||||
*
|
||||
* @param algorithm 哈希算法名称(如 SHA-256)。
|
||||
* @param data 输入的字符串数据。
|
||||
* @return 经过哈希处理后的密钥字节数组。
|
||||
*/
|
||||
fun createSecretKey(algorithm: String, data: String): ByteArray {
|
||||
return createSecretKey(algorithm, data.toByteArray())
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定算法和输入字符串创建 SecretKeySpec 对象。
|
||||
*
|
||||
* @param algorithm 哈希算法名称(如 AES)。
|
||||
* @param data 输入的字符串数据。
|
||||
* @return 根据输入数据和算法生成的 SecretKey 对象。
|
||||
*/
|
||||
fun createSecretKeySpec(algorithm: String, data: String): SecretKey {
|
||||
return SecretKeySpec(createSecretKey(algorithm, data), algorithm)
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定算法和输入字节数组创建 SecretKeySpec 对象。
|
||||
*
|
||||
* @param algorithm 哈希算法名称(如 AES)。
|
||||
* @param data 输入的字节数组数据。
|
||||
* @return 根据输入数据和算法生成的 SecretKey 对象。
|
||||
*/
|
||||
fun createSecretKeySpec(algorithm: String, data: ByteArray): SecretKey {
|
||||
return SecretKeySpec(createSecretKey(algorithm, data), algorithm)
|
||||
}
|
||||
|
||||
79
src/main/kotlin/com/mingliqiye/utils/sleep/SleepUtils.kt
Normal file
79
src/main/kotlin/com/mingliqiye/utils/sleep/SleepUtils.kt
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile SleepUtils.kt
|
||||
* LastUpdate 2026-01-15 16:50:50
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
package com.mingliqiye.utils.sleep
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* 等待工具类,提供多种等待和延迟执行的方式
|
||||
*/
|
||||
object SleepUtils {
|
||||
|
||||
/**
|
||||
* 基于 Thread.sleep 的等待,单位毫秒
|
||||
*
|
||||
* @param millis 等待时间(毫秒)
|
||||
* @throws RuntimeException 当线程被中断时抛出
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sleep(millis: Long) {
|
||||
try {
|
||||
Thread.sleep(millis)
|
||||
} catch (e: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
throw RuntimeException("Sleep interrupted", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 Thread.sleep 的等待,单位毫秒
|
||||
*
|
||||
* @param millis 等待时间(毫秒)
|
||||
* @throws RuntimeException 当线程被中断时抛出
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sleep(millis: Int) {
|
||||
try {
|
||||
Thread.sleep(millis.toLong())
|
||||
} catch (e: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
throw RuntimeException("Sleep interrupted", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 TimeUnit 的等待
|
||||
*
|
||||
* @param timeout 等待时间
|
||||
* @param unit 时间单位
|
||||
* @throws RuntimeException 当线程被中断时抛出
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sleep(timeout: Long, unit: TimeUnit) {
|
||||
try {
|
||||
unit.sleep(timeout)
|
||||
} catch (e: InterruptedException) {
|
||||
Thread.currentThread().interrupt()
|
||||
throw RuntimeException("Sleep interrupted", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +16,13 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile AutoConfiguration.kt
|
||||
* LastUpdate 2025-09-20 10:47:00
|
||||
* LastUpdate 2026-02-05 10:45:05
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.springboot.autoconfigure
|
||||
|
||||
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import com.mingliqiye.utils.system.computerName
|
||||
import com.mingliqiye.utils.system.getPid
|
||||
import com.mingliqiye.utils.system.jdkVersion
|
||||
@ -32,14 +32,24 @@ import com.mingliqiye.utils.time.Formatter
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* 自动配置类,用于Spring Boot应用启动时加载相关组件和打印启动横幅。
|
||||
*
|
||||
* 该类通过@ComponentScan注解扫描指定包下的Bean,并在初始化时打印包含系统信息的启动横幅。
|
||||
*/
|
||||
@org.springframework.boot.autoconfigure.AutoConfiguration
|
||||
@ComponentScan(
|
||||
"com.mingliqiye.utils.springboot.bean",
|
||||
"com.mingliqiye.utils.springboot.converters"
|
||||
)
|
||||
open class AutoConfiguration {
|
||||
private val log = MingLiLoggerFactory.getLogger("MingliUtils-AutoConfiguration")
|
||||
|
||||
companion object {
|
||||
private const val banner =
|
||||
/**
|
||||
* 启动横幅字符串,包含艺术字体和占位符。
|
||||
*/
|
||||
private const val BANNER =
|
||||
"---------------------------------------------------------\n" +
|
||||
"| $$\\ $$\\ $$\\ $$\\ $$\\ $$$$$$$$\\ $$$$$$\\ |\n" +
|
||||
"| $$$\\ $$$ |$$ | $$ | $$ |\\__$$ __|$$ __$$\\ |\n" +
|
||||
@ -49,25 +59,38 @@ open class AutoConfiguration {
|
||||
"| $$ |\\$ /$$ |$$ | $$ | $$ | $$ | $$\\ $$ | |\n" +
|
||||
"| $$ | \\_/ $$ |$$$$$$$$\\\\$$$$$$ | $$ | \\$$$$$$ | |\n" +
|
||||
"| \\__| \\__|\\________|\\______/ \\__| \\______/ |\n"
|
||||
private val log = mingLiLoggerFactory.getLogger("MingliUtils-AutoConfiguration")
|
||||
|
||||
/**
|
||||
* 打印启动横幅,包含系统元数据(如JDK版本、进程ID、计算机名等)。
|
||||
*
|
||||
* 该方法从资源文件中读取元数据,并将其格式化后追加到横幅中进行输出。
|
||||
* 如果读取资源失败,则仅打印默认横幅。
|
||||
*/
|
||||
fun printBanner() {
|
||||
val bannerBuilder = StringBuilder(banner)
|
||||
val bannerBuilder = StringBuilder(BANNER)
|
||||
|
||||
// 尝试从资源文件中读取元数据并拼接到横幅中
|
||||
try {
|
||||
val inputStream = AutoConfiguration::class.java.getResourceAsStream("/META-INF/meta-data") ?: return
|
||||
inputStream.use { stream ->
|
||||
var readlen: Int
|
||||
val buffer = ByteArray(1024)
|
||||
val metaData = StringBuilder()
|
||||
|
||||
// 逐块读取资源文件内容
|
||||
while (stream.read(buffer).also { readlen = it } != -1) {
|
||||
metaData.append(String(buffer, 0, readlen))
|
||||
}
|
||||
|
||||
// 解析元数据并添加额外的系统信息
|
||||
val da = metaData.toString().split("\n").toMutableList()
|
||||
da.add("jdkRuntime=$jdkVersion")
|
||||
da.add("pid=$getPid")
|
||||
da.add("computerName=$computerName")
|
||||
da.add("userName=$userName")
|
||||
da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true))
|
||||
da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7, false))
|
||||
|
||||
// 格式化每条元数据并追加到横幅中
|
||||
da.forEach { s: String ->
|
||||
val d = s.trim { it <= ' ' }.split("=".toRegex(), 2).toTypedArray()
|
||||
if (d.size >= 2) {
|
||||
@ -89,15 +112,23 @@ open class AutoConfiguration {
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
// 捕获IO异常并打印堆栈跟踪
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
// 输出最终构建的横幅
|
||||
println(bannerBuilder.toString().trim())
|
||||
println("---------------------------------------------------------")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化块,在类实例化时执行。
|
||||
*
|
||||
* 调用printBanner方法打印启动横幅,并记录日志表示自动配置成功。
|
||||
*/
|
||||
init {
|
||||
printBanner()
|
||||
log.info("MingliUtils AutoConfiguration succeed")
|
||||
log.info("MingliUtils AutoConfigurationBean succeed")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile GsonAutoConfiguration.kt
|
||||
* LastUpdate 2025-09-15 10:29:30
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.springboot.autoconfigure
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.mingliqiye.utils.json.GsonJsonApi
|
||||
import com.mingliqiye.utils.json.JsonApi
|
||||
import com.mingliqiye.utils.json.converters.DateTimeJsonConverter
|
||||
import com.mingliqiye.utils.json.converters.JsonStringConverter
|
||||
import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter
|
||||
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.gson.GsonBuilderCustomizer
|
||||
import org.springframework.context.annotation.Bean
|
||||
|
||||
@ConditionalOnClass(Gson::class)
|
||||
@AutoConfiguration
|
||||
@AutoConfigureAfter(
|
||||
name = ["org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration",
|
||||
"com.mingliqiye.utils.springboot.autoconfigure.JacksonAutoConfiguration"]
|
||||
)
|
||||
open class GsonAutoConfiguration {
|
||||
companion object {
|
||||
private val log: Logger = LoggerFactory.getLogger("MingliUtils-GsonAutoConfiguration")
|
||||
|
||||
fun addTypeAdapter(gsonBuilder: GsonBuilder): GsonBuilder {
|
||||
val dateTimeJsonConverter: JsonStringConverter<DateTime> = DateTimeJsonConverter()
|
||||
val uuidJsonStringConverter: JsonStringConverter<UUID> = UUIDJsonStringConverter()
|
||||
|
||||
try {
|
||||
return gsonBuilder
|
||||
.registerTypeAdapter(
|
||||
uuidJsonStringConverter.tClass,
|
||||
uuidJsonStringConverter
|
||||
.gsonJsonStringConverterAdapter
|
||||
.gsonTypeAdapter
|
||||
)
|
||||
.registerTypeAdapter(
|
||||
dateTimeJsonConverter.tClass,
|
||||
dateTimeJsonConverter
|
||||
.gsonJsonStringConverterAdapter
|
||||
.gsonTypeAdapter
|
||||
)
|
||||
} finally {
|
||||
log.info("MingliUtils GsonBuilder TypeAdapter add")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val log: Logger = mingLiLoggerFactory.getLogger("MingliUtils-GsonAutoConfiguration")
|
||||
|
||||
@Bean
|
||||
open fun mingliGsonCustomizer(): GsonBuilderCustomizer {
|
||||
return GsonBuilderCustomizer { gsonBuilder: GsonBuilder -> addTypeAdapter(gsonBuilder) }
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
open fun jsonApi(gson: Gson): JsonApi {
|
||||
log.info("MingliUtils-JsonApiAutoConfiguration: GsonJsonApi bean is created.")
|
||||
return GsonJsonApi(gson)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,61 +16,91 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile JacksonAutoConfiguration.kt
|
||||
* LastUpdate 2025-09-15 10:29:02
|
||||
* LastUpdate 2026-02-05 10:45:19
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.springboot.autoconfigure
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.mingliqiye.utils.json.JacksonJsonApi
|
||||
import com.mingliqiye.utils.json.JsonApi
|
||||
import com.mingliqiye.utils.json.api.JSONA
|
||||
import com.mingliqiye.utils.json.api.JacksonJsonApi
|
||||
import com.mingliqiye.utils.json.api.base.JsonApi
|
||||
import com.mingliqiye.utils.json.converters.DateTimeJsonConverter
|
||||
import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter
|
||||
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||
import com.mingliqiye.utils.json.converters.UUIDJsonConverter
|
||||
import com.mingliqiye.utils.json.converters.base.registerModule
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Primary
|
||||
|
||||
@ConditionalOnClass(ObjectMapper::class)
|
||||
@AutoConfiguration
|
||||
@AutoConfigureAfter(org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration::class)
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile JacksonAutoConfiguration.kt
|
||||
* LastUpdate 2026-02-05 10:39:54
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
/*
|
||||
* JacksonAutoConfiguration 是一个 Spring Boot 自动配置类,用于配置 Jackson 相关的序列化和反序列化功能。
|
||||
* 该类在检测到 ObjectMapper 和 Spring Boot 的 JacksonAutoConfiguration 存在时自动生效,
|
||||
* 并注册自定义的 JSON 转换器模块(如 UUID 和 DateTime 转换器)。
|
||||
*
|
||||
* @param objectMapper 用于 JSON 序列化和反序列化的 ObjectMapper 实例。
|
||||
*/
|
||||
@ConditionalOnClass(name = ["com.fasterxml.jackson.databind.ObjectMapper", "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"])
|
||||
@AutoConfigureAfter(name = ["org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"])
|
||||
open class JacksonAutoConfiguration(objectMapper: ObjectMapper) {
|
||||
companion object {
|
||||
private val log: Logger = mingLiLoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration")
|
||||
|
||||
fun addModules(objectMapper: ObjectMapper): ObjectMapper {
|
||||
return objectMapper
|
||||
.registerModule(
|
||||
DateTimeJsonConverter()
|
||||
.jacksonJsonStringConverterAdapter
|
||||
.jacksonModule
|
||||
)
|
||||
.registerModule(
|
||||
UUIDJsonStringConverter()
|
||||
.jacksonJsonStringConverterAdapter
|
||||
.jacksonModule
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val log: Logger = LoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration")
|
||||
private val log: Logger = MingLiLoggerFactory.getLogger("MingliUtils-JacksonAutoConfiguration")
|
||||
|
||||
/*
|
||||
* 初始化块:在类实例化时执行。
|
||||
* 注册自定义的 UUID 和 DateTime JSON 转换器模块到 ObjectMapper 中。
|
||||
*/
|
||||
init {
|
||||
addModules(objectMapper)
|
||||
log.info("MingliUtils Jackson Serializers created")
|
||||
objectMapper
|
||||
.registerModule<UUIDJsonConverter>()
|
||||
.registerModule<DateTimeJsonConverter>()
|
||||
}
|
||||
|
||||
/*
|
||||
* 创建并返回一个 JsonApi Bean 实例。
|
||||
* 该方法会在没有其他 JsonApi Bean 存在时被调用,并将创建的 JacksonJsonApi 实例设置为全局默认的 JSON API。
|
||||
*
|
||||
* @param objectMapper 用于 JSON 操作的 ObjectMapper 实例。
|
||||
* @return 返回配置好的 JsonApi 实例。
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
open fun jsonApi(objectMapper: ObjectMapper): JsonApi {
|
||||
log.info("MingliUtils-JsonApiAutoConfiguration: JacksonJsonApi bean is created.")
|
||||
return JacksonJsonApi(objectMapper)
|
||||
return JacksonJsonApi(objectMapper).also {
|
||||
try {
|
||||
JSONA.getJsonApi()
|
||||
} catch (_: NullPointerException) {
|
||||
JSONA.setJsonApi(it)
|
||||
log.info("JSONA Use {}", it.javaClass.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile SpringBeanUtils.kt
|
||||
* LastUpdate 2025-09-19 20:07:08
|
||||
* LastUpdate 2026-02-04 16:50:39
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -39,6 +39,9 @@ class SpringBeanUtils : ApplicationContextAware {
|
||||
@JvmStatic
|
||||
private var applicationContext: ApplicationContext? = null
|
||||
|
||||
@Throws(BeansException::class)
|
||||
inline fun <reified T> getBean() = getBean(T::class.java)
|
||||
|
||||
/**
|
||||
* 根据Bean名称获取Bean实例
|
||||
*
|
||||
@ -48,11 +51,9 @@ class SpringBeanUtils : ApplicationContextAware {
|
||||
* @throws ClassCastException 当类型转换失败时抛出
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(BeansException::class, ClassCastException::class)
|
||||
@Throws(BeansException::class)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> getBean(name: String): T {
|
||||
return applicationContext!!.getBean(name) as T
|
||||
}
|
||||
fun getBean(name: String): Any = applicationContext!!.getBean(name)
|
||||
|
||||
/**
|
||||
* 根据Bean类型获取Bean实例
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile DateTimeToStringConverter.kt
|
||||
* LastUpdate 2026-02-04 21:57:43
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.springboot.converters
|
||||
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
import com.mingliqiye.utils.time.Formatter
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class DateTimeToStringConverter : Converter<DateTime, String?> {
|
||||
override fun convert(source: DateTime): String {
|
||||
return source.format(Formatter.STANDARD_DATETIME)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -15,8 +15,8 @@
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Converters.kt
|
||||
* LastUpdate 2025-09-15 09:19:48
|
||||
* CurrentFile StringToDateTimeConverter.kt
|
||||
* LastUpdate 2026-02-04 21:57:43
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -24,35 +24,12 @@ package com.mingliqiye.utils.springboot.converters
|
||||
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
import com.mingliqiye.utils.time.Formatter
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import com.mingliqiye.utils.uuid.UUID.Companion.of
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class DateTimeToStringConverter : Converter<DateTime, String?> {
|
||||
override fun convert(source: DateTime): String {
|
||||
return source.format(Formatter.STANDARD_DATETIME)
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class UUIDToStringConverter : Converter<UUID, String> {
|
||||
override fun convert(source: UUID): String {
|
||||
return source.getString()
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class StringToDateTimeConverter : Converter<String, DateTime> {
|
||||
override fun convert(source: String): DateTime {
|
||||
return DateTime.parse(source, Formatter.STANDARD_DATETIME_MILLISECOUND7, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class StringToUUIDConverter : Converter<String, UUID> {
|
||||
override fun convert(source: String): UUID {
|
||||
return of(source)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -15,22 +15,20 @@
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile JsonConverter.kt
|
||||
* LastUpdate 2025-09-15 11:12:07
|
||||
* CurrentFile StringToUUIDConverter.kt
|
||||
* LastUpdate 2026-02-04 21:58:01
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.json.converters
|
||||
package com.mingliqiye.utils.springboot.converters
|
||||
|
||||
interface JsonConverter<F, T> {
|
||||
fun convert(obj: F?): T?
|
||||
fun deConvert(obj: T?): F?
|
||||
val tClass: Class<F>
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
fun getStringConverter(): JsonStringConverter<F>? {
|
||||
if (this is JsonStringConverter<*>) {
|
||||
return this as JsonStringConverter<F>
|
||||
}
|
||||
return null
|
||||
@Component
|
||||
class StringToUUIDConverter : Converter<String, UUID> {
|
||||
override fun convert(source: String): UUID {
|
||||
return UUID.of(source)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile UUIDToStringConverter.kt
|
||||
* LastUpdate 2026-02-04 21:57:43
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.springboot.converters
|
||||
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class UUIDToStringConverter : Converter<UUID, String> {
|
||||
override fun convert(source: UUID): String {
|
||||
return source.getString()
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,17 +16,26 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile StringUtils.kt
|
||||
* LastUpdate 2025-09-18 09:26:41
|
||||
* LastUpdate 2026-02-05 11:05:33
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("StringUtils")
|
||||
|
||||
package com.mingliqiye.utils.string
|
||||
|
||||
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||
import com.mingliqiye.utils.base.BASE16
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import com.mingliqiye.utils.objects.isNull
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
import java.security.MessageDigest
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
|
||||
val log = mingLiLoggerFactory.getLogger("StringUtils")
|
||||
private val log = MingLiLoggerFactory.getLogger(Class.forName("com.mingliqiye.utils.string.StringUtils"))
|
||||
|
||||
val NULLISH_STRINGS = setOf("null", "NaN", "undefined", "None", "none")
|
||||
|
||||
@ -36,11 +45,18 @@ val NULLISH_STRINGS = setOf("null", "NaN", "undefined", "None", "none")
|
||||
* @param str 待判断的字符串
|
||||
* @return `true`: 空 `false`: 非空
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@JvmName("isEmpty")
|
||||
fun String?.isNullish(): Boolean {
|
||||
return this == null || this.isBlank() || this in NULLISH_STRINGS
|
||||
contract {
|
||||
returns(false) implies (this@isNullish != null)
|
||||
}
|
||||
return this.isNullOrBlank() || this in NULLISH_STRINGS
|
||||
}
|
||||
|
||||
@JvmName("__Formatde")
|
||||
fun String.formatd(vararg args: Any) = com.mingliqiye.utils.string.format(this, *args)
|
||||
|
||||
/**
|
||||
* 格式化字符串,将字符串中的占位符{}替换为对应的参数值
|
||||
*
|
||||
@ -82,8 +98,16 @@ fun format(str: String, vararg args: Any?): String {
|
||||
|
||||
// 检查参数数量
|
||||
val placeholderCount = matches.count()
|
||||
if (argIndex != args.size) {
|
||||
if (placeholderCount != args.size) {
|
||||
log.warn("Placeholder count: $placeholderCount, Argument count: ${args.size}")
|
||||
log.warn("template : $str")
|
||||
log.warn(
|
||||
"Arguments : [${
|
||||
", ".join(args) {
|
||||
if (it.isNull()) return@join "null:null"
|
||||
"${it.javaClass.simpleName}:$it"
|
||||
}
|
||||
}]")
|
||||
}
|
||||
|
||||
return finalResult
|
||||
@ -214,3 +238,65 @@ fun <T> String.join(list: List<T>, getstring: (T) -> String = { it.toString() })
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun <T> String.join(array: Array<T>, getstring: (T) -> String = { it.toString() }): String {
|
||||
// 使用StringBuilder构建结果字符串
|
||||
val sb = StringBuilder()
|
||||
for (i in array.indices) {
|
||||
sb.append(getstring(array[i]))
|
||||
// 除了最后一个元素外,都在后面添加当前字符串作为分隔符
|
||||
if (i != array.size - 1) {
|
||||
sb.append(this)
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun String?.parserTemplate(template: String): List<String>? {
|
||||
if (this == null) return null
|
||||
val regex: Regex = Regex(
|
||||
"^" +
|
||||
template
|
||||
.replace("\\", "\\\\")
|
||||
.replace("(", "\\(")
|
||||
.replace(")", "\\)")
|
||||
.replace("[", "\\[")
|
||||
.replace("]", "\\]")
|
||||
.replace("+", "\\+")
|
||||
.replace("=", "\\=")
|
||||
.replace("{}", "((?s).*)")
|
||||
.toRegex() +
|
||||
"$"
|
||||
)
|
||||
val datas = regex.find(this)?.groupValues ?: return null
|
||||
return List(datas.size - 1) {
|
||||
datas[it + 1]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun String.urlEncode() = URLEncoder.encode(this, Charsets.UTF_8.name())
|
||||
fun String.urlDecode() = URLDecoder.decode(this, Charsets.UTF_8.name())
|
||||
|
||||
|
||||
fun String.hmacSHA256String(keyS: String): String {
|
||||
val instance = Mac.getInstance("HmacSHA256")
|
||||
val key = keyS.toByteArray()
|
||||
instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256"))
|
||||
val bytes = instance.doFinal(this.toByteArray())
|
||||
return BASE16.encode(bytes)
|
||||
}
|
||||
|
||||
fun String.md5String(): String {
|
||||
val instance = MessageDigest.getInstance("MD5")
|
||||
instance.update(this.toByteArray())
|
||||
val bytes = instance.digest()
|
||||
return BASE16.encode(bytes)
|
||||
}
|
||||
|
||||
fun String.hmacMd5String(keyS: String): String {
|
||||
val instance = Mac.getInstance("HmacMD5")
|
||||
val key = keyS.toByteArray()
|
||||
instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256"))
|
||||
val bytes = instance.doFinal(this.toByteArray())
|
||||
return BASE16.encode(bytes)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,19 +16,16 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile SystemUtil.kt
|
||||
* LastUpdate 2025-09-16 17:36:11
|
||||
* LastUpdate 2026-01-31 20:47:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("SystemUtils")
|
||||
|
||||
package com.mingliqiye.utils.system
|
||||
|
||||
import com.mingliqiye.utils.random.randomByteSecure
|
||||
import com.mingliqiye.utils.random.randomByte
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.net.Inet4Address
|
||||
import java.net.InetAddress
|
||||
import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
import java.net.*
|
||||
|
||||
/**
|
||||
* 操作系统名称属性,延迟初始化
|
||||
@ -256,10 +253,7 @@ val computerName: String by lazy {
|
||||
*/
|
||||
val userName: String by lazy {
|
||||
try {
|
||||
getEnvVar("USERNAME")
|
||||
?: getEnvVar("USER")
|
||||
?: System.getProperty("user.name")
|
||||
?: "unknown"
|
||||
getEnvVar("USERNAME") ?: getEnvVar("USER") ?: System.getProperty("user.name") ?: "unknown"
|
||||
} catch (e: SecurityException) {
|
||||
"unknown"
|
||||
} catch (e: Exception) {
|
||||
@ -297,11 +291,11 @@ val macAddressBytes: ByteArray by lazy {
|
||||
return@lazy mac
|
||||
}
|
||||
}
|
||||
randomByteSecure(6)
|
||||
randomByte(6)
|
||||
} catch (e: SocketException) {
|
||||
randomByteSecure(6)
|
||||
randomByte(6)
|
||||
} catch (e: Exception) {
|
||||
randomByteSecure(6)
|
||||
randomByte(6)
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,3 +369,91 @@ val allMacAddressesStringList: Map<String, List<String>> by lazy {
|
||||
entry.value.map { String.format("%02X", it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用处理器数量的懒加载属性
|
||||
*/
|
||||
val availableProcessors: Int by lazy {
|
||||
Runtime.getRuntime().availableProcessors()
|
||||
}
|
||||
|
||||
|
||||
private var isLoadprotocol = false
|
||||
private var protocol = ""
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否为开发模式(file协议)
|
||||
*/
|
||||
val isDevMode: Boolean by lazy {
|
||||
protocol == "file"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否不为开发模式
|
||||
*/
|
||||
val isNotDevMode: Boolean by lazy {
|
||||
protocol != "file"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为JAR模式
|
||||
*/
|
||||
val isJarMode: Boolean by lazy {
|
||||
protocol == "jar"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否不为JAR模式
|
||||
*/
|
||||
val isNotJarMode: Boolean by lazy {
|
||||
protocol != "jar"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为WAR模式
|
||||
*/
|
||||
val isWarMode: Boolean by lazy {
|
||||
protocol == "war"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否不为WAR模式
|
||||
*/
|
||||
val isNotMode: Boolean by lazy {
|
||||
protocol != "war"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为JSWAR模式
|
||||
*/
|
||||
val isJswarMode: Boolean by lazy {
|
||||
protocol == "jswar"
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否不为JSWAR模式
|
||||
*/
|
||||
val isNotJswarMode: Boolean by lazy {
|
||||
protocol != "jswar"
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载并获取资源协议
|
||||
* @param clazz 要获取协议的类对象,默认为null
|
||||
* @return 返回资源的协议字符串
|
||||
*/
|
||||
fun loadProtocol(clazz: Class<*>? = null): String {
|
||||
// 如果已经加载过协议且clazz为null,则直接返回已缓存的协议
|
||||
if (isLoadprotocol && clazz == null) {
|
||||
return protocol
|
||||
}
|
||||
val resource: URL? = clazz!!.getResource(
|
||||
clazz.getSimpleName() + ".class"
|
||||
)
|
||||
protocol = resource!!.protocol
|
||||
return protocol.let {
|
||||
isLoadprotocol = true
|
||||
return@let it
|
||||
}
|
||||
}
|
||||
|
||||
112
src/main/kotlin/com/mingliqiye/utils/thread/ThreadEvent.kt
Normal file
112
src/main/kotlin/com/mingliqiye/utils/thread/ThreadEvent.kt
Normal 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 ThreadEvent.kt
|
||||
* LastUpdate 2026-02-05 11:20:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.thread
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* 线程事件同步工具类,用于线程间的事件通知和等待
|
||||
*/
|
||||
open class ThreadEvent<T> {
|
||||
|
||||
private var latch = CountDownLatch(1)
|
||||
|
||||
@Volatile
|
||||
private var data: T
|
||||
|
||||
constructor(data: T) {
|
||||
this.data = data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前事件状态
|
||||
*
|
||||
* @return 当前事件的数据值,如果未设置则返回null
|
||||
*/
|
||||
fun get(): T = data
|
||||
|
||||
/**
|
||||
* 设置事件数据并释放等待的线程
|
||||
*
|
||||
* @param data 要设置的事件数据
|
||||
*/
|
||||
@Synchronized
|
||||
fun set(data: T) {
|
||||
this.data = data
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置事件状态,重新初始化CountDownLatch
|
||||
*/
|
||||
@Synchronized
|
||||
fun reset() {
|
||||
latch = CountDownLatch(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待事件被设置,阻塞当前线程直到事件被触发
|
||||
*/
|
||||
fun await() {
|
||||
latch.await()
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待事件被设置并获取数据
|
||||
*
|
||||
* @return 事件数据,当事件被设置后返回对应的数据
|
||||
*/
|
||||
fun awaitAndGet(): T {
|
||||
await()
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定超时时间内等待事件被设置并获取数据
|
||||
*
|
||||
* @param timeout 等待超时时间
|
||||
* @param unit 时间单位
|
||||
* @return 事件数据,如果在超时时间内事件被设置则返回数据,否则返回null
|
||||
*/
|
||||
fun awaitAndGet(timeout: Long, unit: TimeUnit): T? {
|
||||
await(timeout, unit)
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定超时时间内等待事件被设置
|
||||
*
|
||||
* @param timeout 等待超时时间
|
||||
* @param unit 时间单位
|
||||
* @return 如果在超时时间内事件被设置则返回true,否则返回false
|
||||
*/
|
||||
fun await(timeout: Long, unit: TimeUnit): Boolean {
|
||||
return latch.await(timeout, unit)
|
||||
}
|
||||
|
||||
fun setAndReset(data: T) {
|
||||
set(data)
|
||||
reset()
|
||||
}
|
||||
}
|
||||
110
src/main/kotlin/com/mingliqiye/utils/thread/ThreadRunner.kt
Normal file
110
src/main/kotlin/com/mingliqiye/utils/thread/ThreadRunner.kt
Normal 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 ThreadRunner.kt
|
||||
* LastUpdate 2026-02-05 11:20:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.thread
|
||||
|
||||
import com.mingliqiye.utils.netty.NamedThreadFactory
|
||||
import com.mingliqiye.utils.system.availableProcessors
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.Future
|
||||
|
||||
/**
|
||||
* 线程执行器工具类,用于管理线程池并提供异步任务执行功能
|
||||
*/
|
||||
object ThreadRunner {
|
||||
|
||||
var executorService: ExecutorService? = null
|
||||
|
||||
/**
|
||||
* 关闭线程池执行器
|
||||
* 首先尝试正常关闭,如果失败则强制关闭
|
||||
*/
|
||||
@JvmStatic
|
||||
fun close() {
|
||||
try {
|
||||
executorService?.shutdown()
|
||||
} catch (_: Exception) {
|
||||
executorService?.shutdownNow()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化线程池执行器
|
||||
* 创建固定大小的线程池,线程数量为可用处理器核心数的两倍
|
||||
*
|
||||
* @param string 线程名称前缀,默认为"MingliUtilThread"
|
||||
*/
|
||||
@JvmStatic
|
||||
fun init(string: String = "MingliUtilThread") {
|
||||
executorService = Executors.newFixedThreadPool(
|
||||
availableProcessors * 2,
|
||||
NamedThreadFactory { clazz, poolNumber, threadNumber ->
|
||||
"$string #$threadNumber"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行Runnable任务
|
||||
*
|
||||
* @param runnable 要执行的Runnable任务
|
||||
* @return Future对象,可用于获取任务执行结果或控制任务状态
|
||||
*/
|
||||
@JvmStatic
|
||||
fun runThread(runnable: Runnable): Future<*> {
|
||||
return executorService!!.submit(runnable)
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行Callable任务
|
||||
*
|
||||
* @param runnable 要执行的Callable任务
|
||||
* @return Future对象,可用于获取任务执行结果或控制任务状态
|
||||
*/
|
||||
@JvmStatic
|
||||
fun <T> runThread(runnable: Callable<T>): Future<T> {
|
||||
return executorService!!.submit(runnable)
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步执行Runnable任务,阻塞等待任务完成
|
||||
*
|
||||
* @param runnable 要执行的Runnable任务
|
||||
* @return 任务执行结果(通常为null)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun runThreadAwait(runnable: Runnable): Any {
|
||||
return executorService!!.submit(runnable).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步执行Callable任务,阻塞等待任务完成并返回结果
|
||||
*
|
||||
* @param runnable 要执行的Callable任务
|
||||
* @return 任务执行结果
|
||||
*/
|
||||
@JvmStatic
|
||||
fun <T> runThreadAwait(runnable: Callable<T>): T {
|
||||
return executorService!!.submit(runnable).get()
|
||||
}
|
||||
}
|
||||
43
src/main/kotlin/com/mingliqiye/utils/thread/ThreadUtils.kt
Normal file
43
src/main/kotlin/com/mingliqiye/utils/thread/ThreadUtils.kt
Normal 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 ThreadUtils.kt
|
||||
* LastUpdate 2026-01-31 20:48:19
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.thread
|
||||
|
||||
/**
|
||||
* 线程工具类,提供线程名称的获取和设置功能
|
||||
*/
|
||||
object ThreadUtils {
|
||||
/**
|
||||
* 获取或设置当前线程的名称
|
||||
*
|
||||
* Getter: 返回当前线程的名称
|
||||
* Setter: 设置当前线程的名称
|
||||
*
|
||||
* @return 当前线程的名称字符串
|
||||
*/
|
||||
@JvmStatic
|
||||
var name: String
|
||||
get() = Thread.currentThread().name
|
||||
set(s) {
|
||||
Thread.currentThread().name = s
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile DateTime.kt
|
||||
* LastUpdate 2025-09-17 19:06:39
|
||||
* LastUpdate 2026-02-04 21:54:04
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -26,7 +26,7 @@ import com.mingliqiye.utils.jna.FILETIME_EPOCH_OFFSET
|
||||
import com.mingliqiye.utils.jna.NANOS_PER_100NS
|
||||
import com.mingliqiye.utils.jna.WinKernel32Api
|
||||
import com.mingliqiye.utils.jna.getWinKernel32Apis
|
||||
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||
import com.mingliqiye.utils.logger.MingLiLoggerFactory
|
||||
import com.mingliqiye.utils.system.isWindows
|
||||
import com.mingliqiye.utils.system.javaVersionAsInteger
|
||||
import org.slf4j.Logger
|
||||
@ -40,131 +40,6 @@ import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.Instant
|
||||
|
||||
|
||||
/**
|
||||
* 时间位移 类
|
||||
*
|
||||
* @author MingLiPro
|
||||
*/
|
||||
class DateTimeOffset private constructor(
|
||||
val offsetType: ChronoUnit, val offset: Long
|
||||
) {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 创建一个新的DateTimeOffset实例
|
||||
*
|
||||
* @param offsetType 偏移量的单位类型,指定偏移量的计算单位
|
||||
* @param offset 偏移量的数值,可以为正数、负数或零
|
||||
* @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(offsetType: ChronoUnit, offset: Long): DateTimeOffset {
|
||||
return DateTimeOffset(offsetType, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 DateTimeOffset 实例
|
||||
*
|
||||
* @param offset 偏移量数值
|
||||
* @param offsetType 偏移量的时间单位类型
|
||||
* @return 返回一个新的 DateTimeOffset 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(offset: Long, offsetType: ChronoUnit): DateTimeOffset {
|
||||
return DateTimeOffset(offsetType, offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 时间格式化枚举类
|
||||
*
|
||||
*
|
||||
* 定义了常用的时间格式化模式,用于日期时间的解析和格式化操作
|
||||
* 每个枚举常量包含对应的格式化字符串和字符串长度
|
||||
*
|
||||
*/
|
||||
enum class Formatter(private val value: String) {
|
||||
/**
|
||||
* 标准日期时间格式:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"),
|
||||
STANDARD_DATETIME_MILLISECOUND8("yyyy-MM-dd HH:mm:ss.SSSSSSSS"),
|
||||
STANDARD_DATETIME_MILLISECOUND9("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"),
|
||||
|
||||
/**
|
||||
* 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
|
||||
*/
|
||||
STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
|
||||
|
||||
/**
|
||||
* 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"),
|
||||
|
||||
/**
|
||||
* 标准日期格式:yyyy-MM-dd
|
||||
*/
|
||||
STANDARD_DATE("yyyy-MM-dd"),
|
||||
|
||||
/**
|
||||
* ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSS'000'
|
||||
*/
|
||||
ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"),
|
||||
|
||||
/**
|
||||
* 紧凑型日期时间格式:yyyyMMddHHmmss
|
||||
*/
|
||||
COMPACT_DATETIME("yyyyMMddHHmmss");
|
||||
|
||||
|
||||
private val len: Int = value.length
|
||||
|
||||
fun getLen(): Int {
|
||||
return this.len
|
||||
}
|
||||
|
||||
fun getValue(): String {
|
||||
return this.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间类,用于处理日期时间的转换、格式化等操作。
|
||||
* 提供了多种静态方法来创建 DateTime 实例,并支持与 Date、LocalDateTime 等类型的互转。
|
||||
@ -186,7 +61,7 @@ class DateTime private constructor(
|
||||
|
||||
companion object {
|
||||
private val WIN_KERNEL_32_API: WinKernel32Api? = if (javaVersionAsInteger == 8 && isWindows) {
|
||||
val log: Logger = mingLiLoggerFactory.getLogger("mingli-utils DateTime")
|
||||
val log: Logger = MingLiLoggerFactory.getLogger("mingli-utils DateTime")
|
||||
val a = getWinKernel32Apis()
|
||||
|
||||
if (a.size > 1) {
|
||||
@ -284,11 +159,10 @@ class DateTime private constructor(
|
||||
timestr: String
|
||||
): DateTime {
|
||||
|
||||
val formatterString = Formatter.STANDARD_DATETIME_MILLISECOUND9.getValue()
|
||||
val formatterString = Formatter.STANDARD_DATETIME_MILLISECOUND9.value
|
||||
return DateTime(
|
||||
LocalDateTime.parse(
|
||||
getFillZeroByLen(timestr, formatterString),
|
||||
DateTimeFormatter.ofPattern(formatterString)
|
||||
getFillZeroByLen(timestr, formatterString), DateTimeFormatter.ofPattern(formatterString)
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -305,7 +179,7 @@ class DateTime private constructor(
|
||||
fun parse(
|
||||
timestr: String, formatter: Formatter, fillZero: Boolean
|
||||
): DateTime {
|
||||
return parse(timestr, formatter.getValue(), fillZero)
|
||||
return parse(timestr, formatter.value, fillZero)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -317,7 +191,7 @@ class DateTime private constructor(
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parse(timestr: String, formatter: Formatter): DateTime {
|
||||
return parse(timestr, formatter.getValue())
|
||||
return parse(timestr, formatter.value)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,23 +214,24 @@ class DateTime private constructor(
|
||||
* @return 补零后的时间字符串
|
||||
*/
|
||||
private fun getFillZeroByLen(dstr: String, formats: String): String {
|
||||
if (dstr.length == formats.length) {
|
||||
val formatslen = formats.replace("'", "").length
|
||||
if (dstr.length == formatslen) {
|
||||
return dstr
|
||||
}
|
||||
if (formats.length > dstr.length) {
|
||||
if (formatslen > dstr.length) {
|
||||
var modifiedDstr = dstr
|
||||
if (dstr.length == 19) {
|
||||
modifiedDstr += "."
|
||||
}
|
||||
val sb = StringBuilder(modifiedDstr)
|
||||
for (i in 0 until formats.length - sb.length) {
|
||||
for (i in 0 until formatslen - sb.length) {
|
||||
sb.append("0")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
throw IllegalArgumentException(
|
||||
String.format(
|
||||
"Text: '%s' len %s < %s %s", dstr, dstr.length, formats, formats.length
|
||||
"Text: '%s' len %s < %s %s", dstr, dstr.length, formats, formatslen
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -520,6 +395,20 @@ class DateTime private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载加法运算符,将指定的DateTimeOffset添加到当前DateTime对象
|
||||
* @param dateTimeOffset 要添加的时间偏移量
|
||||
* @return 返回相加后的新DateTime对象
|
||||
*/
|
||||
operator fun plus(dateTimeOffset: DateTimeOffset): DateTime = add(dateTimeOffset)
|
||||
|
||||
/**
|
||||
* 重载减法运算符,从当前DateTime对象中减去指定的DateTimeOffset
|
||||
* @param dateTimeOffset 要减去的时间偏移量
|
||||
* @return 返回相减后的新DateTime对象
|
||||
*/
|
||||
operator fun minus(dateTimeOffset: DateTimeOffset): DateTime = sub(dateTimeOffset)
|
||||
|
||||
/**
|
||||
* 在当前时间基础上减少指定的时间偏移量。
|
||||
*
|
||||
@ -547,11 +436,11 @@ class DateTime private constructor(
|
||||
* @return 返回格式化后的时间字符串
|
||||
*/
|
||||
fun format(formatter: Formatter): String {
|
||||
return format(formatter.getValue())
|
||||
return format(formatter.value)
|
||||
}
|
||||
|
||||
fun format(): String {
|
||||
return format(Formatter.STANDARD_DATETIME_MILLISECOUND9.getValue(), true)
|
||||
return format(Formatter.STANDARD_DATETIME_MILLISECOUND9.value, true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -581,7 +470,7 @@ class DateTime private constructor(
|
||||
* @return 返回格式化后的时间字符串
|
||||
*/
|
||||
fun format(formatter: Formatter, repcZero: Boolean): String {
|
||||
return format(formatter.getValue(), repcZero)
|
||||
return format(formatter.value, repcZero)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -668,7 +557,6 @@ class DateTime private constructor(
|
||||
*/
|
||||
fun toNanoTime(): Long {
|
||||
val instant = toInstant()
|
||||
|
||||
return try {
|
||||
val secondsInNanos = Math.multiplyExact(instant.epochSecond, 1_000_000_000L)
|
||||
Math.addExact(secondsInNanos, instant.nano.toLong())
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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-04 22:14:47
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.time
|
||||
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class DateTimeJsonFormat(
|
||||
val value: Formatter = Formatter.NONE,
|
||||
val formatter: String = "",
|
||||
val repcZero: Boolean = true,
|
||||
)
|
||||
61
src/main/kotlin/com/mingliqiye/utils/time/DateTimeOffset.kt
Normal file
61
src/main/kotlin/com/mingliqiye/utils/time/DateTimeOffset.kt
Normal 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 DateTimeOffset.kt
|
||||
* LastUpdate 2026-02-04 21:54:04
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.time
|
||||
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
/**
|
||||
* 时间位移 类
|
||||
*
|
||||
* @author MingLiPro
|
||||
*/
|
||||
class DateTimeOffset private constructor(
|
||||
val offsetType: ChronoUnit, val offset: Long
|
||||
) {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 创建一个新的DateTimeOffset实例
|
||||
*
|
||||
* @param offsetType 偏移量的单位类型,指定偏移量的计算单位
|
||||
* @param offset 偏移量的数值,可以为正数、负数或零
|
||||
* @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(offsetType: ChronoUnit, offset: Long): DateTimeOffset {
|
||||
return DateTimeOffset(offsetType, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 DateTimeOffset 实例
|
||||
*
|
||||
* @param offset 偏移量数值
|
||||
* @param offsetType 偏移量的时间单位类型
|
||||
* @return 返回一个新的 DateTimeOffset 实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(offset: Long, offsetType: ChronoUnit): DateTimeOffset {
|
||||
return DateTimeOffset(offsetType, offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/main/kotlin/com/mingliqiye/utils/time/Formatter.kt
Normal file
108
src/main/kotlin/com/mingliqiye/utils/time/Formatter.kt
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Formatter.kt
|
||||
* LastUpdate 2026-02-04 21:54:36
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.time
|
||||
|
||||
/**
|
||||
* 时间格式化枚举类
|
||||
*
|
||||
*
|
||||
* 定义了常用的时间格式化模式,用于日期时间的解析和格式化操作
|
||||
* 每个枚举常量包含对应的格式化字符串和字符串长度
|
||||
*
|
||||
*/
|
||||
enum class Formatter(val value: String) {
|
||||
/**
|
||||
* 标准日期时间格式:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"),
|
||||
NONE(""),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"),
|
||||
STANDARD_DATETIME_MILLISECOUND8("yyyy-MM-dd HH:mm:ss.SSSSSSSS"),
|
||||
STANDARD_DATETIME_MILLISECOUND9("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"),
|
||||
|
||||
/**
|
||||
* 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S
|
||||
*/
|
||||
STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"),
|
||||
|
||||
/**
|
||||
* 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
|
||||
*/
|
||||
STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
|
||||
|
||||
/**
|
||||
* 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"),
|
||||
|
||||
/**
|
||||
* 标准日期格式:yyyy-MM-dd
|
||||
*/
|
||||
STANDARD_DATE("yyyy-MM-dd"),
|
||||
|
||||
/**
|
||||
* ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSSSSS
|
||||
*/
|
||||
ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSSSSS"),
|
||||
|
||||
/**
|
||||
* 紧凑型日期时间格式:yyyyMMddHHmmss
|
||||
*/
|
||||
COMPACT_DATETIME("yyyyMMddHHmmss");
|
||||
|
||||
|
||||
private val len: Int = value.replace("'", "").length
|
||||
|
||||
fun getLen(): Int {
|
||||
return this.len
|
||||
}
|
||||
}
|
||||
@ -16,16 +16,14 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile UUID.kt
|
||||
* LastUpdate 2026-01-08 13:21:00
|
||||
* LastUpdate 2026-02-05 11:20:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.uuid
|
||||
|
||||
import com.mingliqiye.utils.base.BASE256
|
||||
import com.mingliqiye.utils.base.BASE64
|
||||
import com.mingliqiye.utils.base.BASE91
|
||||
import com.mingliqiye.utils.random.randomByteSecure
|
||||
import com.mingliqiye.utils.base.*
|
||||
import com.mingliqiye.utils.random.randomByte
|
||||
import com.mingliqiye.utils.random.secureRandom
|
||||
import com.mingliqiye.utils.system.macAddressBytes
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
@ -109,7 +107,7 @@ class UUID : Serializable {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getV4(): UUID {
|
||||
val randomBytes = randomByteSecure(16)
|
||||
val randomBytes = randomByte(16)
|
||||
randomBytes[6] = (randomBytes[6].toInt() and 0x0F).toByte()
|
||||
randomBytes[6] = (randomBytes[6].toInt() or 0x40).toByte()
|
||||
randomBytes[8] = (randomBytes[8].toInt() and 0x3F).toByte()
|
||||
@ -192,7 +190,7 @@ class UUID : Serializable {
|
||||
val buffer = ByteBuffer.allocate(16)
|
||||
buffer.putInt((instant shr 16).toInt())
|
||||
buffer.putShort((instant).toShort())
|
||||
buffer.put(randomByteSecure(2))
|
||||
buffer.put(randomByte(2))
|
||||
buffer.putLong(secureRandom.nextLong())
|
||||
val bytes = buffer.array()
|
||||
bytes[6] = (bytes[6].toInt() and 0x0F or 0x70).toByte()
|
||||
@ -363,6 +361,10 @@ class UUID : Serializable {
|
||||
return result
|
||||
}
|
||||
|
||||
fun of(str: String, base: BaseType): UUID {
|
||||
return UUID(base.baseCodec.decode(str))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -485,6 +487,18 @@ class UUID : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
fun getString(uuidFormatType: UUIDFormatType): String {
|
||||
return getString(isUpper = uuidFormatType.isUpper, isnotSpace = uuidFormatType.isnotSpace)
|
||||
}
|
||||
|
||||
fun getString(baseType: BaseType): String {
|
||||
return getString(baseType.baseCodec)
|
||||
}
|
||||
|
||||
fun getString(baseCodec: BaseCodec): String {
|
||||
return baseCodec.encode(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回标准格式的 UUID 字符串(带连字符)。
|
||||
*
|
||||
|
||||
30
src/main/kotlin/com/mingliqiye/utils/uuid/UUIDFormatType.kt
Normal file
30
src/main/kotlin/com/mingliqiye/utils/uuid/UUIDFormatType.kt
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile UUIDFormatType.kt
|
||||
* LastUpdate 2026-02-04 21:54:04
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.uuid
|
||||
|
||||
enum class UUIDFormatType(val isUpper: Boolean, val isnotSpace: Boolean) {
|
||||
UPPER_SPACE(true, false),
|
||||
NO_UPPER_SPACE(false, false),
|
||||
NO_UPPER_NO_SPACE(false, true),
|
||||
UPPER_NO_SPACE(true, true),
|
||||
}
|
||||
31
src/main/kotlin/com/mingliqiye/utils/uuid/UUIDJsonFormat.kt
Normal file
31
src/main/kotlin/com/mingliqiye/utils/uuid/UUIDJsonFormat.kt
Normal 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 UUIDJsonFormat.kt
|
||||
* LastUpdate 2026-02-04 22:14:47
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.uuid
|
||||
|
||||
import com.mingliqiye.utils.base.BaseType
|
||||
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class UUIDJsonFormat(
|
||||
val value: UUIDFormatType = UUIDFormatType.NO_UPPER_SPACE,
|
||||
val base: BaseType = BaseType.BASE16
|
||||
)
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright 2025 mingliqiye
|
||||
# Copyright 2026 mingliqiye
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,10 +16,9 @@
|
||||
# ProjectName mingli-utils
|
||||
# ModuleName mingli-utils.main
|
||||
# CurrentFile org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
||||
# LastUpdate 2025-09-15 22:32:50
|
||||
# LastUpdate 2026-02-04 16:47:27
|
||||
# UpdateUser MingLiPro
|
||||
#
|
||||
|
||||
com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
||||
com.mingliqiye.utils.springboot.autoconfigure.JacksonAutoConfiguration
|
||||
com.mingliqiye.utils.springboot.autoconfigure.GsonAutoConfiguration
|
||||
|
||||
82
src/test/kotlin/com/mingliqiye/utils/JsonTest.kt
Normal file
82
src/test/kotlin/com/mingliqiye/utils/JsonTest.kt
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.test
|
||||
* CurrentFile JsonTest.kt
|
||||
* LastUpdate 2026-02-05 10:57:18
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils
|
||||
|
||||
import com.mingliqiye.utils.base.BaseType
|
||||
import com.mingliqiye.utils.io.IO.println
|
||||
import com.mingliqiye.utils.json.api.JSONA
|
||||
import com.mingliqiye.utils.json.api.JacksonJsonApi
|
||||
import com.mingliqiye.utils.json.converters.DateTimeJsonConverter
|
||||
import com.mingliqiye.utils.json.converters.UUIDJsonConverter
|
||||
import com.mingliqiye.utils.string.formatd
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
import com.mingliqiye.utils.time.DateTimeJsonFormat
|
||||
import com.mingliqiye.utils.time.Formatter
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import com.mingliqiye.utils.uuid.UUIDFormatType
|
||||
import com.mingliqiye.utils.uuid.UUIDJsonFormat
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
||||
class JsonTest {
|
||||
@Test
|
||||
fun testJSONA() {
|
||||
|
||||
JSONA.setJsonApi(
|
||||
JacksonJsonApi(
|
||||
JSONA.jacksonKotlinObjectMapper()
|
||||
)
|
||||
)
|
||||
JSONA.addJsonConverter<UUIDJsonConverter>()
|
||||
JSONA.addJsonConverter<DateTimeJsonConverter>()
|
||||
|
||||
"{} {} {} {}".formatd("0", 1).println()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBANNER() {
|
||||
com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration.printBanner()
|
||||
}
|
||||
}
|
||||
|
||||
data class AC<T>(
|
||||
var a: String = "AC",
|
||||
@field:DateTimeJsonFormat(Formatter.ISO8601, repcZero = false)
|
||||
var time: DateTime = DateTime.now(),
|
||||
@field:UUIDJsonFormat(
|
||||
base = BaseType.BASE256,
|
||||
value = UUIDFormatType.UPPER_NO_SPACE
|
||||
)
|
||||
var uuid: UUID = UUID.getV4(),
|
||||
var b: T
|
||||
)
|
||||
|
||||
data class BC<T>(
|
||||
var a: String = "BC",
|
||||
var b: T
|
||||
)
|
||||
|
||||
data class CC<T>(
|
||||
var a: String = "BC",
|
||||
var b: T
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user