Kotlinx序列化多平台兼容性详解

kotlinx.serialization 是 Kotlin 官方的多平台序列化库,设计时充分考虑了 Kotlin Multiplatform(KMP)的兼容性。以下是其多平台兼容性的关键特性和注意事项:


1. 核心多平台支持

  • 跨平台序列化逻辑 :在 commonMain 中定义可序列化的数据类和序列化/反序列化逻辑,可在所有目标平台(JVM、JS、Native)共享。
  • 统一注解@Serializable@SerialName 等注解在公共代码中直接使用。
  • 格式支持kotlinx-serialization-jsonkotlinx-serialization-cbor 等核心格式均支持多平台。

2. 平台特定实现

不同平台的序列化行为由库自动处理,但需注意:

  • JVM :最稳定,支持反射(如 PolymorphicSerializer),但推荐显式注册序列化模块以避免性能问题。
  • Kotlin/JS :行为与 JVM 基本一致,但需注意:
    • 日期格式:JS 的 Date 与 Java 不同,建议统一使用 kotlinx-datetime 处理日期。
  • Kotlin/Native
    • 无反射 :Native 平台禁用反射,必须显式注册多态子类(如 Json { serializersModule = myModule })。
    • 并发限制 :序列化器初始化需在单线程(如 @SharedImmutable)完成。
    • 资源访问:读取文件需使用平台特定代码(如 iOS 的 NSBundle)。

3. 多平台配置最佳实践

共享数据类
kotlin 复制代码
// commonMain/kotlin
import kotlinx.serialization.Serializable

@Serializable
data class Project(val id: Int, val name: String, val isPublic: Boolean)
序列化模块注册(Native 关键!)
kotlin 复制代码
// commonMain/kotlin
import kotlinx.serialization.modules.*

val myModule = SerializersModule {
    polymorphic(Project::class) {
        subclass(PrivateProject::class) // 显式注册多态子类
    }
}

// 在 Native 等平台使用模块
val json = Json { serializersModule = myModule }
平台差异处理(expect/actual)
kotlin 复制代码
// commonMain/kotlin
expect fun readConfigFile(): String

// androidMain/kotlin
actual fun readConfigFile() = File("config.json").readText()

// iosMain/kotlin
actual fun readConfigFile(): String {
    val path = NSBundle.mainBundle.pathForResource("config", "json") 
    return NSString(contentsOfFile = path!!, encoding = NSUTF8StringEncoding) as String
}

4. 常见问题与解决

问题 1:Native 平台反序列化失败
  • 原因:未注册多态子类或使用了反射。

  • 解决 :显式注册所有子类:

    kotlin 复制代码
    Json {
        serializersModule = SerializersModule {
            polymorphic(Shape::class) {
                subclass(Circle::class)
                subclass(Rectangle::class)
            }
        }
    }
问题 2:日期格式不一致
  • 解决 :统一使用 Instant(推荐 kotlinx-datetime):

    kotlin 复制代码
    @Serializable
    data class Event(
        @Serializable(with = InstantSerializer::class)
        val time: Instant
    )
问题 3:JS 平台 Long 类型溢出
  • 解决 :在 JSON 配置中使用字符串表示 Long:

    kotlin 复制代码
    Json { explicitNulls = false; useAlternativeNames = true }

5. 构建配置要点

build.gradle.kts 中确保:

kotlin 复制代码
kotlin {
    jvm()
    js(IR) { browser() }
    iosX64()

    sourceSets {
        commonMain {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
            }
        }
    }
}

总结

  • 优势kotlinx.serialization 在 KMP 中实现了高度代码共享,核心逻辑可完全写在 commonMain
  • 注意
    • Native 平台:禁用反射,必须显式注册多态类型。
    • 日期/长整型 :使用跨平台库(如 kotlinx-datetime)或统一配置。
    • 资源访问 :通过 expect/actual 实现平台差异化。
  • 推荐:始终使用最新版本(如 1.6.0+)以获得最佳多平台支持。

通过遵循显式注册、避免反射和统一数据表示,可高效实现全平台一致的序列化逻辑。

相关推荐
草莓熊Lotso5 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
大模型玩家七七5 小时前
基于语义切分 vs 基于结构切分的实际差异
java·开发语言·数据库·安全·batch
恋猫de小郭5 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
寻星探路10 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
工程师老罗12 小时前
如何在Android工程中配置NDK版本
android
曹牧13 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
爬山算法13 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty72514 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎14 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven