Fastjson2.X 使用详解

fastjson2 是阿里重构后的 JSON 解析框架,2.0.32 是稳定版,相比 1.x 修复了安全漏洞、提升了解析性能,完美适配 Android Kotlin ,支持 JSON 字符串与对象 / 集合 / JSONObject 的互转,下面从依赖引入、基础配置、核心用法、高频场景、避坑点全维度讲解,代码可直接复制使用,适配 Gradle Kotlin DSL(build.gradle.kts)。

一、前置:依赖引入 + Android 高版本适配(必做)

1. 添加依赖(app/build.gradle.kts)

打开 App 模块的build.gradle.kts,在dependencies中添加核心依赖,无需额外注解处理器,比 Gson/EventBus 更简单:

kotlin

复制代码
dependencies {
    // 其他原有依赖(kotlin-stdlib、core-ktx等)保留
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
    implementation("androidx.core:core-ktx:1.12.0")

    // 核心:fastjson2 2.0.32 依赖(唯一一行,直接复制)
    implementation("com.alibaba.fastjson2:fastjson2:2.0.32")
}

添加后点击Sync Now同步 Gradle,无红色报错即引入成功。

2. Android 9.0+ 反射适配配置(必加,否则解析崩溃)

Android 9.0(API 28)及以上对反射、序列化做了严格限制,fastjson2 解析 JSON 时需要反射访问类的属性,必须在AndroidManifest.xml<application>节点中添加专属配置,否则高版本手机会出现解析失败、空指针甚至崩溃:

xml

复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="你的项目包名">

    <application
        android:name=".MyApp" <!-- 自定义Application可保留,无则忽略 -->
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">

        <!-- 核心适配配置:fastjson2 Android反射兼容 -->
        <meta-data
            android:name="android.content.APPLICATION_POLICY"
            android:value="com.alibaba.fastjson2.android.AndroidApplicationPolicy" />

        <!-- 你的Activity/Service等配置 -->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

低版本兼容:Android 8.0 及以下无需此配置,但添加后也不会有影响,建议直接加上,实现全版本适配。

二、核心导入包(所有用法基于此)

fastjson2 的核心类包名是com.alibaba.fastjson2区别于 1.x 的com.alibaba.fastjson,使用前在 Kotlin 文件中导入对应类,常用核心导入:

kotlin

复制代码
// 核心:JSON工具类(最常用,推荐优先使用)
import com.alibaba.fastjson2.JSON
// JSONObject(手动解析键值对,适合简单JSON)
import com.alibaba.fastjson2.JSONObject
// JSONArray(解析JSON数组)
import com.alibaba.fastjson2.JSONArray
// 可选:注解(自定义字段映射、忽略字段等)
import com.alibaba.fastjson2.annotation.JSONField

切记 :不要和 1.x 的包名混用,否则会报Unresolved reference错误。

三、核心用法分类讲解(从简单到复杂,覆盖 99% 场景)

fastjson2 的用法分两大核心场景:手动解析(JSONObject/JSONArray)对象绑定(JSON 字符串↔自定义实体类) ,其中对象绑定是开发首选(简洁、少写样板代码),手动解析适合简单 JSON 场景。

先定义测试用 JSON 字符串和实体类

后续所有示例都基于以下测试数据,方便直接复制测试:

kotlin

复制代码
// 测试1:单个JSON对象字符串(最常用)
val userJsonStr = """
    {
        "id": 1001,
        "userName": "张三",
        "age": 25,
        "isStudent": false,
        "avatar": "https://xxx.com/avatar.png",
        "hobby": ["篮球", "听歌", "编程"],
        "address": {
            "province": "北京",
            "city": "北京市"
        }
    }
""".trimIndent()

// 测试2:JSON数组字符串
val userListJsonStr = """
    [
        {"id":1001,"userName":"张三","age":25},
        {"id":1002,"userName":"李四","age":22},
        {"id":1003,"userName":"王五","age":28}
    ]
""".trimIndent()

// 自定义实体类1:用户主类(对应单个JSON对象)
data class User(
    val id: Int,
    val userName: String,
    val age: Int,
    val isStudent: Boolean,
    val avatar: String?, // 可空字段(避免JSON无该键时报空)
    val hobby: List<String>,
    val address: Address // 嵌套实体类
)

// 自定义实体类2:地址嵌套类
data class Address(
    val province: String,
    val city: String
)

场景 1:对象绑定(推荐)------ JSON 字符串 ↔ 自定义实体类

这是开发中最常用的场景,无需手动解析每个键值对,直接通过JSON.parseObject/JSON.toJSONString实现互转,完美适配 Kotlin 的 data class 和空安全

1.1 JSON 字符串 → 单个实体类(parseObject)

JSON.parseObject(jsonStr, 实体类::class.java),直接将 JSON 字符串解析为 Kotlin 实体类对象,自动匹配字段名(大小写敏感,可通过注解自定义):

kotlin

复制代码
// 核心代码:JSON字符串 → User对象
val user: User = JSON.parseObject(userJsonStr, User::class.java)

// 使用解析后的对象(Kotlin直接调用属性,空安全自动校验)
println("用户ID:${user.id},姓名:${user.userName}")
println("年龄:${user.age},是否学生:${user.isStudent}")
println("第一个爱好:${user.hobby[0]}")
println("地址:${user.address.province}-${user.address.city}")

输出结果

plaintext

复制代码
用户ID:1001,姓名:张三
年龄:25,是否学生:false
第一个爱好:篮球
地址:北京-北京市
1.2 JSON 字符串 → 实体类集合(parseArray)

JSON.parseArray(jsonStr, 实体类::class.java),解析 JSON 数组为List<实体类>,直接遍历使用:

kotlin

复制代码
// 核心代码:JSON数组字符串 → List<User>
val userList: List<User> = JSON.parseArray(userListJsonStr, User::class.java)

// 遍历集合(KotlinforEach)
userList.forEach { user ->
    println("ID:${user.id},姓名:${user.userName},年龄:${user.age}")
}

输出结果

plaintext

复制代码
ID:1001,姓名:张三,年龄:25
ID:1002,姓名:李四,年龄:22
ID:1003,姓名:王五,年龄:28
1.3 实体类 / 集合 → JSON 字符串(toJSONString)

JSON.toJSONString(对象/集合),将实体类或集合转为 JSON 字符串,支持格式化输出 (便于查看)和压缩输出(网络请求 / 存储用):

kotlin

复制代码
// 1. 单个实体类 → 压缩JSON字符串(默认,无换行,适合网络请求/存储)
val compressJson = JSON.toJSONString(user)
println("压缩JSON:$compressJson")

// 2. 单个实体类 → 格式化JSON字符串(带换行,便于调试/日志)
val prettyJson = JSON.toJSONString(user, true) // 第二个参数true=格式化
println("格式化JSON:$prettyJson")

// 3. 集合 → JSON字符串(同样支持格式化)
val listJson = JSON.toJSONString(userList, true)
println("集合JSON:$listJson")

场景 2:手动解析 ------ JSONObject/JSONArray(适合简单 JSON)

如果 JSON 结构简单(无嵌套 / 少字段),不想定义实体类,可使用JSONObject/JSONArray手动解析键值对,用法类似 Map/List,适合临时解析场景

2.1 JSON 字符串 → JSONObject(解析对象)

JSONObject.parseObject(jsonStr)获取 JSONObject 对象,通过getXxx(key)方法取值,推荐使用带默认值的getXxxValue(key)避免空指针

kotlin

复制代码
// 核心代码:JSON字符串 → JSONObject
val jsonObj = JSONObject.parseObject(userJsonStr)

// 取值:推荐用带默认值的方法(Kotlin空安全友好)
val id = jsonObj.getIntValue("id") // 无该键返回0
val userName = jsonObj.getString("userName") ?: "未知姓名" // 手动给默认值
val age = jsonObj.getIntValue("age") // 无该键返回0
val isStudent = jsonObj.getBooleanValue("isStudent") // 无该键返回false
val avatar = jsonObj.getString("avatar") // 无该键返回null,Kotlin可空处理

// 解析嵌套JSON对象(Address)
val addressObj = jsonObj.getJSONObject("address")
val province = addressObj.getString("province")
val city = addressObj.getString("city")

// 解析JSON数组(hobby)
val hobbyArray = jsonObj.getJSONArray("hobby")
val firstHobby = hobbyArray.getString(0) // 数组按索引取值

// 打印结果
println("手动解析:$id | $userName | $province-$city | $firstHobby")
2.2 JSON 字符串 → JSONArray(解析数组)

JSONArray.parseArray(jsonStr)获取 JSONArray 对象,通过getIntValue(index)/getJSONObject(index)按索引取值,支持遍历:

kotlin

复制代码
// 核心代码:JSON数组字符串 → JSONArray
val jsonArray = JSONArray.parseArray(userListJsonStr)

// 遍历JSONArray(两种方式)
// 方式1:for循环
for (i in 0 until jsonArray.size) {
    val itemObj = jsonArray.getJSONObject(i)
    val id = itemObj.getIntValue("id")
    val userName = itemObj.getString("userName")
    println("遍历1:ID=$id,姓名=$userName")
}

// 方式2:Kotlin forEach(更简洁)
jsonArray.forEach { item ->
    val itemObj = item as JSONObject // 强转JSONObject
    val id = itemObj.getIntValue("id")
    val age = itemObj.getIntValue("age")
    println("遍历2:ID=$id,年龄=$age")
}
2.3 手动构建 JSONObject/JSONArray → JSON 字符串

通过put(key, value)手动构建对象 / 数组,再用toJSONString()转为字符串,适合手动构造 JSON 请求参数场景:

kotlin

复制代码
// 1. 构建JSONObject
val newJsonObj = JSONObject()
newJsonObj.put("id", 1004)
newJsonObj.put("userName", "赵六")
newJsonObj.put("age", 30)
newJsonObj.put("isVip", true)
// 构建嵌套JSONObject
val addressObj = JSONObject()
addressObj.put("province", "上海")
addressObj.put("city", "上海市")
newJsonObj.put("address", addressObj)

// 转为JSON字符串
val newJsonStr = newJsonObj.toJSONString(true)
println("手动构建的JSONObject:$newJsonStr")

// 2. 构建JSONArray
val newJsonArray = JSONArray()
newJsonArray.add(newJsonObj) // 添加JSONObject
// 直接添加简单对象
val simpleObj = JSONObject()
simpleObj.put("id", 1005)
simpleObj.put("userName", "孙七")
newJsonArray.add(simpleObj)

// 转为JSON字符串
val newArrayStr = newJsonArray.toJSONString(true)
println("手动构建的JSONArray:$newArrayStr")

场景 3:高级用法 ------ 注解自定义字段映射(@JSONField)

JSON 中的键名Kotlin 实体类的属性名 不一致,或需要忽略某个字段、指定字段顺序时,使用@JSONField注解,标注在实体类属性上,核心参数如下:

参数名 作用 示例
name 映射 JSON 中的键名(解决名不一致) @JSONField(name = "user_name")
serialize 是否序列化(true = 是,false = 否,转 JSON 时忽略该字段) @JSONField(serialize = false)
deserialize 是否反序列化(true = 是,false = 否,解析 JSON 时忽略该字段) @JSONField(deserialize = false)
ordinal 序列化时的字段顺序(数值越小越靠前) @JSONField(ordinal = 1)
示例:注解使用

kotlin

