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

如何在Kotlinx Serialization中自定义序列化器实现蛇形转驼形解析

自定义Kotlinx Serialization序列化器实现驼峰/蛇形字段名自动转换

完整实现代码

直接在数据类的伴生对象中实现自定义序列化逻辑,无需给每个字段加@SerialName注解:

import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.jsonObject

@Serializable
data class User(
    val userId: Int,
    val userName: String,
    val userEmail: String
) {
    @Serializer(forClass = User::class)
    companion object : KSerializer<User> {
        // 复用官方默认序列化器,避免重复编写字段序列化逻辑
        private val delegateSerializer = serializer<User>()

        override val descriptor: SerialDescriptor = delegateSerializer.descriptor

        override fun serialize(encoder: Encoder, value: User) {
            if (encoder is JsonEncoder) {
                // 先通过默认序列化器生成JSON,再把驼峰字段转成蛇形
                val originalJson = delegateSerializer.serialize(encoder, value)
                val transformedJson = originalJson.jsonObject.mapKeys { (key, _) ->
                    camelToSnake(key)
                }
                encoder.encodeJsonElement(transformedJson)
            } else {
                // 非JSON格式直接用默认序列化逻辑
                delegateSerializer.serialize(encoder, value)
            }
        }

        override fun deserialize(decoder: Decoder): User {
            if (decoder is JsonDecoder) {
                // 先解码蛇形命名的JSON,把字段转成驼峰后再解析
                val originalJson = decoder.decodeJsonElement().jsonObject
                val transformedJson = originalJson.mapKeys { (key, _) ->
                    snakeToCamel(key)
                }
                return decoder.json.decodeFromJsonElement(delegateSerializer, transformedJson)
            } else {
                // 非JSON格式直接用默认反序列化逻辑
                delegateSerializer.deserialize(decoder)
            }
        }

        // 驼峰转蛇形工具函数
        private fun camelToSnake(name: String): String {
            return name.replace(Regex("([a-z0-9])([A-Z])"), "$1_$2").lowercase()
        }

        // 蛇形转驼峰工具函数
        private fun snakeToCamel(name: String): String {
            return name.split("_")
                .joinToString("") { it.replaceFirstChar(Char::uppercase) }
                .replaceFirstChar(Char::lowercase)
        }
    }
}

测试验证

运行以下代码确认序列化/反序列化效果:

fun main() {
    // 后端返回的蛇形命名JSON
    val snakeCaseJson = """{"user_id": 1, "user_name": "Jerry", "user_email": "jerry@example.com"}"""

    // 反序列化:蛇形字段自动转为驼峰属性
    val user = kotlinx.serialization.json.Json.decodeFromString<User>(snakeCaseJson)
    println(user) // 输出:User(userId=1, userName=Jerry, userEmail=jerry@example.com)

    // 序列化:驼峰属性自动转为蛇形字段
    val serializedJson = kotlinx.serialization.json.Json.encodeToString(user)
    println(serializedJson) // 输出:{"user_id":1,"user_name":"Jerry","user_email":"jerry@example.com"}
}

关键逻辑说明

  1. 复用默认序列化器:通过serializer<User>()获取官方实现,只做字段名转换,避免重复编写每个字段的序列化逻辑。
  2. 字段名双向转换:
    • 序列化时,把数据类的驼峰属性名转为蛇形字段名
    • 反序列化时,把JSON的蛇形字段名转为驼峰属性名
  3. 兼容非JSON场景:判断编码器/解码器类型,非JSON格式直接使用默认逻辑,保证通用性。

注意事项

  • 若数据类包含嵌套的可序列化对象,嵌套类也需要配置相同的自定义序列化器,否则嵌套字段不会自动转换命名。
  • 多个数据类需要该逻辑时,可将camelToSnake和snakeToCamel抽离为顶层工具函数或单独工具类,避免代码重复。
  • 确保项目已引入kotlinx serialization依赖,例如Gradle配置:
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:10:13