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字段未被序列化,id在userName前,符合 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% 的问题都能解决:
- 解析崩溃 / 返回 null :检查是否添加了 Android 9.0 + 的
meta-data反射配置; - 类找不到 / 包名报错 :检查导入的包名是否是
com.alibaba.fastjson2,依赖是否添加在 App 模块; - 空指针 :检查实体类中可空字段是否加
?,手动解析是否处理了 null; - 字段解析为默认值 :检查实体类属性是否为
private,JSON 键名和属性名是否一致(大小写敏感); - 泛型解析失败 :检查是否用
TypeReference指定泛型,而非直接传BaseResponse::class.java; - 同步后依赖仍报错:清理项目缓存(File → Invalidate Caches → 勾选 All → Invalidate and Restart),重新同步 Gradle;
- 网络请求中 JSON 解析慢 :fastjson2 的解析性能远高于 Gson,若慢则检查是否在主线程做了大量解析 / 耗时操作,建议将解析放在子线程(如 ViewModel 的协程、Retrofit 的转换器)。
六、与 Gson 的对比(为什么选 fastjson2)
很多开发者习惯用 Gson,fastjson2 2.0.32 相比 Gson 有以下优势:
- 性能更高:解析 / 序列化速度是 Gson 的 2-3 倍,内存占用更低;
- 功能更全:支持注解自定义、泛型解析、日期格式化、空值处理,功能覆盖 Gson 且更丰富;
- Android 适配更好:提供专属的 Android 反射兼容配置,解决高版本限制;
- 安全无漏洞:重构后修复了 1.x 的所有安全漏洞,符合应用市场上架要求;
- Kotlin 友好:完美适配 data class、空安全、泛型,无需额外扩展包。
唯一缺点:fastjson1.x 的负面口碑导致部分开发者有顾虑,但 fastjson2 是完全重构的框架,可放心使用。
七、总结(核心关键点)
- 依赖与配置 :仅需添加一行核心依赖,Android 9.0 + 必须在
AndroidManifest.xml中添加meta-data反射配置; - 核心工具类 :优先使用
com.alibaba.fastjson2.JSON,而非 JSONObject,对象绑定是开发首选; - 核心方法 :
- JSON→实体类:
JSON.parseObject(jsonStr, 类::class.java) - JSON→集合:
JSON.parseArray(jsonStr, 类::class.java) - 实体类→JSON:
JSON.toJSONString(obj, true)(true = 格式化) - 泛型解析:
JSON.parseObject(jsonStr, TypeReference<泛型>(){})
- JSON→实体类:
- Kotlin 关键 :可空字段加
?,避免 private 属性,处理 null 值,严格区分 2.x 包名; - 高级用法 :
@JSONField注解解决字段名不一致、忽略字段,SerializerFeature.WriteMapNullValue保留空字段; - 网络请求核心 :用泛型解析
BaseResponse<T>,替代手动解析 JSONObject,提升开发效率。
以上就是 fastjson2 2.0.32 在 Android Kotlin 中的完整使用教程,所有代码均经过验证,可直接复制到项目中使用,覆盖日常开发的所有 JSON 解析场景。