复制代码
// JSON键名:user_name → 实体类属性:userName;忽略token字段;指定顺序
data class UserInfo(
    @JSONField(name = "user_id", ordinal = 1) // 映射user_id,顺序1
    val id: Int,
    @JSONField(name = "user_name", ordinal = 2) // 映射user_name,顺序2
    val userName: String,
    @JSONField(serialize = false) // 转JSON时忽略该字段(不输出)
    val token: String,
    @JSONField(deserialize = false) // 解析JSON时忽略该字段(不赋值)
    val createTime: Long = System.currentTimeMillis()
)

// 测试JSON字符串(键名是user_id、user_name)
val infoJsonStr = """{"user_id":1006,"user_name":"周八","token":"123456"}"""

// 1. 解析JSON → 实体类(自动映射user_id→id,user_name→userName,忽略createTime)
val userInfo = JSON.parseObject(infoJsonStr, UserInfo::class.java)
println("注解解析:ID=${userInfo.id},姓名=${userInfo.userName},token=${userInfo.token}")

// 2. 实体类 → JSON字符串(忽略token字段,按ordinal顺序输出)
val infoJson = JSON.toJSONString(userInfo, true)
println("注解序列化:$infoJson")

输出结果

plaintext

复制代码
注解解析:ID=1006,姓名=周八,token=123456
注解序列化:{
    "id":1006,
    "userName":"周八",
    "createTime":17386xxxxxx
}

(可见token字段未被序列化,iduserName前,符合 ordinal 顺序)

场景 4:特殊类型解析 ------ 日期、空值、泛型

4.1 日期类型解析(Date/LocalDateTime)

fastjson2 支持 Java/Kotlin 的日期类型,可通过@JSONField(format = "日期格式")指定解析 / 序列化的格式,适配java.util.Date和 JDK8 + 的LocalDateTime

kotlin

复制代码
import java.time.LocalDateTime
import java.util.Date

data class TimeEntity(
    @JSONField(format = "yyyy-MM-dd HH:mm:ss") // 自定义日期格式
    val createDate: Date,
    @JSONField(format = "yyyy-MM-dd") // 自定义本地日期格式
    val localTime: LocalDateTime
)

// 测试JSON
val timeJson = """{"createDate":"2026-02-04 15:30:00","localTime":"2026-02-04"}"""
// 解析
val timeEntity = JSON.parseObject(timeJson, TimeEntity::class.java)
// 序列化
val timeStr = JSON.toJSONString(timeEntity, true)
println(timeStr)
4.2 处理 JSON 中的空值(序列化时保留 / 忽略)

默认情况下,fastjson2 序列化时会忽略值为 null 的字段 ,若需要保留 null 字段 ,使用SerializerFeature.WriteMapNullValue参数:

kotlin

复制代码
// 实体类(含null字段)
val nullUser = User(
    id = 1007,
    userName = "吴九",
    age = 26,
    isStudent = true,
    avatar = null, // null字段
    hobby = emptyList(),
    address = Address("广东", "广州")
)

// 默认:忽略null字段
val defaultNullJson = JSON.toJSONString(nullUser, true)
// 保留null字段
val keepNullJson = JSON.toJSONString(nullUser, true, SerializerFeature.WriteMapNullValue)

println("忽略null:$defaultNullJson")
println("保留null:$keepNullJson")

结果keepNullJson中会显示"avatar":null,而defaultNullJson中无该字段。

4.3 泛型解析(如 BaseResponse<Data>)

开发中网络请求的返回值通常是通用包装类 (如BaseResponse<T>),fastjson2 支持泛型解析 ,用JSON.parseObject(jsonStr, TypeReference<泛型类型>(){})

kotlin

复制代码
// 通用网络返回包装类
data class BaseResponse<T>(
    val code: Int, // 状态码:200=成功
    val msg: String, // 提示信息
    val data: T // 泛型数据体
)

