使用Gson转换JSON为POJO时报Expected BEGIN_OBJECT异常
Gson解析JSON报Expected BEGIN_OBJECT but was STRING异常排查
问题根因
异常和你定义的POJO结构、原始接口返回的JSON格式无关,核心问题出在转换逻辑的冗余序列化步骤,导致最终传入解析的JSON结构不符合预期:
- 你代码中使用的
message.data(常见于FCM推送消息回调场景)本质是Map<String, String>类型,所有字段值都被强制存储为字符串类型:orderPlacedData字段在这个Map中不是嵌套对象,而是已经序列化为字符串的JSON片段。 - 你额外执行
Gson().toJson(message.data)做二次序列化时,Gson会将Map中所有字符串值自动添加转义符、用双引号包裹,最终生成的jsonString里orderPlacedData对应的值是被双引号包裹的字符串,而非预期的嵌套对象,和你定义的POJO字段类型不匹配,因此抛出异常。
二次序列化后实际传入解析的错误结构示例:
{ "orderPlacedData": "{\"createdAt\":\"2022-06-22T00:34:25.833Z\",\"lastUpdated\":\"2022-06-22T00:34:25.833Z\",\"orderId\":\"62b26391e5ddd5001620cd07\",\"orderedItems\":{\"quantity\":1,\"price\":654,\"id\":\"61f4da753627fc0016dfec5a\"},\"userId\":\"6294d73a789e677d84d8e282\",\"status\":\"PENDING_CONFIRMATION\"}" }
解决方案
你可以任选以下一种方式修复,不需要修改现有定义的Kotlin数据类:
- 直接移除冗余的二次序列化步骤,从Map中取出对应字段的字符串值单独解析:
val data = try { val orderPlacedDataJson = message.data.getValue("orderPlacedData") val orderPlacedData = Gson().fromJson(orderPlacedDataJson, OrderPlacedData::class.java) OrderRecievedData(orderPlacedData) } catch (e: Exception) { Log.d(TAG, "onMessageReceived: exception $e") null }
- 如果需要一次性解析整个Map的内容,可以为Gson注册自定义TypeAdapter,识别字段中存储的JSON字符串并自动反序列化为对应对象,避免二次序列化带来的转义问题。
- 如果可以调整推送/接口下发端逻辑,尽量避免将嵌套对象序列化为字符串存储在Map结构中,不过要注意FCM的data字段原生只支持字符串类型值,无法直接传递嵌套对象结构。
注意:解析前可以先打印jsonString的实际内容,就能直观看到字段被转义为字符串的问题,快速定位类型不匹配位置。
内容的提问来源于stack exchange,提问作者Sreshtha Mehrotra
相关产品推荐
相关产品推荐

