Kotlin JSON库使用

本文针对 Kotlin 项目中常用的 JSON 库的一些 API 使用进行一个基本介绍

kotlinx.serialization

Kotlin Serialization (https://github.com/Kotlin/kotlinx.serialization) 是 Kotlin 自带的处理序列化与反序列化的库,目前支持的格式有如下几种:

  • JSON:kotlinx-serialization-json
  • Protocol Buffers:kotlinx-serialization-protobuf
  • CBOR:kotlinx-serialization-cbor
  • Properties:kotlinx-serialization-properties
  • HOCON:kotlinx-serialization-hocon (only on JVM)

详细使用文档:https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md

项目搭建

坐标引入参考:https://github.com/Kotlin/kotlinx.serialization,我这里使用Maven搭建项目,需要添加下面的maven配置:

<properties>
    <kotlin.version>2.2.0</kotlin.version>
    <serialization.version>1.9.0</serialization.version>
</properties>
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-serialization-json -->
    <dependency>
        <groupId>org.jetbrains.kotlinx</groupId>
        <artifactId>kotlinx-serialization-json</artifactId>
        <version>${serialization.version}</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-plugin</artifactId>
            <version>${kotlin.version}</version>
            <executions>
                <execution>
                    <id>compile</id>
                    <phase>compile</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <compilerPlugins>
                    <plugin>kotlinx-serialization</plugin>
                </compilerPlugins>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.jetbrains.kotlin</groupId>
                    <artifactId>kotlin-maven-serialization</artifactId>
                    <version>${kotlin.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

对象与JSON互转

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
class Project(val name: String, val language: String)

fun main() {
    // 对象转JSON
    val data = Project("kotlinx.serialization", "Kotlin")
    // JSON转对象
    val string = Json.encodeToString(data)
    println(string) // {"name":"kotlinx.serialization","language":"Kotlin"}
    val obj = Json.decodeFromString<Project>(string)
    println(obj) // Project(name=kotlinx.serialization, language=Kotlin)
}

遍历JSON树结构

import kotlinx.serialization.json.*

fun main() {
    // 1. 定义 JSON 字符串(实际开发中可来自网络/文件)
    val jsonStr = """
        {
          "name": "Kotlin Serialization",
          "version": 1.6,
          "isStable": true,
          "features": ["树形解析", "数据类序列化", "多格式支持"],
          "config": {"enableCache": true, "timeout": 3000},
          "emptyField": null
        }
    """.trimIndent()

    // 2. 解析为 JSON 树根节点(JsonElement)
    val jsonRoot: JsonElement = Json.parseToJsonElement(jsonStr)

    // 3. 强制转换为 JsonObject(因为根节点是对象,需确保类型匹配,否则抛异常)
    val jsonObject = jsonRoot.jsonObject // 安全转换:不会抛异常,返回 nullable
    // 或强制转换(风险高,类型不匹配时抛 ClassCastException):
    // val jsonObject = jsonRoot as JsonObject

    println("解析后的 JSON 对象:$jsonObject")
}

JSON转Map

参考这个SO:https://stackoverflow.com/questions/44870961/how-to-map-a-json-string-to-kotlin-map

无需任何第三方库:

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject

val input = """{
     "_id" : { "some_id" : "593440eb7fa580d99d1abe85"} , 
     "name" : "Firstname Secondname" ,
     "reg_number" : "ATC/DCM/1016/230" ,
     "oral" : 11 ,
     "oral_percent" : 73 , 
     "cat_1" : 57 , 
     "cat_2" : 60 , 
     "cat_average" : 59 , 
     "assignment" : 90
}"""

val json = Json.parseToJsonElement(input)
val map = json.jsonObject.toMap()

Gson

使用时需引入 gson 的依赖:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.13.1</version>
</dependency>

Gson 是针对 java 对象的序列化框架。基于 Kotlin 对象使用 Gson 框架,会失去 Kotlin 的一些重要特性,比如:

  • 非空类型安全。比如 Kotlin 类的属性定义为非空类型时,仍然可以将一个 null 赋值给它创建一个对象。跟预期不符
import com.google.gson.Gson

// 数据类:name 是非空字段(无 ?)
data class User(val name: String, val age: Int)

fun main() {
    // JSON 中缺失 name 字段(仅含 age) 反序列化:非空字段 name 缺失 → 崩溃
    val user = Gson().fromJson("""{"age": 25}""", User::class.java)
    println(user.name)  // null
}

解决该问题的方式就是给 name 加个?

  • 参数默认值没有效果。Kotlin 属性可以赋予默认值。但是当使用 Gson 时,将会失去效果。
import com.google.gson.Gson

// 数据类:name 是非空字段(无 ?)
data class User(val name: String = "zs", val age: Int)

fun main() {
    // JSON 中缺失 name 字段(仅含 age) 反序列化:非空字段 name 缺失 → 崩溃
    val user = Gson().fromJson("""{"age": 25}""", User::class.java)
    println(user.name)  // null
}

这种情况下 gson 在找 User 的无参构造时没有找到,最终通过UnsafeAllocator.create()直接创建对象,不会走构造函数,给的默认值自然就不生效了

解决这个问题的方式是:给每个属性都赋一个初始值,这样就会生成一个无参的构造函数了,也就不会出现这种问题了

data class User(val name: String = "zs", val age: Int = 0)

即使已经给 data class 所有属性默认值了,但是当 json 中某个属性的值显式的为 null 时,null值还是会覆盖到原本的默认值,这就是问题所在:声明的时候不能为 null,写代码的时候也没异常提示,运行就会出现NPE。

Jackson

使用时需引入 jackson 的依赖:

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.16.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-kotlin</artifactId>
        <version>2.16.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.16.1</version>
    </dependency>
</dependencies>

在 Kotlin 中使用 Jackson(核心依赖 jackson-databind + Kotlin 专用模块 jackson-module-kotlin)是比 Gson 更 “原生适配 Kotlin” 的 JSON 处理方案 —— 它能更好地支持空安全、默认值、数据类等 Kotlin 特性

关键特性(Kotlin 友好)

(1)默认值自动生效(无需额外依赖)

Jackson 原生支持 Kotlin 数据类的默认值,JSON 字段缺失时自动填充默认值(无需像 Gson 那样依赖 kotlin-reflect):

// JSON 缺失 age 字段(默认值 0)
val json = """{"name": "王五"}"""
val user = objectMapper.readValue(json, User::class.java)
println(user.age) // 输出:0(默认值生效)

(2)空安全适配

  • 可空字段(String?)接收 null 或缺失字段时,不会崩溃,直接赋值 null
  • 非空字段(String)若 JSON 传递 null,会抛出明确异常(InvalidFormatException),而非静默破坏空安全(Gson 2.10+ 存在的问题)。

其他的使用方法就和 java 中的差不多了,主要针对 kotlin 中的使用做说明

posted @ 2025-11-14 21:23  vonlinee  阅读(9)  评论(0)    收藏  举报