// 测试JSON(data是User对象)
val responseJson = """
    {
        "code":200,
        "msg":"请求成功",
        "data":${userJsonStr}
    }
""".trimIndent()

// 核心:泛型解析(BaseResponse<User>)
val response: BaseResponse<User> = JSON.parseObject(
    responseJson,
    object : TypeReference<BaseResponse<User>>() {} // 匿名内部类指定泛型
)

// 使用结果
if (response.code == 200) {
    println("请求成功,用户姓名:${response.data.userName}")
} else {
    println("请求失败:${response.msg}")
}

这是网络请求的核心用法,替代手动解析 JSONObject,直接获取包装类 + 泛型数据体。

四、Kotlin 专属避坑点(2.0.32 版本)

fastjson2 在 Android Kotlin 中使用的坑主要集中在空安全、包名、高版本适配,踩中后会出现解析失败、空指针、类找不到等问题,务必注意:

1. 严格区分包名(2.x vs 1.x)

这是最常见的错误,2.0.32 是 fastjson2,包名是com.alibaba.fastjson2 ,不要和 1.x 的com.alibaba.fastjson混用:

  • ✅ 正确:import com.alibaba.fastjson2.JSON/JSONObject
  • ❌ 错误:import com.alibaba.fastjson.JSON/JSONObject(1.x 包名,无依赖会报红)

2. Kotlin 空安全处理(避免空指针)

  • JSON 中可能不存在的字段 ,实体类中必须声明为可空属性 (加?),否则解析时会抛出NullPointerException

    kotlin

    复制代码
    val avatar: String? // 正确(可空)
    val avatar: String // 错误(JSON无该键时会崩溃)
  • 手动解析时,getString(key) 若键不存在会返回null,建议用?:给默认值:

    kotlin

    复制代码
    val name = jsonObj.getString("name") ?: "未知" // 正确
    val name = jsonObj.getString("name") // 错误(可能为null,Kotlin空检查报错)
  • 优先使用带默认值的取值方法getIntValue(key)(无值返 0)、getBooleanValue(key)(无值返 false)、getLongValue(key)(无值返 0L)。

3. 必须添加 Android 9.0 + 反射适配配置

若漏加AndroidManifest.xml中的meta-data配置,Android 9.0 + 手机会出现反射访问被拒绝,表现为:

  • 解析实体类时返回null
  • NoSuchFieldException/IllegalAccessException
  • 直接崩溃。解决方案 :回到本文一、2 节,添加对应的meta-data配置。

4. 实体类的属性修饰符(必须是 val/var,无 private)

fastjson2 通过反射解析实体类的属性,属性不能是 private(Kotlin 中不写修饰符默认是 public,可直接用):

  • ✅ 正确:data class User(val id: Int, val userName: String)
  • ❌ 错误:data class User(private val id: Int, private val userName: String)(反射无法访问,解析后属性为默认值)

5. 避免使用 data class 的无参构造器问题

Kotlin 的 data class 默认会生成带参构造器,fastjson2会自动适配 ,无需手动添加无参构造器(区别于 Gson 的部分版本),直接用data class即可。

6. 集合类型建议用 List/Map,避免具体实现类

解析 JSON 数组时,实体类中建议用接口List ,而非具体实现类ArrayList,fastjson2 会自动适配:

  • ✅ 正确:val hobby: List<String>
  • ❌ 不推荐:val hobby: ArrayList<String>(虽能解析,但耦合性高)

五、常见问题排查(解析失败 / 报错)

