1. 概述

本文将介绍几种在 Kotlin 中处理 JSON 字段多个名称的方法。所谓“多个名称”,通常是指字段在不同版本的接口或不同系统中使用了不同的命名方式,我们需要在反序列化时兼容这些不同名称。

这在实际开发中很常见,比如:

  • 接口升级后字段名变更,但旧字段仍保留以保证兼容性
  • 集成第三方系统时,其字段命名风格与我们不一致

通过合理处理这些字段名,可以让我们的数据类更清晰、统一,也更容易维护。

2. 为什么要处理 JSON 字段名

2.1 接口版本兼容

接口在迭代过程中可能会修改字段名,例如从 userId 改为 id,但为了兼容旧客户端,老字段依然存在。这时我们需要在数据类中兼容新旧字段名。

✅ 举个例子:

// 旧数据
{ "userId": "123" }

// 新数据
{ "id": "123" }

如果我们只定义一个 val id: String 的字段,就需要反序列化器能识别两种字段名。

2.2 第三方接口命名风格不一致

当我们对接多个第三方系统时,它们可能使用了不同的命名风格(如 snake_case、camelCase、PascalCase),我们希望统一字段名,避免数据类中出现各种奇怪的命名。

3. 使用 @JsonNames 注解

@JsonNames 是 kotlinx.serialization 提供的注解,允许我们为一个字段指定多个 JSON 名称。

✅ 示例:

@Serializable
data class User(
    @JsonNames("uid")
    val id: String
)

这段代码表示:

  • 该字段在 JSON 中可以是 iduid
  • 反序列化时,无论遇到哪个名称,都会映射到 id 属性

🧪 测试代码:

fun handleJsonWithJsonNames() {
    val json = """{"uid":"1"}"""
    val user = Json.decodeFromString<User>(json)
    assertEquals(user.id) // Output: 1
}

⚠️ 注意:@JsonNames 只适用于 kotlinx-serialization-json 模块,不适用于其他序列化框架。

4. 使用 @SerialName 注解

@SerialName 是更通用的注解,适用于所有使用 kotlinx.serialization 的场景,不仅限于 JSON。

✅ 示例:

@Serializable
data class Car(
    @SerialName("which_model")
    val model: String
)

这段代码表示:

  • 该字段在 JSON 中可以是 modelwhich_model
  • 反序列化时,两者都会映射到 model 属性

🧪 测试代码:

fun handleJsonNamesWithSerialName() {
    val carJson = """{"which_model":"Altima"}"""
    val car = Json.decodeFromString<Car>(carJson)
    assertEquals(car.model) // Output: Altima
}

✅ 优点:

  • 通用性强,适用于非 JSON 的序列化方式
  • @Serializable 配合良好

❌ 缺点:

  • 不支持多个别名(只能指定一个替代名)

5. 小结

本文介绍了两种在 Kotlin 中处理 JSON 字段多个名称的方法:

方法 支持多别名 适用范围 示例注解
@JsonNames ✅ 是 仅 JSON @JsonNames("uid")
@SerialName ❌ 否 所有 kotlinx.serialization 场景 @SerialName("which_model")

✅ 推荐使用场景:

  • 如果只处理 JSON,推荐使用 @JsonNames,更灵活
  • 如果使用了其他序列化方式(如 ProtoBuf、CBOR),建议使用 @SerialName

完整示例代码可参考 GitHub 项目


原始标题:Handling Multiple Names for JSON Field in Kotlin