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

如何编写KSerializer反序列化可对象/字符串的YAML多语言字段?

实现支持单/多语言字符串的Kotlinx序列化器

问题场景

我需要反序列化包含单语言或多语言字符串的YAML配置,示例如下:

key1: File
# or
key2:
  en_US: File
  de_DE: Datei

使用kotlinx.serialization和KAML(为kotlinx序列化提供YAML支持),目标是将配置反序列化为以下密封接口及实现类:

@Serializable
sealed interface LingualString {
    // 实际代码使用java.util.Locale,此处简化
    operator fun get(locale: String): String
}

@Serializable
class MonolingualString(
    private val text: String
) : LingualString {
    override operator fun get(locale: String) = text
}

@Serializable
class MultilingualString(
    private val map: Map<String, String>
) : LingualString {
    override operator fun get(locale: String) = map[locale]!!
}

请问如何编写能加载这类值的KSerializer<LingualString>?


解决方案

1. 编写自定义序列化器

通过自定义KSerializer判断YAML元素类型,分别映射到MonolingualString或MultilingualString:

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.yaml.YamlDecoder
import kotlinx.serialization.yaml.YamlEncoder

object LingualStringSerializer : KSerializer<LingualString> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("LingualString")

    override fun deserialize(decoder: Decoder): LingualString {
        require(decoder is YamlDecoder) { "该序列化器仅支持YAML格式" }
        val element = decoder.decodeYamlElement()

        return when {
            element.isScalar -> {
                // 处理单语言字符串
                MonolingualString(element.content)
            }
            element.isMapping -> {
                // 处理多语言键值对映射
                val localeMap = decoder.decodeSerializableValue(
                    Map.serializer(String.serializer(), String.serializer())
                )
                MultilingualString(localeMap)
            }
            else -> throw IllegalArgumentException("不支持的YAML元素类型")
        }
    }

    override fun serialize(encoder: Encoder, value: LingualString) {
        require(encoder is YamlEncoder) { "该序列化器仅支持YAML格式" }
        when (value) {
            is MonolingualString -> encoder.encodeString(value.text)
            is MultilingualString -> encoder.encodeSerializableValue(
                Map.serializer(String.serializer(), String.serializer()),
                value.map
            )
        }
    }
}

2. 绑定序列化器到密封接口

修改LingualString接口,指定使用自定义序列化器:

@Serializable(with = LingualStringSerializer::class)
sealed interface LingualString {
    operator fun get(locale: String): String
}

3. 测试使用示例

创建包含LingualString的配置类,验证序列化/反序列化逻辑:

import kotlinx.serialization.Serializable
import com.charleskorn.kaml.Yaml

@Serializable
data class AppConfig(
    val key1: LingualString,
    val key2: LingualString
)

fun main() {
    val yamlContent = """
        key1: File
        key2:
          en_US: File
          de_DE: Datei
    """.trimIndent()

    // 反序列化
    val config = Yaml.default.decodeFromString(AppConfig.serializer(), yamlContent)
    println(config.key1.get("en_US")) // 输出: File
    println(config.key2.get("de_DE")) // 输出: Datei

    // 序列化(可选)
    val serializedYaml = Yaml.default.encodeToString(AppConfig.serializer(), config)
    println(serializedYaml)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:47:41