You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何让配置获取函数直接返回对应类型无需手动转换?

问题描述

现有JPA实体类AppSetting和枚举AppSettingType,用于存储不同类型的应用配置:

@Entity
@Table(name = "table_app_settings")
data class AppSetting(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "app_setting_id")
    val id: Long? = null,

    @Column(name = "app_setting_name")
    val name: String = "",

    @Column(name = "app_setting_value")
    var value: String = "",

    @Column(name = "app_setting_type")
    val type: AppSettingType,
)

enum class AppSettingType {
    CHAR,
    STRING,
    BYTE,
    SHORT,
    INT,
    LONG,
    DOUBLE,
    FLOAT,
    BOOLEAN,
}

当前实现的getAppSetting方法返回DatabaseResult<Any?>,调用时需要手动执行.toString().toInt()这类转换才能拿到目标类型(比如获取barcode_value时)。希望优化方法,让它直接返回指定类型,无需手动转换。

解决方案

核心思路是实现泛型版本的getAppSetting方法,结合AppSettingType做类型校验与自动转换,同时处理类型不匹配的异常场景:

1. 给枚举添加类型映射

先给AppSettingType扩展一个属性,关联对应的Kotlin类型,方便后续校验:

val AppSettingType.targetClass: KClass<*>
    get() = when(this) {
        AppSettingType.CHAR -> Char::class
        AppSettingType.STRING -> String::class
        AppSettingType.BYTE -> Byte::class
        AppSettingType.SHORT -> Short::class
        AppSettingType.INT -> Int::class
        AppSettingType.LONG -> Long::class
        AppSettingType.DOUBLE -> Double::class
        AppSettingType.FLOAT -> Float::class
        AppSettingType.BOOLEAN -> Boolean::class
    }

2. 实现泛型版getAppSetting

使用reified关键字获取泛型类型,复用原有转换逻辑并添加类型校验:

inline fun <reified T> getAppSetting(name: String): DatabaseResult<T> {
    log.info("Getting App Setting $name as type ${T::class.simpleName}")
    val appSetting = appSettingsRepository.findAppSettingByName(name)

    return if (appSetting != null) {
        log.info("App Setting $name found with ID ${appSetting.id}")
        // 校验请求类型与存储类型是否匹配
        if (appSetting.type.targetClass != T::class) {
            log.error("Mismatched type: $name is stored as ${appSetting.type}, requested ${T::class.simpleName}")
            return DatabaseResult(code = ResultCode.TYPE_MISMATCH_FAILURE)
        }

        // 执行类型转换
        val convertedValue = when(appSetting.type) {
            AppSettingType.CHAR -> appSetting.value.first() as T
            AppSettingType.STRING -> appSetting.value as T
            AppSettingType.BYTE -> appSetting.value.toByte() as T
            AppSettingType.SHORT -> appSetting.value.toShort() as T
            AppSettingType.INT -> appSetting.value.toInt() as T
            AppSettingType.LONG -> appSetting.value.toLong() as T
            AppSettingType.DOUBLE -> appSetting.value.toDouble() as T
            AppSettingType.FLOAT -> appSetting.value.toFloat() as T
            AppSettingType.BOOLEAN -> appSetting.value.toBoolean() as T
        }

        DatabaseResult(code = ResultCode.FETCH_SUCCESS, entity = convertedValue)
    } else {
        log.error("App Setting $name does not exist in database")
        DatabaseResult(code = ResultCode.FETCH_FAILURE)
    }
}

3. 简化调用方式

现在可以直接指定泛型类型调用,无需手动转换:

// 直接获取Int类型的配置
val barcodeResult = getAppSetting<Int>("barcode_value")
// 取出实体,类型为Int?
val newBarcode = barcodeResult.entity

4. 可选:优化保存方法

同样可以实现泛型版的保存方法,自动匹配AppSettingType:

inline fun <reified T> saveAppSetting(name: String, value: T): DatabaseResult<T> {
    val settingType = when(T::class) {
        Char::class -> AppSettingType.CHAR
        String::class -> AppSettingType.STRING
        Byte::class -> AppSettingType.BYTE
        Short::class -> AppSettingType.SHORT
        Int::class -> AppSettingType.INT
        Long::class -> AppSettingType.LONG
        Double::class -> AppSettingType.DOUBLE
        Float::class -> AppSettingType.FLOAT
        Boolean::class -> AppSettingType.BOOLEAN
        else -> throw IllegalArgumentException("Unsupported type: ${T::class.simpleName}")
    }

    val appSetting = AppSetting(
        name = name,
        value = value.toString(),
        type = settingType
    )

    val saveResult = saveAppSetting(appSetting)
    return if (saveResult.code != ResultCode.CREATION_FAILURE) {
        DatabaseResult(code = saveResult.code, entity = value)
    } else {
        DatabaseResult(code = ResultCode.CREATION_FAILURE)
    }
}

调用保存方法时也无需手动指定类型:

// 自动识别Int类型并保存
saveAppSetting("barcode_value", 177)

补充说明

  • reified泛型允许在方法内部获取实际的类型信息,无需额外传递类型参数
  • 类型校验可以提前发现类型不匹配的问题,避免运行时转换异常
  • 可以根据业务需求扩展ResultCode,新增TYPE_MISMATCH_FAILURE来标识类型不匹配的错误场景

内容的提问来源于stack exchange,提问作者JamieRhys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:20:35