Skip to content

logan0817/GsonSafeParser

Repository files navigation

GsonSafeParser

English

GsonSafeParser 是一个 Kotlin 优先的 Android Gson 防御性解析库。它面向 Android 项目发布 AAR,解决接口字段类型不稳定导致的整棵 Bean 解析失败问题,并提供 Retrofit 接入、解析事件观测、契约报告、接入诊断和 Demo App 验证工具。

核心目标不是把错误数据悄悄吞掉,而是做到三件事:保住能继续解析的 Bean,留下能定位到字段的契约证据,并让生产环境可以用结构化事件持续观察后端返回漂移。

核心能力

  1. 字段级安全兜底:对象、集合、Map、基础类型出现 JSON 类型错配时,只兜底当前字段,尽量保住外层 Bean。
  2. 默认回归 Gson:Safe Adapter 创建失败、配置不完整或遇到无法确认的类型时,默认交回 Gson 原生解析策略。
  3. Kotlin 友好:支持 Kotlin data class 默认值、reified API、parseSafe<T>()fromJsonSafe<T>()
  4. Retrofit 接入:提供 GsonSafeConverterFactory,支持空响应策略和 raw JSON 捕获上限。
  5. 契约证据:通过 SafeParserEventTypeMismatchEventcontractReport()toBackendMarkdown() 输出字段 path、期望形状、实际形状、兜底动作、客户端影响和后端修复建议。
  6. Demo App:内置 Android 示例应用,可粘贴业务 JSON,在真机上对比 GsonSafeParser 和原生 Gson 解析结果。

默认行为

当前开箱默认配置:fallbackPolicy = FallbackPolicy.NullOnlyprimitiveParsingPolicy = PrimitiveParsingPolicy.DelegateToGsonemptyResponsePolicy = EmptyResponsePolicy.DefaultValueForUnitOrVoidOnlyuseJdkUnsafe = falsemapItemKeyPolicy = MapItemKeyPolicy.Hash

固定行为:

场景 异常 JSON 处理结果
Object 字段 []""1 字段错形默认返回 null 或保留构造默认值,外层对象继续解析。
顶层 Object []""1 顶层 JSON 不是对象时通常返回 null;不可恢复 Gson 异常会继续抛出。
String 字段 []{} 字段读取失败时保留构造默认值;根级交回 Gson 原生 Adapter。

FallbackPolicy(默认:FallbackPolicy.NullOnly):

目标类型 异常 JSON FallbackPolicy.NullOnly(默认) FallbackPolicy.Default
List / Set {}"" 返回 null 返回空集合。
Map []"" 返回 null 返回空 Map。

PrimitiveParsingPolicy(默认:PrimitiveParsingPolicy.DelegateToGson):

目标类型 异常 JSON PrimitiveParsingPolicy.DelegateToGson(默认) PrimitiveParsingPolicy.Safe
Int / Long / Boolean {}[]"" 交回 Gson 原生 Adapter。 使用安全基础值。

EmptyResponsePolicy(默认:EmptyResponsePolicy.DefaultValueForUnitOrVoidOnly):

场景 响应内容 DefaultValueForUnitOrVoidOnly(默认) DefaultValue Null DelegateToGson
Retrofit Unit / Void 空 body 空响应体 Unit 返回 UnitVoid 返回 null 返回各自空值。 返回 null 交回 Gson 原生 Converter。
Retrofit 业务模型空 body 空响应体 返回 null 返回默认对象。 返回 null 通常会得到 EOFException

使用安装

发布产物是 Android AAR,并使用 JDK 17 编译。AAR 会自动合并框架自身 consumer ProGuard 规则;业务 App 仍需要按 Android 混淆 配置自己的模型 keep 规则。老项目不需要第一天全量补 @SerializedName,建议先用宽范围包级 keep 保住 release 字段名、构造方法和 Kotlin 默认值能力,稳定后再逐步收窄。@SerializedName 只能固定 JSON 字段名,不能替代 Kotlin Metadata 和构造方法 keep。

版本号以徽章为准。普通 Gson 或手动持有 Gson 实例时,只依赖 core:

最新版本:Maven Central: core

implementation("io.github.logan0817:gson-safe-parser-core:0.2.1") // 接入 GsonSafeParser 核心解析能力。

如果项目使用 Retrofit,只依赖 retrofit 模块即可;它会传递带上 core:

最新版本:Maven Central: retrofit

implementation("io.github.logan0817:gson-safe-parser-retrofit:0.2.1") // 接入 Retrofit Converter 扩展,并自动带上 core。

快速开始

data class ApiResponse(
    val code: Int = 0,
    val data: User? = null
)

data class User(
    val id: Long = 0L,
    val name: String = ""
)