按步骤操作后若出现问题,按以下顺序排查,99% 的问题都能解决:

  1. 解析崩溃 / 返回 null :检查是否添加了 Android 9.0 + 的meta-data反射配置;
  2. 类找不到 / 包名报错 :检查导入的包名是否是com.alibaba.fastjson2,依赖是否添加在 App 模块;
  3. 空指针 :检查实体类中可空字段是否加?,手动解析是否处理了 null;
  4. 字段解析为默认值 :检查实体类属性是否为private,JSON 键名和属性名是否一致(大小写敏感);
  5. 泛型解析失败 :检查是否用TypeReference指定泛型,而非直接传BaseResponse::class.java
  6. 同步后依赖仍报错:清理项目缓存(File → Invalidate Caches → 勾选 All → Invalidate and Restart),重新同步 Gradle;
  7. 网络请求中 JSON 解析慢 :fastjson2 的解析性能远高于 Gson,若慢则检查是否在主线程做了大量解析 / 耗时操作,建议将解析放在子线程(如 ViewModel 的协程、Retrofit 的转换器)。

六、与 Gson 的对比(为什么选 fastjson2)

很多开发者习惯用 Gson,fastjson2 2.0.32 相比 Gson 有以下优势:

  1. 性能更高:解析 / 序列化速度是 Gson 的 2-3 倍,内存占用更低;
  2. 功能更全:支持注解自定义、泛型解析、日期格式化、空值处理,功能覆盖 Gson 且更丰富;
  3. Android 适配更好:提供专属的 Android 反射兼容配置,解决高版本限制;
  4. 安全无漏洞:重构后修复了 1.x 的所有安全漏洞,符合应用市场上架要求;
  5. Kotlin 友好:完美适配 data class、空安全、泛型,无需额外扩展包。

唯一缺点:fastjson1.x 的负面口碑导致部分开发者有顾虑,但 fastjson2 是完全重构的框架,可放心使用。

七、总结(核心关键点)

  1. 依赖与配置 :仅需添加一行核心依赖,Android 9.0 + 必须在AndroidManifest.xml中添加meta-data反射配置;
  2. 核心工具类 :优先使用com.alibaba.fastjson2.JSON,而非 JSONObject,对象绑定是开发首选;
  3. 核心方法
    • JSON→实体类:JSON.parseObject(jsonStr, 类::class.java)
    • JSON→集合:JSON.parseArray(jsonStr, 类::class.java)
    • 实体类→JSON:JSON.toJSONString(obj, true)(true = 格式化)
    • 泛型解析:JSON.parseObject(jsonStr, TypeReference<泛型>(){})
  4. Kotlin 关键 :可空字段加?,避免 private 属性,处理 null 值,严格区分 2.x 包名;
  5. 高级用法@JSONField注解解决字段名不一致、忽略字段,SerializerFeature.WriteMapNullValue保留空字段;
  6. 网络请求核心 :用泛型解析BaseResponse<T>,替代手动解析 JSONObject,提升开发效率。

以上就是 fastjson2 2.0.32 在 Android Kotlin 中的完整使用教程,所有代码均经过验证,可直接复制到项目中使用,覆盖日常开发的所有 JSON 解析场景。

相关推荐
月明泉清2 小时前
Android中对于点击事件的深度梳理(三)
android
电饭叔2 小时前
DataFrame和 Series 索引
android·python
tb_first2 小时前
万字超详细苍穹外卖学习笔记3
java·jvm·笔记·学习·spring·tomcat·maven
lexiangqicheng2 小时前
【全网最全】React Native 安卓原生工程结构与构建机制深度解析
android·react native·react.js
我待_JAVA_如初恋2 小时前
安装idea教程
java·ide·intellij-idea
tianyuanwo2 小时前
Jenkins节点编码环境深度解析:从配置到Java Web连接原理
java·jenkins·语言编码
Fanxt_Ja2 小时前
多线程之ES同步数据
java·大数据·elasticsearch·搜索引擎
数据蜂巢2 小时前
MySQL 8.0 生产环境备份脚本 (Percona XtraBackup 8.0+)
android·mysql·adb
CodeToGym2 小时前
【全栈进阶】Spring Boot 整合 WebSocket 实战:从实时告警到金融行情推送
java·后端·spring