Skip to content

Commit 086f015

Browse files
committed
feat(posts): 新增序列化对比文章
1 parent b29af67 commit 086f015

1 file changed

Lines changed: 348 additions & 0 deletions

File tree

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
---
2+
categories: Android
3+
title: Kotlinx-serialization vs Gson vs Moshi:现代JSON序列化框架的抉择
4+
tags:
5+
- 序列化
6+
- gson
7+
- moshi
8+
- Kotlinx-serialization
9+
toc: true
10+
toc_sticky: true
11+
excerpt: Kotlinx-serialization、Gson和Moshi分别代表了不同设计哲学下的解决方案,本文将深入剖析它们的异同与适用场景。
12+
---
13+
14+
Kotlinx-serialization、Gson和Moshi分别代表了不同设计哲学下的解决方案,本文将深入剖析它们的异同与适用场景。
15+
16+
## 第一章:Gson——Java时代的经典之作
17+
18+
### 1.1 诞生背景与设计理念
19+
20+
Gson由Google在2008年推出,是Java生态系统中最古老、应用最广泛的JSON库之一。其设计哲学是"简单至上":
21+
22+
```java
23+
// 典型的Gson使用方式
24+
Gson gson = new Gson();
25+
User user = new User("Alice", 30);
26+
27+
// 序列化
28+
String json = gson.toJson(user);
29+
// 输出: {"name":"Alice","age":30}
30+
31+
// 反序列化
32+
User userFromJson = gson.fromJson(json, User.class);
33+
```
34+
35+
### 1.2 核心特性
36+
- **零配置基础使用**:默认情况下无需注解即可工作
37+
- **类型擦除绕过**:通过TypeToken处理泛型
38+
39+
```java
40+
// 处理泛型列表
41+
Type listType = new TypeToken<List<User>>(){}.getType();
42+
List<User> users = gson.fromJson(jsonArray, listType);
43+
```
44+
45+
- **灵活的适配器系统**:可自定义序列化逻辑
46+
- **强大的日期格式化支持**
47+
48+
### 1.3 Kotlin中的局限性
49+
50+
```kotlin
51+
data class User(val name: String, val age: Int)
52+
53+
// Gson可能破坏Kotlin的特性
54+
val user = User(null, 30) // 编译错误:name不可为空
55+
56+
// 但Gson通过反射创建对象时可能绕过空安全检查
57+
val json = """{"age":30}""" // name字段缺失
58+
val user = gson.fromJson(json, User::class.java)
59+
// user.name实际为null,违反了Kotlin非空约束!
60+
```
61+
62+
## 第二章:Moshi——Square公司的现代响应
63+
64+
### 2.1 针对Gson痛点的改进
65+
66+
Moshi由Square公司开发,继承了Gson的简洁性,同时解决了其核心问题:
67+
68+
```kotlin
69+
// Moshi的基本使用
70+
val moshi = Moshi.Builder().build()
71+
val jsonAdapter = moshi.adapter(User::class.java)
72+
73+
val user = User("Alice", 30)
74+
val json = jsonAdapter.toJson(user)
75+
76+
// 明确的空安全处理
77+
val incompleteJson = """{"age":30}"""
78+
val user = jsonAdapter.fromJson(incompleteJson)
79+
// 可能抛出JsonDataException或返回null
80+
```
81+
82+
### 2.2 核心改进点
83+
84+
- **Kotlin友好**:原生支持Kotlin特性
85+
- **更好的空安全**:显式处理空值
86+
- **性能优化**:代码生成选项减少反射使用
87+
- **模块化设计**:更容易扩展
88+
89+
### 2.3 代码生成模式
90+
91+
```kotlin
92+
@JsonClass(generateAdapter = true)
93+
data class User(
94+
val name: String,
95+
val age: Int,
96+
@Json(name = "created_at") val createdAt: Date?
97+
)
98+
99+
// 编译时生成适配器,提高性能
100+
val moshi = Moshi.Builder()
101+
.add(KotlinJsonAdapterFactory()) // 支持Kotlin特性
102+
.build()
103+
```
104+
105+
## 第三章:Kotlinx-serialization——原生的Kotlin解决方案
106+
107+
### 3.1 Kotlin-first的设计哲学
108+
109+
Kotlinx-serialization是JetBrains官方提供的序列化框架,完全围绕Kotlin语言特性构建:
110+
111+
```kotlin
112+
import kotlinx.serialization.*
113+
import kotlinx.serialization.json.*
114+
115+
@Serializable
116+
data class User(
117+
val name: String,
118+
val age: Int,
119+
@SerialName("created_at") val createdAt: Long? = null
120+
)
121+
122+
fun main() {
123+
val user = User("Alice", 30, System.currentTimeMillis())
124+
125+
// 序列化
126+
val json = Json.encodeToString(user)
127+
// 输出: {"name":"Alice","age":30,"created_at":1633024000000}
128+
129+
// 反序列化
130+
val decodedUser = Json.decodeFromString<User>(json)
131+
}
132+
```
133+
134+
### 3.2 核心特性亮点
135+
136+
#### 3.2.1 多格式支持
137+
138+
```kotlin
139+
// 不仅仅是JSON
140+
@Serializable
141+
data class Project(val name: String, val stars: Int)
142+
143+
fun main() {
144+
val project = Project("kotlinx.serialization", 1000)
145+
146+
// JSON
147+
val json = Json.encodeToString(project)
148+
149+
// CBOR (简洁的二进制格式)
150+
val cbor = Cbor.encodeToByteArray(project)
151+
152+
// Protobuf
153+
val protoBuf = ProtoBuf.encodeToByteArray(project)
154+
155+
// 属性列表
156+
val properties = Properties.encodeToStringMap(project)
157+
}
158+
```
159+
160+
#### 3.2.2 编译时安全
161+
162+
```kotlin
163+
// 编译时类型检查
164+
@Serializable
165+
data class User(
166+
val name: String,
167+
val age: Int,
168+
val email: String? = null // 可选字段
169+
)
170+
171+
// 缺失必填字段会在编译时或运行时明确报错
172+
val invalidJson = """{"name":"Alice"}"""
173+
// Json.decodeFromString<User>(invalidJson)
174+
// 抛出: SerializationException: Field 'age' is required
175+
```
176+
177+
#### 3.2.3 密封类和多态序列化
178+
179+
```kotlin
180+
@Serializable
181+
sealed class Response
182+
183+
@Serializable
184+
@SerialName("success")
185+
data class Success(val data: String) : Response()
186+
187+
@Serializable
188+
@SerialName("error")
189+
data class Error(val message: String) : Response()
190+
191+
fun main() {
192+
val responses = listOf<Response>(
193+
Success("Data loaded"),
194+
Error("Network failure")
195+
)
196+
197+
val json = Json.encodeToString(responses)
198+
// 输出: [{"type":"success","data":"Data loaded"},{"type":"error","message":"Network failure"}]
199+
}
200+
```
201+
202+
## 第四章:三大框架全方位对比
203+
204+
### 4.1 技术架构对比
205+
206+
| 特性维度 | Gson | Moshi | Kotlinx-serialization |
207+
| :------------- | :----------------- | :--------------------- | :---------------------- |
208+
| **设计理念** | Java优先,反射驱动 | Gson改进版,Kotlin友好 | Kotlin原生,多平台 |
209+
| **序列化方式** | 运行时反射 | 反射或代码生成 | 编译时生成 |
210+
| **Kotlin支持** | 需要适配器 | 良好,需要工厂 | 完美,语言级集成 |
211+
| **空安全** || 良好 | 优秀 |
212+
| **默认值支持** | 有限 | 良好 | 优秀 |
213+
| **多平台** | JVM为主 | JVM为主 | 全平台(JVM/JS/Native) |
214+
| **依赖大小** | ~240KB | ~270KB | ~800KB(含多格式) |
215+
216+
### 4.2 性能基准对比(相对值)
217+
218+
**序列化速度**:Kotlinx-serialization (代码生成) > Moshi (代码生成) > Moshi (反射) > Gson
219+
{: .notice--info}
220+
221+
**反序列化速度**:Moshi (代码生成) ≈ Kotlinx-serialization > Moshi (反射) > Gson
222+
{: .notice--info}
223+
224+
**内存使用**:Kotlinx-serialization < Moshi < Gson
225+
{: .notice--info}
226+
227+
**启动性能**:Kotlinx-serialization > Moshi (代码生成) > Gson> Moshi (反射)
228+
{: .notice--info}
229+
230+
## 第五章:实战场景选择指南
231+
232+
### 5.1 新项目技术选型决策树
233+
234+
<div class="notice">
235+
<h4>项目类型 → Kotlin使用程度 → 平台需求 → 推荐方案</h4>
236+
<p>├── 纯Kotlin新项目 → 全平台 → kotlinx-serialization</p>
237+
<p>├── 纯Kotlin新项目 → Android/JVM → Moshi或kotlinx-serialization</p>
238+
<p>├── Java项目 → 少量Kotlin → Gson或Moshi</p>
239+
<p>└── 混合/遗留项目 → 逐步迁移 → 根据模块选择</p>
240+
</div>
241+
242+
## 第六章:高级特性深度解析
243+
244+
### 6.1 kotlinx-serialization的上下文序列化
245+
246+
```kotlin
247+
// 处理无法添加@Serializable注解的类
248+
object DateSerializer : KSerializer<Date> {
249+
override val descriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)
250+
251+
override fun serialize(encoder: Encoder, value: Date) {
252+
encoder.encodeString(value.toString())
253+
}
254+
255+
override fun deserialize(decoder: Decoder): Date {
256+
return SimpleDateFormat("yyyy-MM-dd").parse(decoder.decodeString())
257+
}
258+
}
259+
260+
@Serializable
261+
data class Event(val name: String, val date: @Contextual Date)
262+
263+
fun main() {
264+
val json = Json { serializersModule = SerializersModule {
265+
contextual(Date::class, DateSerializer)
266+
}}
267+
268+
json.encodeToString(Event("name", Date()))
269+
// {"name":"name","date":"Tue Dec 16 14:07:15 GMT+08:00 2025"}
270+
271+
val string = """
272+
{"name":"name","date":"2025-12-16"}
273+
""".trimIndent()
274+
json.decodeFromString<Event>(string)
275+
// Event(name=name, date=Tue Dec 16 00:00:00 GMT+08:00 2025)
276+
}
277+
```
278+
279+
### 6.2 Moshi的Kotlin代码生成器
280+
```kotlin
281+
// 使用注解处理器提升性能
282+
@JsonClass(generateAdapter = true)
283+
data class User(val name: String, val age: Int)
284+
285+
// 生成的代码(简化版)
286+
class UserJsonAdapter(moshi: Moshi) : JsonAdapter<User>() {
287+
private val stringAdapter = moshi.nextAdapter<String>(...)
288+
private val intAdapter = moshi.nextAdapter<Int>(...)
289+
290+
override fun fromJson(reader: JsonReader): User {
291+
var name: String? = null
292+
var age: Int? = null
293+
reader.beginObject()
294+
while (reader.hasNext()) {
295+
when (reader.nextName()) {
296+
"name" -> name = stringAdapter.fromJson(reader)
297+
"age" -> age = intAdapter.fromJson(reader)
298+
}
299+
}
300+
reader.endObject()
301+
return User(name!!, age!!)
302+
}
303+
}
304+
```
305+
306+
### 6.3 Gson的TypeAdapterFactory高级用法
307+
```java
308+
// 自定义复杂类型的处理
309+
public class AnimalAdapterFactory implements TypeAdapterFactory {
310+
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
311+
if (!Animal.class.isAssignableFrom(type.getRawType())) {
312+
return null;
313+
}
314+
315+
return (TypeAdapter<T>) new TypeAdapter<Animal>() {
316+
public void write(JsonWriter out, Animal value) {
317+
// 自定义序列化逻辑
318+
}
319+
320+
public Animal read(JsonReader in) {
321+
// 自定义反序列化逻辑
322+
}
323+
};
324+
}
325+
}
326+
```
327+
328+
## 第七章:选择建议
329+
### 7.1 Kotlinx-serialization
330+
- 纯Kotlin项目
331+
- 需要多格式序列化
332+
- 追求最佳性能和类型安全
333+
- 使用Kotlin协程或Compose
334+
335+
### 7.2 Moshi
336+
- 需要与Java代码互操作
337+
- 团队熟悉Square生态
338+
- 需要高度可定制的序列化逻辑
339+
340+
### 7.3 Gson
341+
- 旧项目维护
342+
- 快速原型验证
343+
- 对性能要求不高
344+
- 团队Java背景为主
345+
346+
**总结:**无论选择哪个框架,关键是根据项目需求、团队技能和长期维护计划做出理性决策。技术选型没有绝对的对错,只有适合与否。在序列化这个看似简单但实则复杂的问题上,正确的工具选择可以显著提升开发效率和系统稳定性。
347+
{: .notice--success}
348+

0 commit comments

Comments
 (0)