本文全面剖析 Gson 中 TypeAdapter 的使用技巧,通过多个实战案例展示如何处理动态键、多态类型等复杂JSON结构,并提供性能优化方案。
在 JSON 解析中,我们常遇到以下痛点:
TypeAdapter 核心优势:
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
class CustomTypeAdapter : TypeAdapter<YourClass>() {
override fun write(out: JsonWriter, value: YourClass) {
// 序列化逻辑:对象 → JSON
}
override fun read(reader: JsonReader): YourClass {
// 反序列化逻辑:JSON → 对象
}
}
// 注册适配器
val gson = GsonBuilder()
.registerTypeAdapter(YourClass::class.java, CustomTypeAdapter())
.create()
JSON结构:
{
"user": "Alice",
"scores": {
"math": [90, 85, 92],
"science": [88, 95]
}
}
Kotlin数据类:
data class StudentReport(
val user: String,
val scores: Map<String, List<Int>>
)
完整TypeAdapter实现:
class ReportAdapter : TypeAdapter<StudentReport>() {
override fun write(out: JsonWriter, report: StudentReport) {
out.beginObject()
out.name("user").value(report.user)
// 处理动态键scores
out.name("scores")
out.beginObject()
report.scores.forEach { (subject, scores) ->
out.name(subject)
out.beginArray()
scores.forEach { out.value(it) }
out.endArray()
}
out.endObject()
out.endObject()
}
override fun read(reader: JsonReader): StudentReport {
var user = ""
val scores = mutableMapOf<String, List<Int>>()
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"user" -> user = reader.nextString()
"scores" -> {
reader.beginObject()
while (reader.hasNext()) {
val subject = reader.nextName()
val scoreList = mutableListOf<Int>()
reader.beginArray()
while (reader.hasNext()) {
scoreList.add(reader.nextInt())
}
reader.endArray()
scores[subject] = scoreList
}
reader.endObject()
}
else -> reader.skipValue() // 跳过未知字段
}
}
reader.endObject()
return StudentReport(user, scores)
}
}
关键技巧:
beginObject()
/endObject()
处理嵌套结构forEach
遍历动态键值对skipValue()
跳过不认识的字段保证兼容性JSON结构:
[
{ "type": "text", "content": "Hello" },
{ "type": "image", "url": "pic.jpg", "width": 800 }
]
Kotlin数据类:
sealed class Message {
abstract val type: String
}
data class TextMessage(
override val type: String = "text",
val content: String
) : Message()
data class ImageMessage(
override val type: String = "image",
val url: String,
val width: Int
) : Message()
TypeAdapterFactory 实现:
class MessageAdapterFactory : TypeAdapterFactory {
override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (!Message::class.java.isAssignableFrom(type.rawType)) {
return null
}
return object : TypeAdapter<Message>() {
override fun write(out: JsonWriter, msg: Message) {
// 根据实际类型选择序列化方式
when (msg) {
is TextMessage -> gson.getAdapter(TextMessage::class.java).write(out, msg)
is ImageMessage -> gson.getAdapter(ImageMessage::class.java).write(out, msg)
else -> throw IllegalArgumentException("Unsupported message type")
}
}
override fun read(reader: JsonReader): Message {
// 使用临时JsonObject判断类型
val json = JsonParser.parseReader(reader).asJsonObject
return when (json.get("type").asString) {
"text" -> gson.fromJson(json, TextMessage::class.java)
"image" -> gson.fromJson(json, ImageMessage::class.java)
else -> throw IllegalArgumentException("Unknown message type")
}
}
} as TypeAdapter<T>
}
}
注册方式:
val gson = GsonBuilder()
.registerTypeAdapterFactory(MessageAdapterFactory())
.create()
多态处理流程图:
JSON结构:
{
"event": "Conference",
"date": "2023-08-15T14:30:00Z"
}
Kotlin数据类:
data class Event(
val name: String,
val date: Date
)
日期TypeAdapter:
class DateAdapter : TypeAdapter<Date>() {
private val isoFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
override fun write(out: JsonWriter, date: Date) {
out.value(isoFormat.format(date))
}
override fun read(reader: JsonReader): Date {
return isoFormat.parse(reader.nextString())
?: throw JsonParseException("Invalid date format")
}
}
使用方式:
val gson = GsonBuilder()
.registerTypeAdapter(Date::class.java, DateAdapter())
.create()
特性 | 流式处理 (JsonReader/Writer) | DOM解析 (JsonObject) |
---|---|---|
内存占用 | ✅ 极低 (常量级) | ❌ 高 (整文档加载) |
处理速度 | ✅ 快 | ⚠️ 中等 |
大文件处理 | ✅ 适合 | ❌ 不适合 |
编码复杂度 | ⚠️ 较高 | ✅ 简单 |
对于复杂对象,委托子适配器处理各部分:
class OrderAdapter(private val productAdapter: TypeAdapter<Product>)
: TypeAdapter<Order>() {
override fun read(reader: JsonReader): Order {
var id = 0
var products = listOf<Product>()
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"id" -> id = reader.nextInt()
"products" -> {
products = mutableListOf<Product>().apply {
reader.beginArray()
while (reader.hasNext()) {
add(productAdapter.read(reader))
}
reader.endArray()
}
}
else -> reader.skipValue()
}
}
reader.endObject()
return Order(id, products)
}
// write方法类似实现
}
object AdapterCache {
private val adapters = ConcurrentHashMap<Class<*>, TypeAdapter<*>>()
fun <T> getAdapter(clazz: Class<T>, gson: Gson): TypeAdapter<T> {
return adapters.getOrPut(clazz) {
gson.getAdapter(clazz)
} as TypeAdapter<T>
}
}
// 使用缓存适配器
val productAdapter = AdapterCache.getAdapter(Product::class.java, gson)
GsonBuilder()
.registerTypeAdapter(MyClass::class.java, MyAdapter())
.registerTypeAdapterFactory(MyFactory())
.create()
try {
// 解析操作
} catch (e: JsonParseException) {
// 处理格式错误
} catch (e: IOException) {
// 处理IO异常
}
JsonReader/JsonWriter
避免内存溢出skipValue()
跳过未知字段peek()
返回的token类型when (reader.peek()) {
JsonToken.NULL -> {
reader.nextNull()
// 处理null值
}
// 其他类型处理...
}
特性 | TypeAdapter | JsonDeserializer |
---|---|---|
处理机制 | 流式API | DOM树解析 |
性能 | ✅ 高 | ⚠️ 中等 |
内存占用 | ✅ 低 | ❌ 高 |
复杂度 | ⚠️ 中等 | ✅ 简单 |
控制粒度 | ✅ 精细 | ⚠️ 一般 |
支持序列化 | ✅ 是 | ❌ 否(需配合JsonSerializer) |
适合场景 | 大文件/高性能需求 | 简单结构/快速开发 |
选择建议:
{
"dataType": "user",
"data": {
"name": "Alice",
"age": 30
}
}
class DynamicDataAdapter : TypeAdapter<Any>() {
override fun read(reader: JsonReader): Any {
var type: String? = null
var data: Any? = null
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"dataType" -> type = reader.nextString()
"data" -> data = when (type) {
"user" -> parseUser(reader)
"product" -> parseProduct(reader)
else -> throw JsonParseException("Unknown data type: $type")
}
else -> reader.skipValue()
}
}
reader.endObject()
return data ?: throw JsonParseException("Missing data")
}
private fun parseUser(reader: JsonReader): User {
// 具体解析逻辑
}
}
class ByteArrayAdapter : TypeAdapter<ByteArray>() {
override fun write(out: JsonWriter, value: ByteArray) {
out.value(Base64.getEncoder().encodeToString(value))
}
override fun read(reader: JsonReader): ByteArray {
return Base64.getDecoder().decode(reader.nextString())
}
}
通过本文的深度解析,你应该已经掌握:
核心价值点:
在您的下一个项目中遇到复杂JSON解析需求时,不妨尝试使用TypeAdapter,它将帮助您构建更健壮、高效的JSON处理管道。