val json = """{"code":200,"data":[]}"""
val gson = GsonSafeParser.create() // 创建带安全解析能力的 Gson 实例。
val response = gson.fromJson(json, ApiResponse::class.java) // 使用安全 Gson 解析接口响应。

原生 Gson 遇到 data 期望对象却收到 [] 时会抛异常;GsonSafeParser 会兜底 data 字段,并继续解析外层 code

可恢复错形才会被兜底,例如 Object 字段收到数组、集合收到对象、整数字段收到越界值。JSON 语法错误、根级解析失败,以及无法被字段级兜底隔离的委托 Adapter 异常会继续抛出;字段级 Adapter 读取失败可能只影响当前字段并产生事件。调用方仍应按业务需要保留异常上报或外层兜底。

Kotlin 便捷 API:

val response = GsonSafeParser.fromJsonSafe<ApiResponse>(json) // 直接解析并返回业务对象。
val result = GsonSafeParser.parseSafe<ApiResponse>(json) // 解析并同时返回事件列表。

println(result.value)
println(result.events)
println(result.contractReport().toMarkdown())
println(result.contractReport().toBackendMarkdown())
println(result.contractReport().summary.warningCount)
println(result.contractReport().toStructuredRows().firstOrNull()?.stableKey)

如果你要高频重复解析同一套接口,先创建一次可复用 Parser 更合适:

val parser = GsonSafeParser.parser(config) // 只创建一次安全 Parser,后续反复复用同一个 Gson。
val value = parser.fromJsonSafe<ApiResponse>(json)
val result = parser.parseSafe<ApiResponse>(json)

Retrofit 接入

val retrofit = Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addConverterFactory(GsonSafeConverterFactory.create()) // 注册 GsonSafeParser 的响应转换器。
    .build()

如果需要自定义空响应或观测策略:

val config = SafeParserConfig.production(
    observerPolicy = SafeObserverPolicy(
        onEvent = { event -> println(event) } // 接收并上报解析事件。
    )
)

val retrofit = Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addConverterFactory(GsonSafeConverterFactory.create(config)) // 使用自定义配置注册转换器。
    .build()

如果项目里已经统一维护了 Gson,同时还想保留 Retrofit 层的空响应、rawJson 和事件策略,可以使用:

val config = SafeParserConfig.debug() // 既控制 Safe Gson,也控制 Retrofit 层的空响应和观测策略。
val gson = GsonBuilder()
    .serializeNulls()
    .enableSafeParser(config) // 把同一份 SafeParserConfig 注册到 Gson。
    .create()

val retrofit = Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addConverterFactory(GsonSafeConverterFactory.create(gson, config)) // 同时复用已有 Gson 和 Retrofit 层 SafeParserConfig。
    .build()

GsonSafeConverterFactory.create(gson)create(gson, config) 不会修改传入的 Gson;如果需要字段级安全解析,应该在创建这份 Gson 前,对同一个 GsonBuilder 调用 .enableSafeParser(config)

常用配置

val config = SafeParserConfig(
    fallbackPolicy = FallbackPolicy.NullOnly, // 字段错配时返回 null 或保留构造默认值。
    emptyResponsePolicy = EmptyResponsePolicy.DefaultValueForUnitOrVoidOnly, // Retrofit 空响应只为 Unit/Void 返回空值。
    primitiveParsingPolicy = PrimitiveParsingPolicy.DelegateToGson, // 基础类型交回 Gson 原生 Adapter。
    skippedPlatformTypePrefixes = setOf("android."), // 跳过 Android 平台类型,避免反射系统对象;不要把业务模型包名前缀放这里。
    nullValuePolicy = NullValuePolicy.WriteExplicitNulls, // 显式 JSON null 只写入 nullable 字段。
    mapItemKeyPolicy = MapItemKeyPolicy.Hash, // Map item 事件默认输出稳定哈希。
    captureRawJsonInCallbacks = false, // 线上默认不在事件中携带原始 JSON。
    maxRawJsonCaptureBytes = 1024 * 1024, // 限制 raw JSON 最大捕获体积为 1 MiB。
    onEvent = { event -> println(event) }, // 监听统一解析事件。
    onTypeMismatch = { event ->
        println("${event.path}: ${event.actualToken} -> ${event.expectedType}")
    } // 输出字段路径、实际 token 和期望类型。
)

预设配置:

