generated from mingliqiye/lib-tem
- 更新多个工具类的最后修改时间和用户信息 - 移除冗余的 main 函数测试代码 - 优化 ByteUtils 中流处理方法的引用- 为 Collection 扩展大量实用函数,包括转换、获取元素和创建集合实例等 - 引入 SuperStream 替代部分自定义流处理逻辑 - 调整 Spring Boot 自动配置包扫描路径- 修复资源读取时的空指针风险,使用 Kotlin 的 elvis 操作符简化代码
274 lines
10 KiB
Kotlin
274 lines
10 KiB
Kotlin
/*
|
|
* 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 ConfigurationProp.kt
|
|
* LastUpdate 2025-09-19 11:30:04
|
|
* UpdateUser MingLiPro
|
|
*/
|
|
|
|
package com.mingliqiye.utils.configuration
|
|
|
|
/**
|
|
* 配置属性注解,用于标记配置类中的字段,支持通过命令行参数进行初始化。
|
|
*
|
|
* @param name 配置项的名称,默认为空字符串,表示使用字段名作为配置项名称。
|
|
* @param description 配置项的描述信息,默认为空字符串。
|
|
* @param showHelper 是否显示帮助信息,默认为 true。
|
|
*/
|
|
@Retention(AnnotationRetention.RUNTIME)
|
|
@Target(
|
|
AnnotationTarget.TYPE_PARAMETER,
|
|
AnnotationTarget.VALUE_PARAMETER,
|
|
AnnotationTarget.FIELD, // 添加字段支持
|
|
AnnotationTarget.PROPERTY // 添加属性支持
|
|
)
|
|
annotation class ConfigurationProp(val name: String = "", val description: String = "", val showHelper: Boolean = true)
|
|
|
|
/**
|
|
* 根据字段名生成对应的 setter 方法名。
|
|
*
|
|
* @param fieldName 字段名。
|
|
* @return 对应的 setter 方法名。
|
|
*/
|
|
private fun getSetterName(fieldName: String): String {
|
|
return "set" + fieldName.take(1).uppercase() + fieldName.substring(1)
|
|
}
|
|
|
|
/**
|
|
* 根据字段名生成对应的 getter 方法名。
|
|
*
|
|
* @param fieldName 字段名。
|
|
* @return 对应的 getter 方法名。
|
|
*/
|
|
private fun getGetterName(fieldName: String): String {
|
|
return "get" + fieldName.take(1).uppercase() + fieldName.substring(1)
|
|
}
|
|
|
|
/**
|
|
* 配置初始化器,用于解析命令行参数并填充配置对象。
|
|
*/
|
|
open class ConfigurationProps {
|
|
|
|
companion object {
|
|
/**
|
|
* 初始化配置类实例,并根据命令行参数填充其字段。
|
|
*
|
|
* @param clazz 配置类的 Class 对象。
|
|
* @param args 命令行参数数组。
|
|
* @return 初始化后的配置类实例。
|
|
*/
|
|
@JvmStatic
|
|
fun <T : ConfigurationProps> init(clazz: Class<T>, args: Array<String>): T {
|
|
val mapsArgs = parseArguments(args)
|
|
val instance = clazz.getDeclaredConstructor().newInstance()
|
|
|
|
processFields(clazz, instance, mapsArgs)
|
|
|
|
return instance
|
|
}
|
|
|
|
/**
|
|
* 解析命令行参数,将其转换为键值对映射。
|
|
*
|
|
* 支持以下格式:
|
|
* - `--key=value` 或 `-k=value`:键值对形式。
|
|
* - `--key value` 或 `-k value`:键和值分开的形式。
|
|
* - `--flag` 或 `-f`:布尔标志形式,默认值为 "true"。
|
|
*
|
|
* @param args 命令行参数数组。
|
|
* @return 解析后的键值对映射。
|
|
*/
|
|
private fun parseArguments(args: Array<String>): Map<String, List<String>> {
|
|
val mapsArgs = mutableMapOf<String, MutableList<String>>()
|
|
|
|
var i = 0
|
|
while (i < args.size) {
|
|
val arg = args[i]
|
|
|
|
when {
|
|
arg.startsWith("--") -> {
|
|
// 处理 --key=value 格式
|
|
if (arg.contains("=")) {
|
|
val (key, value) = arg.substring(2).split("=", limit = 2)
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add(value)
|
|
}
|
|
// 处理 --key value 格式
|
|
else if (i + 1 < args.size && !args[i + 1].startsWith("-")) {
|
|
val key = arg.substring(2)
|
|
val value = args[i + 1]
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add(value)
|
|
i++ // 跳过下一个参数
|
|
}
|
|
// 处理 --flag 格式的布尔标志
|
|
else {
|
|
val key = arg.substring(2)
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add("true")
|
|
}
|
|
}
|
|
|
|
arg.startsWith("-") -> {
|
|
// 处理 -k=value 格式
|
|
if (arg.contains("=")) {
|
|
val (key, value) = arg.substring(1).split("=", limit = 2)
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add(value)
|
|
}
|
|
// 处理 -k value 格式
|
|
else if (i + 1 < args.size && !args[i + 1].startsWith("-")) {
|
|
val key = arg.substring(1)
|
|
val value = args[i + 1]
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add(value)
|
|
i++
|
|
}
|
|
// 处理 -f 格式的布尔标志
|
|
else {
|
|
val key = arg.substring(1)
|
|
mapsArgs.getOrPut(key) { mutableListOf() }.add("true")
|
|
}
|
|
}
|
|
}
|
|
i++
|
|
}
|
|
|
|
return mapsArgs
|
|
}
|
|
|
|
/**
|
|
* 处理配置类中的字段,根据解析出的参数设置字段值。
|
|
*
|
|
* @param clazz 配置类的 Class 对象。
|
|
* @param instance 配置类的实例。
|
|
* @param mapsArgs 解析后的命令行参数映射。
|
|
*/
|
|
private fun <T : ConfigurationProps> processFields(
|
|
clazz: Class<T>,
|
|
instance: T,
|
|
mapsArgs: Map<String, List<String>>
|
|
) {
|
|
val fields = clazz.declaredFields
|
|
|
|
for (field in fields) {
|
|
val configurationProp = field.getAnnotation(ConfigurationProp::class.java)
|
|
if (configurationProp != null) {
|
|
val fieldName = configurationProp.name.ifEmpty { field.name }
|
|
val values = mapsArgs[fieldName]
|
|
|
|
if (values != null) {
|
|
try {
|
|
val setter = clazz.getDeclaredMethod(
|
|
getSetterName(field.name),
|
|
field.type
|
|
)
|
|
|
|
val value = convertValue(field.type, values, configurationProp)
|
|
setter.invoke(instance, value)
|
|
} catch (e: Exception) {
|
|
println("Warning: Failed to set field ${field.name}: ${e.message}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将字符串值转换为目标类型。
|
|
*
|
|
* @param type 目标类型。
|
|
* @param values 字符串值列表。
|
|
* @param annotation 配置属性注解。
|
|
* @return 转换后的值。
|
|
*/
|
|
private fun convertValue(
|
|
type: Class<*>,
|
|
values: List<String>,
|
|
annotation: ConfigurationProp
|
|
): Any? {
|
|
val lastValue = values.lastOrNull() ?: return null
|
|
|
|
return when (type) {
|
|
String::class.java -> lastValue
|
|
|
|
Integer::class.java, Int::class.java -> try {
|
|
lastValue.toInt()
|
|
} catch (e: NumberFormatException) {
|
|
println("Warning: Invalid integer value '$lastValue'")
|
|
null
|
|
}
|
|
|
|
Long::class.java, java.lang.Long::class.java -> try {
|
|
lastValue.toLong()
|
|
} catch (e: NumberFormatException) {
|
|
println("Warning: Invalid long value '$lastValue'")
|
|
null
|
|
}
|
|
|
|
Double::class.java, java.lang.Double::class.java -> try {
|
|
lastValue.toDouble()
|
|
} catch (e: NumberFormatException) {
|
|
println("Warning: Invalid double value '$lastValue'")
|
|
null
|
|
}
|
|
|
|
Boolean::class.java, java.lang.Boolean::class.java -> when (lastValue.lowercase()) {
|
|
"true", "1", "yes", "on" -> true
|
|
"false", "0", "no", "off" -> false
|
|
else -> {
|
|
println("Warning: Invalid boolean value '$lastValue'")
|
|
null
|
|
}
|
|
}
|
|
|
|
List::class.java -> values
|
|
|
|
else -> {
|
|
println("Warning: Unsupported type ${type.simpleName}")
|
|
null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun printHelp() {
|
|
val fields = this::class.java.declaredFields
|
|
val help = StringBuilder()
|
|
for (field in fields) {
|
|
val configurationProp = field.getAnnotation(ConfigurationProp::class.java)
|
|
if (configurationProp != null && configurationProp.showHelper) {
|
|
val fieldName = configurationProp.name.ifEmpty { field.name }
|
|
help.append("$fieldName -> 类型: ${field.type.simpleName}")
|
|
if (configurationProp.description.isNotEmpty()) {
|
|
help.append(" 描述: ${configurationProp.description}")
|
|
}
|
|
help.append("\n")
|
|
}
|
|
}
|
|
println(help)
|
|
}
|
|
|
|
val fields: Map<String, Any?>
|
|
get() {
|
|
val fields = this::class.java.declaredFields
|
|
val fieldValues = mutableMapOf<String, Any?>()
|
|
for (field in fields) {
|
|
field.isAccessible = true
|
|
val fieldName = field.name
|
|
val fieldValue = field.get(this)
|
|
fieldValues[fieldName] = fieldValue
|
|
}
|
|
return fieldValues
|
|
}
|
|
}
|