如何编写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
相关产品推荐
相关产品推荐