val production = SafeParserConfig.production() // 创建线上默认配置。
val debug = SafeParserConfig.debug() // 创建联调配置,默认开启 raw JSON 捕获。
val lowInterference = SafeParserConfig.lowInterference() // 创建低误伤配置,行为更接近原生 Gson。
  1. production() 适合正式上线时作为默认配置。它使用契约优先读策略和事件观测,但默认不把整段 raw JSON 挂到回调里,这样排障信息够用,又不容易把大响应体、敏感字段或额外内存开销长期带到线上链路里。
  2. debug() 适合联调、测试和接口排障。它和 production() 使用同一套契约优先读策略,会把 raw JSON 一起带进事件回调,方便你直接看到“后端到底返回了什么,哪个字段开始错位”,但同时会加默认体积上限,避免把超大响应整段塞进日志。
  3. lowInterference() 适合灰度接入,或者你现在最担心的是“新库会不会改动我原来太多解析结果”。它具体会做几件事:字段、集合、Map 遇到整体类型错配时优先返回 null,而不是主动造空集合、空 Map 或默认对象;IntBooleanString 这类基础类型交回 Gson 原生 Adapter 处理;Retrofit 空响应默认返回 null;对象构造时不使用 JDK Unsafe 绕过构造函数。这样它仍然会记录错配事件和保住能继续解析的外层结构,但不会过早把错误数据改成安全默认值。

注解

@SafeParseDelegateToGson // 让这个类型直接使用 Gson 原生 Adapter。
class StrictModel

data class PageState(
    @field:SafeParseSkip // 告诉 Safe Reflective 跳过这个字段。
    val runtimeCache: Any? = null
)
  1. @SafeParseDelegateToGson 标在类上,表示该类型直接交给 Gson 原生 Adapter。
  2. @SafeParseSkip 标在字段上,表示 Safe Reflective 不读写该字段,适合运行时状态、缓存字段或平台对象。

Demo App

仓库内置 demo-app,用于真机验证库能力:

./gradlew :demo-app:assembleDebug # 构建 debug 版本 Demo App。
./gradlew :demo-app:installDebug # 把 debug Demo App 安装到已连接设备。
adb shell am start -n io.github.logan.gsonsafeparser.demo/.MainActivity # 启动 Demo App 首页。

Demo App 支持内置用例和用户自定义 JSON。你可以把接口返回直接粘贴进去,对比 GsonSafeParser 和原生 Gson 的解析结果、事件流和接入建议。

文档

建议阅读顺序:先看 快速开始,再看 配置说明错形能力矩阵;如果是 Android release 接入,再补看 Android 混淆

  1. 快速开始:安装、普通 Gson、Retrofit、Kotlin API 和 CI 自检。
  2. 错形能力矩阵:对象、集合、Map、基础类型、Kotlin 默认值、Retrofit 空响应和 raw JSON 捕获的处理范围。
  3. 配置说明:配置项、预设策略、事件流、注解和默认行为。
  4. Android 混淆:新项目接入、老项目快速接入、R8 fullMode 选择和 release 验证。
  5. Demo App:真机测试方式、页面说明和用户 JSON 验证入口。
  6. 排障指南:空响应、raw JSON、Adapter 创建失败、平台对象和业务协议问题。
  7. 发布清单:0.2.1 发版前的 AAR、混淆、文档版本和 Maven 本地产物检查。
  8. 0.2.1 发布说明:契约优先默认行为、Breaking Changes 和发布前注意事项。

风险边界

GsonSafeParser 是 Gson 的增强层,不是新的 JSON 协议解释器。它可以降低解析崩溃概率,并告诉你哪个字段出现了类型错配,但不会证明后端契约是正确的。

当问题超出当前库的处理边界时,默认原则是交回 Gson 原生链路处理。遇到 Gson 版本差异、混淆导致运行时信息缺失、用户配置不完整或 Safe Adapter 创建失败时,库本身不应成为新的崩溃来源;JSON 语法错误、根级解析失败,以及无法被字段级兜底隔离的委托 Adapter 异常会继续抛出,不会被 parseSafe 静默吞掉。

致谢与来源说明

GsonSafeParser 是独立维护的 Kotlin 开源项目。当前仓库代码以维护者主导、AI 辅助重构的方式持续演进,最终结果由维护者审核、调整并验证。AI 使用情况单独说明如下:

  1. ChatGPT Codex:用于重构、测试补强、文档整理和自查。
  2. DeepSeek DeepSeek-V4-Pro:用于重构辅助、文档润色和问题复核。

项目在设计、问题场景梳理、README 审阅和 issue 自查阶段参考过公开项目 getActivity/GsonFactory,相关许可证、原版权声明和更完整的 AI 透明说明见 NOTICE

License

Apache License 2.0

About

一个专为 Kotlin Android 打造的 Gson 防御性 JSON 解析框架,用于安全处理异常、不规范及不一致的接口数据。 A defensive Gson JSON parsing framework for Kotlin Android to safely handle malformed, inconsistent, and unexpected API responses.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors